4

使用Python Multiprocessing爬取知乎数据

 2 years ago
source link: http://nathanlvzs.github.io/Crawl-Zhihu-with-Python-Multiprocessing.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

使用Python Multiprocessing爬取知乎数据

NathanLVZS   |   Sunday 3 January 2016

Category:  Python

  • Python
  • Multiprocessing
  • Zhihu

前一两个月的时候在弄一个project,需要爬取知乎的数据。从头开始实现一个爬虫感觉十分地繁琐又十分耗费时间,于是在GitHub上面搜索了一下已有的知乎的爬虫资源,找到zhihu-python这个包,感觉封装地挺不错的,想要拉取的数据都已经有了相对应的方法实现,想要修改、增加一些东西都挺方便,于是决定使用这个包。

zhihu-python是单线程实现的,由于要爬取的数据较多,所以会耗费较多的时间,于是想提高一下速度。苦于没有集群,只好采用多进程的方式进行,使用multiprocessing这个库来实现。

好像知乎没有使用反爬虫机制,爬取过程还算蛮顺利的,就是学校的网络连回大陆不怎么稳定,速度一般。。。

代码传送门

我想通过一个种子用户A,爬取A以及以他为起点的关注网络。所需的数据有:

  • 用户的基本信息:id,收到的赞同数,收到的感谢数,关注的人的数量,关注他的人的数量,回答过的问题数量等

  • 用户关注的人

  • 用户回答过的问题的编号

  • 问题对应的话题

结果的保存:每个进程保存自己的结果在单独的文件。在程序执行过程中将出错的任务保存到一个队列中,在全部任务结束后由主进程将该队列中的内容输出到一个文件中。

关于layer

Image

根据zhihu-python的实现方式以及数据之间的联系,可将数据爬取分为两个阶段–用户数据的爬取、问题话题数据的爬取,这样代码编写实现起来会快一些,出现问题也方便更快地解决。

用户数据爬取

对于第一阶段,采用广度优先的方式,维护一个队列(使用multiprocessing.JoinableQueue),里面存放任务信息。一开始的时候首先将种子用户任务信息放进去。

主进程的流程

Image

子进程的流程

Image

子进程先从任务队列里面获取到一个任务项,当正常处理或者错误处理完成之后,会调用任务队列的task_done方法。任务队列对象中会记录自己还有多少个未完成的任务项,每次调用一次 task_done 方法都会将未完成项的数量减一,该数量为0即说明队列中所有的项都被处理过了,这时所有的子进程就可以结束然后退出了。

在所有子进程开始之后,主进程会阻塞直至任务队列中所有项都完成,可见Queue.join。当所有任务完成之后,主进程将一个共享标志位置位,告诉给子进程任务已经结束。子进程的循环中会判断该标志位是否被置位,如果标志位被置位则跳出循环并结束本进程。

话题数据爬取

对于第二阶段,首先根据第一阶段获取到的问题id数据构建任务队列。跟第一阶段不同的是,这个队列在任务开始的时候就是确定了的,任务执行过程中并不会往队列里添加新的队列项。

主进程的流程

Image

子进程的流程

Image

本阶段的任务队列在一开始的时候就已填充完毕,也可以使用第一阶段的方式来结束子进程,不过我尝试了另一种做法。由于使用的是 queue.get(False) ,每次尝试向队列获取任务项时,如果互斥锁已被其他进程获取,则会触发队列空异常,故不能一出现队列空异常就结束。可以使用一个计数器,记录连续捕获队列空异常的次数,如果大于一个合适的阈值,则说明队列中所有的项都已被处理完,可以结束了。

采用的错误处理方式基本上就是重试,如果是连接异常,就不断重试。如果是遇到其他异常,对于一个任务项,如果连续5次都出现其他异常,则将该任务项记录起来。在回到主进程之后全部输出到文件。

知乎可能会不时修改一些页面html元素、样式什么的,11月底的时候我的代码还可以抓数据的,这几天整理的时候发现有问题,然后花了一些时间改了下代码。

如果遇到问题,可以去zhihu-python的GitHub页面看一下有没有相关的issue解决方法,尽量保持auth.py和zhihu.py这两个文件跟zhihu-python上的保持同步。这两个文件,我改动的地方都加了注释标记。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK