代码地址: https://github.com/WiseDoge/Spider_Hub/tree/master/ZhiHu

之前一直不太了解分布式爬虫设计思路,于是在github上搜了一个简易的分布式爬虫,学习了一下实现思路,并做一下对应笔记

分布式爬虫主要涉及到三个方面。

1.模拟登录;

2.master广度遍历,将待爬页push到队列(redis);

3.slave从redis中取出待爬页,进行深度遍历

下面分三个方面分别阐述,以知乎为例。

一.模拟登录

1.首先可以自己手动登陆一次,注意登陆时post的数据以及url

这里post数据格式为:

postdata = {
     '_xsrf': get_xsrf(session),
     'password': secret,
     'remember_me': 'true',
     'email': account,   
     }

其中_xsrf这个字段,在登陆页的源码中可以找到这个字段,但它是一个动态变化的参数,因此必须保证在得到字段值后在同一个session中去做登陆操作。另外可以做的额外操作是将cookie本地化,

然后以后去请求时,从本地加载cookie,如果登陆失败,再重新去做登陆操作。另一个就是验证码的识别,可以用pytesseract来做自动识别(记得安装pytesseract外,装上tesseract ocr,因为

pytesseract只是一个wrapper),今天经过尝试发现其实它的识别率很低,在这里采用的方式是image.show,然后人工识别。看了好几个版本的知乎登陆源码,发现基本上用的都是类似的方式,

另外,目前知乎全站已用https,直接使用之前的源码,可能会返回403.

 

二.Master设计

登陆结束后,就能正式开始进行爬虫操作了。

这里的广度遍历比较精简,就是一个递归,怎么做的呢

1.获取入口页的关注者列表,

2.然后随机获取并剔除一条数据,作为下一次抓取的入口,push到队列。此处redis主要就是起到队列的作用

3.不断递归

核心代码如下:

def crawl(url):
    followees = get_followees(url)
    one = get_next_url(followees)
    try:
        test_list = get_followees(one)
        put_into_queue(followees)
        print(one)
        crawl(one)
    except NoFolloweeError:
        next_random_url = conn.srandmember("UrlSet", 1)[0].decode("utf-8")
        crawl(next_random_url)

 

三.Slave设计

假设有一些代理主机,在这里,一台主机开启一个线程,每一个线程去打开一个网页,解析网页后,将有用信息存储到mongodb,为什么用mongodb,这是因为mongodb比mysql更适合用于分布式存储。

slave设计应该是比较灵活的,可以根据自己的设备条件来做调整。不过源码有应该还是有一些问题的。

1.队列取出url后没看到有剔除操作;

2.代理是新启用一个session,所以可能会遇到无法登陆的情况,这个可以将登陆后的cookie本地化后,在代理主机中加载cookie即可解决。