接着这篇《Python爬取数据的分页分析》,最后的难点地方:滚动分页,不知道总页数的情况,如何确定爬虫的分页抓取。
以简书的“个人主页”-- “动态”为例来说明。
先看一下“个人动态”中有哪些数据:评论,喜欢,打赏,关注(作者、专题)(这些都指的是对他人的文章),发表文章(自己),还有一个重要数据“加入简书”(注册时间)。
## 用户行为类型
## share_note 发表文章
## like_collection 关注专题
## comment_note 发表评论
## like_comment 赞了评论
## reward_note 打赏文章
## like_user 关注作者
再看一下网页结构,在个人主页下 看动态,是一个tab切换,有 文章 -- 动态 -- 最新评论 -- 热门,默认情况下,看到的是“文章”这个tab,切换到“动态”tab下,就可以看到用户在简书上一系列的行为操作和时间。不断下拉滚动条,看到所有记录,最后一条是用户的注册时间。
一个典型的滚动分页,不知道总页数。那爬虫如何确定分页的URL,抓取到所有数据呢?
特别注意,因为这个页面采用的框架页,进到用户主页,切换到“动态”tab,查看源代码,是看不到“动态”内容的源代码的。这个也给我们确定分页的URL中的参数造成难题。
还是用Chrome -- 检查 -- Network 工具来分析一下 第2页,第3页的URL,找找规律:
这是第2页URL:
http://www.jianshu.com/users/1441f4ae075d/timeline?max_id=97250697&page=2
第3页URL:
http://www.jianshu.com/users/1441f4ae075d/timeline?max_id=94439065&page=3
基本可以确定,分页URL是userid/timeline?max_id=xxx&page=x
,URL中需要这样两个参数:max_id和page,max_id是什么鬼,这个就是这里分页的最关键的地方,还有一共有多少页怎么确定,也就是爬虫需要递归调用多少次才结束。
还有一点,需要同时看一下,第2页、第3页分页返回的是xml数据(一段网页代码),也就是这时最大程度复用了页面,用的Ajax。
第一步,先确定max_id,还是要到页面源代码中找蛛丝马迹,如果按照一开始进到用户主页,切到“动态”tab,别说max_id找不到,就连页面的那些内容也找不到。陷入僵局的状态。这个max_id看名字就不像时间戳,而像是页面开始的数据id。
关键原因是框架页面挡住了我们的视线,把第2页、第3页的URL直接粘到地址栏回车,查看源代码,一切都有了。
把刚刚分页URL中的那个max_id搜一下,有木有。我的猜想是最后一个id。顺着这个思路往下就比较好弄了。关键是拿出
<li class="" id="feed-93167794">
当中的id去构造一个分页URL就行了,然后顺序往下翻,直到最后一页为止。
不细说了,如何确定max_id,如何提取max_id,如何确定最后一页。
好啦,我直接上源码:
#coding=utf-8
import requests
from lxml import etree
## 抓取用户timeline数据
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
}
def get_info(url,page):
uid = url.split('/')
uid = uid[4]
if url.find('page='):
page = page+1
html = requests.get(url,headers=headers).content
selector = etree.HTML(html)
infos2 = selector.xpath('//ul[@class="note-list"]/li/@id')
infos = selector.xpath('//ul[@class="note-list"]/li')
for info in infos:
name = info.xpath('div/div/div/a/text()')[0]
dd = info.xpath('div/div/div/span/@data-datetime')[0]
type = info.xpath('div/div/div/span/@data-type')[0]
print type
print dd
if len(infos) > 1:
tid = infos2[len(infos2) - 1]
tid = int(filter(str.isdigit, tid)) - 1
print tid
next_url = 'http://www.jianshu.com/users/%s/timeline?max_id=%s&page=%s' % (uid, tid, page)
get_info(next_url,page)
get_info('http://www.jianshu.com/users/54b5900965ea/timeline',1)
Github: https://github.com/ppy2790/author/, 可以比较一下Scrapy 和直接用 requests 两种方式的代码有什么不同。
经验:大胆设想,小心求证,简化处理,认真查找,反复折腾。