Scrapy IT之家評論爬蟲

引言

最近在學習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。
接口post數據字段
pid好弄,直接1就行了,關鍵是hash怎麼拿到,這個估計也是爲了防止爬蟲新加的字段。然後就是花了很長時間分析怎麼拿到hash值。終於在漫長的網頁源碼中找到了hash的影子,在每篇新聞的評論的html源碼中的head裏的script中找到了hash。
html中hash值
找到了就容易了,直接爬下來,但是發現爬下來的數據裏並沒有script標籤,本來script應該包含在iframe標籤內的,結果爬下來的數據直接<iframe … id=“ifcomment”>< /iframe>結束了,中間的html源碼都沒有。
爬取數據中沒有hash本來以爲終於能拿到hash了, 結果還是不行,接着找hash。分析接口發現referer:https://dyn.ithome.com/comment/388459 ,點開這個url,正是熱評的界面,分析源碼發現hash值也在script標籤裏。
html中hash
爬這個url發現有hash值
爬取數據有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格式。
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哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章