程序员今日看点

分析一个爬虫的分页问题

2017-02-14  本文已影响1279人  向右奔跑

接着这篇《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 两种方式的代码有什么不同。

经验:大胆设想,小心求证,简化处理,认真查找,反复折腾

上一篇下一篇

猜你喜欢

热点阅读