引言
最近在学习Python爬虫,这里推荐一个入门爬虫的博客系列
https://github.com/Ehco1996/Python-crawler
博主写的对新手很友好,很适合入门。
我写这篇文章的目的是记录一下在学习他的
从零开始写Python爬虫 --- 爬虫应用:IT之家热门段子(评论)爬取
中做的改进和遇到的问题。
思路
和原文爬取特定分类新闻下的热评不同的是,我是爬取IT之家首页的最热排行里24小时阅读榜中文章的热门评论,增加一下热评的时效性。
根据原文,我的思路如下:
- 获取首页最热排行里文章的url
- 根据对应url获取newsID,再将newsID和type数据post给接口http://it.ithome.com/ithome/getajaxdata.aspx获取返回的热评数据
- 解析出热评的标题、评论人、时间、内容、支持数和反对数,进行存储
本以为能够很顺利的实现,结果还是遇到了一些问题。
问题
原文是用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哦
网友评论