reddit是一個國外的論壇性質的東西,為了做chatbot,所以準備爬一些數據下來。
準備工作
—— scrapy框架的安裝和熟悉
可參考網頁:
http://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/tutorial.html
http://www.lxweimin.com/p/7a146c848388
—— 網頁結構分析
用firefox打開reddit,搜索chat
得到的網頁為https://www.reddit.com/search?q=chat&type=sr&count=4&before=t5_2uul1
下圖是搜索結果頁面,然后有很多個分板塊,來看看如何一步一步分析得到每一句對話。
注:下面查看xpath的方式都是用Firebug查看的,比較方便
1. 獲取同一頁上的不同板塊
以第二個板塊為例,它的鏈接網頁為
https://www.reddit.com/r/online_chat/
它在html文件中的顯示為
<a class="search-title may-blank" href="https://www.reddit.com/r/online_chat
/?ref=search_subreddits">
Online
<mark>Chat</mark>
</a>
它的xpath為
/html/body/div[5]/div[2]/div/div/div[2]/header/a
現在來看看第一個板塊chat的xpath
/html/body/div[5]/div[2]/div/div/div[1]/header/a/
所以獲取的方式為
pages = selector.xpath('/html/body/div[5]/div[2]/div/div/div/header/a/@href').extract()
2. 獲取下一頁
再來看下一頁的網頁為https://www.reddit.com/search?q=chat&type=sr&count=3&after=t5_3d7l3
對比第一頁的https://www.reddit.com/search?q=chat&type=sr&count=4&before=t5_2uul1
規律不是很明顯,所以來看看第一頁中的next按鈕的html顯示
<span class="nextprev">
view more:
<a rel="nofollow next">next ?</a>
</span>
xpath為
/html/body/div[5]/div[2]/div/footer/div/span/a
對比來看看第二頁的next的xpath:
/html/body/div[5]/div[2]/div/footer/div/span/a[2]
為什么最后多了一個[2]是因為多了一個prev按鈕,所以來看看
<a rel="nofollow next">next ?</a>
#下面是第一頁的
<a rel="nofollow next">next ?</a>
找到共同點為都有rel="nofollow next",所以獲取方式可以通過把第一頁當作特殊情況或者通過這個共同點來獲取。
如果采取第一種方案:
next_page = selector.xpath('/html/body/div[5]/div[2]/div/footer/div/span/a[2]/@href').extract()
如果采取第二種方案:
next_page = selector.xpath('/html/body/div[5]/div[2]/div/footer/div/span/a[@rel="nofollow next"]/@href').extract()
3. 獲取板塊里面的每個發言頁面
看看第一個板塊chat板塊的結構
# 第一個發言的xpath
/html/body/div[5]/div/div[1]/div[2]/div/p[1]/a
鏈接到的網站為:
https://www.reddit.com/r/chat/comments/5q77js/rchat_is_seeking_capable_mods_with_css_experience/
# 第二個發言的xpath
/html/body/div[5]/div/div[3]/div[2]/div/p[1]/a
第一個發言在html中的顯示:
<a class="title may-blank " data-event-action="title" href="/r/chat/comments/5q77js
/rchat_is_seeking_capable_mods_with_css_experience/" 略</a>
第二個發言在html中的顯示:
<a class="title may-blank " data-event-action="title" href="/r/chat/comments/6tivrr/26m_lets_do_it/" 略</a>
共同點就是data-event-action="title"
所以獲取方式為:
talks_page = selector.xpath('/html/body/div[5]//div[@data-event-action="title"]/@href').extract()
因為reddit不同板塊的結構可能不同,所以的話再看一個板塊,第二個板塊的第一個發言的xpath為
/html/body/div[5]/div/div[1]/div[2]/div[1]/p[1]/a
可見滿足我們的提取方式。
4. 獲取板塊里面的下一頁
/html/body/div[5]/div/div[53]/span/span/a
# html中顯示
<a rel="nofollow next">next ?</a>
# 第二頁的next按鈕
/html/body/div[5]/div/div[51]/span/span[3]/a
獲取方式為:
next_page = selector.xpath('/html/body/div[5]/div//a[@rel="nofollow next"]/@href').extract()
5. 獲取每一個發言頁面的對話
先看看發言頁面長什么樣子
最外圈的xpath為:/html/body/div[5]/div[2]/div[3]
第一個人的評論然后往下依次為:
對應圖中的hello
/html/body/div[5]/div[2]/div[3]/+div[1]/+div[2]/form/div/div/p
對應圖中的Hi :)
/html/body/div[5]/div[2]/div[3]/+div[1]/+div[3]/div/div[1]/+div[2]/form/div/div/p
對應圖中的hello. How are you?
/html/body/div[5]/div[2]/div[3]/+div[1]/+div[3]/div/div[1]/+div[3]/div/div[1]/+div[2]/form/div/div/p
然后下面的第二個人發起的評論為
/html/body/div[5]/div[2]/div[3]/+div[3]/+div[2]/form/div/div/p
可以按照構造規律從外往里提取文本,但是這樣比較麻煩,來看看在html中的顯示:
<div class="usertext-body may-blank-within md-container ">
<div class="md">
<p>hello</p>
</div>
</div>
發現class="usertext-body may-blank-within md-container "這個都是存在的,算是一個共同點。
然后在html中觀察每一個人發起的評論區域的html顯示中都會有data-type="comment"。
所以便有一種提取方法:
-
提取每個人發起的對話區域:
comment_zone = selector.xpath('//div[@data-type="comment"]')
-
用循環提取每一句對話
for conversation in comment_zone: talk = conversation.xpath('//div[@class="usertext-body may-blank-within md-container "]/div/p/text()').extract()
但是在每一輪對話中,就像下面這種,有針對一句話的兩個人的不同回答,那怎么辦?
這時候可以給scrappy定義的item多加一點屬性,除了對話本身,還得加一點id之類的標示,每個人發起的回復有一個id,然后后期再處理。
也可以在寫py文件時就處理,為后面省一點時,處理邏輯可以是遞歸。
不過這里因為數量也夠大了,所以這種情況就直接忽略或者跳過就好了,省去一些麻煩。
編寫爬蟲代碼
框架使用scrapy
略
開始爬取
略
注:上面的代碼中可能有細節錯誤,主要提供一個爬蟲的框架和思想介紹,不關注細節