引言
最近在學習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哦