Scrapy-IT之家评论爬虫

2018-10-14  本文已影响0人  AmazingUU

引言

最近在学习Python爬虫,这里推荐一个入门爬虫的博客系列
https://github.com/Ehco1996/Python-crawler
博主写的对新手很友好,很适合入门。

我写这篇文章的目的是记录一下在学习他的
从零开始写Python爬虫 --- 爬虫应用:IT之家热门段子(评论)爬取
中做的改进和遇到的问题。

思路

和原文爬取特定分类新闻下的热评不同的是,我是爬取IT之家首页的最热排行里24小时阅读榜中文章的热门评论,增加一下热评的时效性。

根据原文,我的思路如下:

  1. 获取首页最热排行里文章的url
  2. 根据对应url获取newsID,再将newsID和type数据post给接口http://it.ithome.com/ithome/getajaxdata.aspx获取返回的热评数据
  3. 解析出热评的标题、评论人、时间、内容、支持数和反对数,进行存储

本以为能够很顺利的实现,结果还是遇到了一些问题。

问题

原文是用requests和多进程实现爬取速度的提升,由于Scrapy本身就是利用多进程实现爬取速度的提升,再加上我想换一种方法实现,这里就采用Scrapy实现。下面就是遇到的问题。

1. newsID在url中被/隔开,需要进行拼接

原文中给出的newsID直接在url中,例:https://www.ithome.com/html/it/323076.htm ,但是最热排行里的文章的newsID在url中是被分割的,例:https://www.ithome.com/0/388/459.htm
这个很容易解决,正则表达式匹配一下再拼接就搞定了。代码如下:

    # 选出newsID,例:https://www.ithome.com/0/388/110.htm匹配出[388,110]
    pattern = re.compile(r'(\d\d\d)')
    newsID_list = pattern.findall(link)
    newsID = newsID_list[0] + newsID_list[1]  # 拼接出newsID

2. 接口post数据类型改变

分析接口http://it.ithome.com/ithome/getajaxdata.aspx发现,目前post数据不仅仅是newsID和type,而是又加了两个字段hash和pid。

pid好弄,直接1就行了,关键是hash怎么拿到,这个估计也是为了防止爬虫新加的字段。然后就是花了很长时间分析怎么拿到hash值。终于在漫长的网页源码中找到了hash的影子,在每篇新闻的评论的html源码中的head里的script中找到了hash。

找到了就容易了,直接爬下来,但是发现爬下来的数据里并没有script标签,本来script应该包含在iframe标签内的,结果爬下来的数据直接<iframe ...... id="ifcomment">< /iframe>结束了,中间的html源码都没有。

本来以为终于能拿到hash了, 结果还是不行,接着找hash。分析接口发现referer:https://dyn.ithome.com/comment/388459 ,点开这个url,正是热评的界面,分析源码发现hash值也在script标签里。

爬这个url发现有hash值

爬下来的数据有hash就简单了,接着就是取出script标签,正则匹配出hash,最后将newsID、hash、pid、type一起post给接口就可以拿到返回数据了。找到hash是整个项目中最关键的问题。代码如下:

    # hash在script标签内
    script = response.xpath('/html/head/script[3]/text()').extract()[0]
    # 选出hash,例:var ch11 = '0A56BCA76AE1AD61';匹配出0A56BCA76AE1AD61
    pattern = re.compile(r'\w{16}')
    hash = pattern.search(script).group()
    # print(hash)
    post_url = 'https://dyn.ithome.com/ithome/getajaxdata.aspx'  # post url
    # post数据为newsID,hash,pid,type
    yield scrapy.FormRequest(
        url=post_url,
        meta={'title': title},
        formdata={'newsID': newsID, 'hash': hash, 'pid': '1', 'type': 'hotcomment'},
        callback=get_hot_comment
    )

3. 接口返回数据为json格式,不能使用xpath找到标签

第二步post之后,返回的response本来想直接使用xpath取出各个评论数据,发现取不出来。分析发现返回的response为json格式。

将response.text用json.loads()格式化,并取出html,最后再用BeautifulSoup()格式化一下,评论的各个数据就很容易取出来了。

代码如下:

    # 分析response.text,发现为json格式,'html'对应html源码,即{'html':<li>...}
    html = json.loads(response.text)['html']
    # html源码格式化
    soup = BeautifulSoup(html, 'lxml')
    # 每条热评在class='entry'的li标签内
    li_list = soup.find_all('li', class_='entry')
    for li in li_list:
        # 分析html源码,取出热评对应数据
        item['username'] = li.find('span', class_='nick').text
        item['time'] = li.find('span', class_='posandtime').text.split('\xa0')[1]
        item['content'] = li.find('p').text
        like = li.find('a', class_='s').text
        hate = li.find('a', class_='a').text
        # 选出点赞数和反对数,例:支持(100)匹配出100
        item['like_num'] = re.search(r'\d+', like).group()
        item['hate_num'] = re.search(r'\d+', hate).group()
        # print(item)
        yield item

4. 设置ROBOTSTXT_OBEY = False,否则scrapy自动forbidden了

前面忘了说,需要在settings.py里将ROBOTSTXT_OBEY设为False,否则scrapy直接根据网站robot.text自动forbidden了。这里需要说一下,该爬虫项目仅供学习交流使用,爬取时降低速度,减少对端服务器压力。

总结

上面四个问题解决之后,整个项目就没什么大的问题了。其中最关键的还是拿到hash值。还有需要说明的一点是,当前接口post的数据为newsID、hash、pid、type,后面可能IT之家还会修改,爬取时注意post数据是否改变。

项目地址

https://github.com/AmazingUU/Scrapy-IT_home_hot_comment
上面是项目地址,觉得还可以的话,给个star哦

上一篇下一篇

猜你喜欢

热点阅读