使用Scrapy爬取大规模数据
系统学习了解Python爬虫有20天时间了,做了一些爬虫小实验,如:
- 爬取51JOB岗位要求及信息 《当我们学Python时,我们学什么》;
- Python模拟登录爬取QQ群论坛数据,《用Python玩转QQ群论坛》,《成长会不完全大数据-Python爬虫案例》;
- 用Scrapy爬取找到简书签约作者,《Python爬虫学习:简书签约作者知多少?》;
- 工作中爬取优酷视频,爬取筛选赶集、58简历库。
但是以上爬取的数据量都不大,最多的有一千多数条数据。于是想做一次大数据量的爬取。选择的数据源是简书用户,使用的是Scrapy框架。同时也想对简书的用户做一个数据分析。
要爬取大量数据,使用Scrapy要考虑的是新的url在哪里产生,解析的方法如何循环调用,也就是爬取的深度和广度。在Scrapy官方文档上的案例过于简单,实现的过程遇到不少问题,如scrapy中的方法如何调度,如何返回,循环中如何去抓取需要的另一个字段,再如何返回等等, 有些可能是我思维的局限,问题先记下,一步步解决。
一、考虑爬虫从哪里入口?
简书的用户id不是一个自增的序列数,无法使用一个循环就可以跑下所有用户。一开始我是想从一篇热门文章的阅读数或者喜欢数开始抓取用户,热门文章的阅读数能达到6W+,喜欢数在6~7K。但下一步数据再怎么爬,没有想好,阅读和喜欢的用户都是最普通用户,他们的关注和粉丝很少,而且阅读用户是Ajax数据。还有一个问题,数据如何去重。
后来,我再看上次爬取的简书签约作者时,发现有8个签约作者粉丝都超过1W,彭小六粉丝近3W。于是就觉得从这里作为入口,会是一个比较好的方案,简单易行,使用几个不多的url作为待爬取的入口,便可以抓取到大量的数据。最后我选择几个入口用户是,简书、彭小六、剽悍一只猫、入江之鲸、陶瓷兔子5个用户url,爬取他们的粉丝用户信息。
没有把所有签约作者url一起列为入口,是因为我现在数据存为csv格式,考虑可能超过65535行。后来我看了一下,特征用户还可以包括简叔,简书首席拒稿官。
要爬取的用户信息:
class JsuserItem(Item):
nickname = Field() #用户昵称
subscriptions = Field() # 用户关注数
fans = Field() #粉丝数
url = Field() #用户首页url
articles = Field() #写的文章数
words = Field() #写作的字数
likes = Field() #收到的喜欢数
comments = Field() # 发表的评论数,这个数据跳到另外url,还要做分页处理,这次没有做。
regtime = Field() # 与评论数一样,下次再爬取
collected = Field() #文集数量
二、如何使用Scrapy循环爬取数据
在上一篇文章爬虫框架Scrapy快速入门中数据提交,获取新的url,url规则没有变,抓取的页面结构没有变,所以都是在parse()中实现。这次不一样。
1、列出start_urls, parse()方法会自动从这个待爬取的url列表依次执行。
2、每一个用户的粉丝是分页加载的。所以需要一个方法获取粉丝分页url,分页页面每一行数据显示了一个用户文章数、字数、喜欢数、粉丝数,不需要进入到用户首页。
要获得用户注册时间,第一篇文章发表时间,发表过多少评论,是需要进到用户首页的,这也是下一步抓取要解决的。
用户信息在parse()方法中,我的目标就是拿到所有分页url,parse_item()中解析出用户信息并提交。在parse()方法中循环调用parse_item()。把所有特征用户的粉丝数据都抓取出来。
注意:
1)在构造分页url时,查看到一个参数“_=”后面是一串数字,在浏览器中验证去掉又不行,猜测是时间戳。就用time构造出一个,测试正确。
2)在scrapy中方法调用,采用回调的方式。
for i in range(1, pages + 1):
nurl = response.url + '?_' + str(t) + '&page=' + str(i) #构造出分页的url
yield Request(nurl, callback=self.parse_item)
看一下爬取到的数据:
到了65535行!把数据导入数说立方,去重后的条数为64714条,重复率为1.2%,可见用户在粉以上几个签约作者时重合度并不高。
数据统计 90.8%用户写了7篇文章,68.9%用户没有发表过文章你坚持写7篇就超过90%的用户。更多数据分析,另外写一篇来解读。下一步的学习放在mongodb,redis上,练习10W+级别的数据爬取,以及Scrapy处理复杂的流程和性能优化。