关于twitter爬虫的总结

来源:互联网 发布:太原java工程师待遇 编辑:程序博客网 时间:2024/05/17 08:50

       最近有需要收集包含特定关键词的tweets数据。要求查询的时间跨度比较大,使用Twitter给的API有诸多问题,尤其是似乎还突破不了七天的限制,再加上懒得研究,所以还是决定采用爬取网页响应的方式。


一、Twitter搜索的机制

       Twitter提供了一个search的功能,允许用户以关键词进行搜索,在高级搜索选项当中也能设置时间段等限定条件。得到初始搜索结果页面后,将页面下拉,到达底部之后会加载下一页。这个加载过程是由js完成的,如果关闭浏览器的js,那么下一页将不会加载,用户仅能浏览搜索结果首页。


二、拿到搜索结果首页

       Twitter的search功能实际上是以get方式发出请求,因此只需要构造一个url就能进行查询。

#可以设定语言、关键词以及时间区间,事实上进一步研究Twitter的search功能后还能添加更多限制,譬如不出现的关键词,关键词列表等url = 'https://twitter.com/search?l=ja&q=熊本城since%3A2016-04-01 until%3A2017-11-01&src=typd'

       好消息是,与微博不同,似乎Twitter的search功能并不要求用户登录,因此我们不必考虑登录的问题。有了这个url,利用urllib2、request之类的库就能很轻松的拿到一个HTML页面,这个页面即是搜索结果首页,与关闭浏览器js的搜索结果是一致的,使用正则表达式或者BeautifulSoup一洗就可以了。


三、翻页机制

       通过抓包能发现,翻页是由请求如下url完成的:

date_since = '2016-04-01'date_until = '2016-09-21'keyword = '熊本城'lang =  'ja'timeline_Url = 'https://twitter.com/i/search/timeline?vertical=default&q="' + keyword + '"since%3A' + date_since + '%20until%3A' + date_until + '&l='+lang+'&src=typd&include_available_features=1&include_entities=1&max_position=' + position + '&reset_error_state=false'

       其中时间段和关键词这两个参数与查询首页时参数一致,而position则能在首页的返回数据中找到,值得注意的是首页返回的数据中有一个min-position和一个max-position,这两者似乎是相同的,其中的机制没有深入研究。在抓包看了加载流程之后我猜测max-position应该是用来请求整个页面数据的,而min-position则用来进行分步加载,因此就使用了max-position。

       接着如果我们继续翻页,可以看到后续的翻页请求也同样由此url完成,只是参数position发生改变,而每一次翻页请求所需要的position显然来自上一个页面请求的返回。

       发出这个请求之后,能接收到一个json文件。分析之后可以发现,这个json由以下几个键值对组成:

{"min_position":str"has_more_items":boolean"items_html":html"new_latent_count":int"focused_refresh_interval":int}

items_html:一个不标准的html页面,这个页面包含了本次翻页所要加载的数据,也是我们要爬取的主要内容。

min_position:包含了一个position数据,这用来组装下一次翻页请求的url。

has_more_items:大概是用来表明本次返回是否完全。在多次尝试后我发现似乎所有通过爬虫获取的页面该参数都为false,目前看来对爬取数据没有影响。

new_latent_count:本页新增数据条数。

focused_refresh_interval:不明。看字面意思猜测可能是刷新时间,但这个刷新时间有何影响还不清楚。同样在多次尝试后发现该参数恒为30000,也没有发现对爬取有何影响。


三、抓取流程和存在的问题

       现在抓取数据的流程就很清楚了。

       1、填入相关参数,请求搜索首页。获得首页tweets数据及position。

       2、将相关参数及上页position填入,组装timeline的url,请求翻页加载的数据。

       3、重复第2步。

       有几个问题需要注意。

       1、在进行第2步时,返回的json数据中的items_html是不完整的html,想要用BeautifulSoup之类的工具解析的话需要给它添加一个简单的头尾,例如

Head = u"""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>Fake Title</title><body>"""Tail = u"""</body></head></html>"""
       2、Twitter不要求用户登录,但他会检查你的请求的header,尤其是user-agent。恶心人的地方在于如果你的user-agent没有通过检查,那么也不会报错,而是返回一个空的items_html。user-agent失效特点在于position为空,而其他原因导致的无数据返回是会有position返回的。

       3、在我爬取的过程当中,如果请求的数据量稍稍大一些——可能只需要几万条这个量级——那么在数据获取的过程中会出现抓取到空页面的情况。除了第2点谈到的user-agent失效的情况(然而事实上这种情况非常少见),剩下的我没有办法解释。

       4、在解析html拿数据的时候,你会发现发推时间实际上有两个地方拿,一个是网页显示的时间,一个是发推的时间戳。我在进行爬取的时候发现Twitter网页端的时间显示是有问题的,一开始认为是时区问题,但后来发现并不尽然。因此,还是拿时间戳比较靠谱。进一步研究你会发现,Twitter search在工作时实际上使用的是网页显示的那个时间去拿数据。结合一些表现,我猜测第3点问题的原因很可能就在于此,不过鉴于任务已经完成,就不再深究了,以后遇到再说吧。