引言
最近在学习Python爬虫,这里推荐一个入门爬虫的博客系列
/Ehco1996/Python-crawler
博主写的对新手很友好,很适合入门。
我写这篇文章的目的是记录一下在学习他的
从零开始写Python爬虫 — 爬虫应用:IT之家热门段子(评论)爬取
中做的改进和遇到的问题。
思路
和原文爬取特定分类新闻下的热评不同的是,我是爬取IT之家首页的最热排行里24小时阅读榜中文章的热门评论,增加一下热评的时效性。
根据原文,我的思路如下:
获取首页最热排行里文章的url根据对应url获取newsID,再将newsID和type数据post给接口/ithome/getajaxdata.aspx获取返回的热评数据解析出热评的标题、评论人、时间、内容、支持数和反对数,进行存储
本以为能够很顺利的实现,结果还是遇到了一些问题。
问题
原文是用requests和多进程实现爬取速度的提升,由于Scrapy本身就是利用多进程实现爬取速度的提升,再加上我想换一种方法实现,这里就采用Scrapy实现。下面就是遇到的问题。
1. newsID在url中被/隔开,需要进行拼接
原文中给出的newsID直接在url中,例:/html/it/323076.htm ,但是最热排行里的文章的newsID在url中是被分割的,例:/0/388/459.htm 。
这个很容易解决,正则表达式匹配一下再拼接就搞定了。代码如下:
# 选出newsID,例:/0/388/110.htm匹配出[388,110]pattern = pile(r'(\d\d\d)')newsID_list = pattern.findall(link)newsID = newsID_list[0] + newsID_list[1] # 拼接出newsID
2. 接口post数据类型改变
分析接口/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:/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';匹配出0A56BCA76AE1AD61pattern = pile(r'\w{16}')hash = pattern.search(script).group()# print(hash)post_url = '/ithome/getajaxdata.aspx' # post url# post数据为newsID,hash,pid,typeyield 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').textitem['time'] = li.find('span', class_='posandtime').text.split('\xa0')[1]item['content'] = li.find('p').textlike = li.find('a', class_='s').texthate = li.find('a', class_='a').text# 选出点赞数和反对数,例:支持(100)匹配出100item['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数据是否改变。
项目地址
/AmazingUU/Scrapy-IT_home_hot_comment
上面是项目地址,觉得还可以的话,给个star哦