网站地图 | RSS订阅 老铁博客 - 上海SEO优化|上海网站建设|蜘蛛池出租|站群代搭建
你的位置:首页 » 网站建设 » 正文

分布式爬虫很难吗?用Python写一个小白也能听懂的分布式知乎爬虫

2019-8-3 8:49:41 | 作者:老铁SEO | 0个评论 | 人浏览

  很早就有采集知乎用户数据的想法,要实现这个想法,需要写一个网络爬虫(Web Spider)。因为在学习 python,正好 python 写爬虫也是极好的选择,于是就写了一个基于 python 的网络爬虫。

  几个月前写了爬虫的初版,后来因为一些原因,暂时搁置了下来,最近重新拾起这个想法。首先优化了代码的结构,然后在学弟的提醒下,从多线程改成了多进程,一台机器上运行一个爬虫程序,会启动几百个子进程加速抓取。

  但是一台机器的性能是有极限的,所以后来我使用 MongoDB 和 Redis 搭建了一个主从结构的分布式爬取系统,来进一步加快抓取的速度。

  然后我就去好几个服务器厂商申请免费的试用,比如百度云、腾讯云、Ucloud…… 加上自己的笔记本,断断续续抓取了一个多周,才采集到300万知乎用户数据。中间还跑坏了运行网站的云主机,还好 自动备份 起作用,数据没有丢失,但那又是另外一个故事了……

  给大家推荐一个学习交流的地方,想要学习Python的小伙伴可以一起来学习,719+139+688,入坑需谨慎,对Python没啥兴趣的就不要来凑热闹啦。我们要抓取知乎用户数据,首先要知道在哪个页面可以抓取到用户的数据。知乎用户的个人信息在哪里呢,当然是在用户的主页啦,我们以轮子哥为例 ~

  可以发现只有excited-vczh这部分是会变化的,它代表着知乎用户的唯一ID,在知乎的数据格式中,它的键名叫做urlToken。

  页面URL有了,而且从上图我们可以发现不登录也可以访问用户主页,这说明我们可以不用考虑模拟登陆的问题,可以自由的获取用户主页面源码。

  那么我们如何从用户主页的源码中获取用户的数据呢?一开始我以为需要挨个匹配页面中对应的部分,但我查看源码的时候发现知乎把用户数据集集中放到了源码的一个地方,那就是 id=data 的 div 的data-state属性的值中,看下图:

  知道了用户数据都藏在date-state中,我们用 BeautifulSoup 把该属性的值取出来,然后作为 JSON 格式读取,再把数据集中存储用户数据的部分提取出来即可,看代码:

  刚刚我们讨论到可以通过抓取用户主页面源码来获取个人信息,而用户主页面可以通过拼接字符串的形式得到 URL,其中拼接的关键是如何获取用户唯一ID —— urlToken?

  和获取个人信息同样的方法,我们可以在该页面源码的date-state属性值中找到关注他的用户(一部分):

  名为ids的键值中存储有当前列表页的所有用户的urlToken,默认列表的每一页显示20个用户,所以我们写一个循环便可以获取当前页该用户的所有关注者的urlToken。

  再写一个循环遍历关注者列表的所有页,便可以获取用户的所有关注者的 urlToken。

  有了每个用户在知乎的唯一ID,我们便可以通过拼接这个ID得到每个用户的主页面URL,进一步获取到每个用户的个人信息。

  我选择抓取的是用户的关注者列表,即关注这个用户的所有用户(follower)的列表,其实你也可以选择抓取用户的关注列表(following)。我希望抓取更多知乎非典型用户(潜水用户),于是选择了抓取关注者列表。当时抓取的时候有这样的担心,万一这样抓不到主流用户怎么办?毕竟很多知乎大V虽然关注者很多,但是主动关注的人相对都很少,而且关注的很可能也是大V。但事实证明,主流用户基本都抓取到了,看来基数提上来后,总有缝隙出现。

  频繁抓取会被知乎封IP,也就是常说的反爬虫手段之一,不过俗话说“道高一尺,魔高一丈”,既然有反爬虫手段,那么就一定有反反爬虫手段,咳,我自己起的名……

  言归正传,如果知乎封了你的IP,那么怎么办呢?很简单,换一个IP。这样的思想催生了代理IP池的诞生。所谓代理IP池,是一个代理IP的集合,使用代理IP可以伪装你的访问请求,让服务器以为你来自不同的机器。

  于是我的应对知乎反爬虫机制的策略就很简单了:全力抓取知乎页面 -- 被知乎封IP -- 换代理IP -- 继续抓 -- 知乎继续封 -- 继续换 IP..... (手动斜眼)

  使用 代理IP池,你可以选择用付费的服务,也可以选择自己写一个,或者选择用现成的轮子。我选择用七夜写的 qiyeboy/IPProxyPool 搭建代理池服务,部署好之后,修改了一下代码让它只保存https协议的代理IP,因为使用http协议的IP访问知乎会被拒绝。

  搭建好代理池服务后,我们便可以随时在代码中获取以及使用代理 IP 来伪装我们的访问请求啦!

  多线程/多进程只是最大限度的利用了单台机器的性能,如果要利用多台机器的性能,便需要分布式的支持。

  我采用了主从结构,即一台主机负责调度、管理待抓取节点,多台从机负责具体的抓取工作。

  具体到这个知乎爬虫来说,主机上搭建了两个数据库:MongoDB 和 Redis。MongoDB 负责存储抓取到的知乎用户数据,Redis 负责维护待抓取节点集合。从机上可以运行两个不同的爬虫程序,一个是抓取用户关注者列表的爬虫(list_crawler),一个是抓取用户个人资料的爬虫(info_crawler),他们可以配合使用,但是互不影响。

  我们重点讲讲主机上维护的集合,主机的 Redis 数据库中一共维护了5个集合:

  这里插一句,之所以采用集合(set),而不采用队列(queue),是因为集合天然的带有唯一性,也就是说可以加入集合的节点一定是集合中没有出现过的节点,这里在5个集合中流通的节点其实是urlToken。

  (其实集合可以缩减为3个,省去失败集合,失败则重新投入原来的集合,但我为了测速所以保留了5个集合的结构)

  主机是一台外网/局域网可以访问的“服务器”,从机可以是PC/笔记本/Mac/服务器,这个架构可以部署在外网也可以部署在内网。

  • 本文来自: 老铁博客,转载请保留出处!欢迎发表您的评论
  • 相关标签:反爬虫策略  
  • 已有0位网友发表了一针见血的评论,你还等什么?

    必填

    选填

    记住我,下次回复时不用重新输入个人信息

    必填,不填不让过哦,嘻嘻。

    ◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。