reddit是一個(gè)國外的論壇性質(zhì)的東西,為了做chatbot,所以準(zhǔn)備爬一些數(shù)據(jù)下來。
準(zhǔn)備工作
—— scrapy框架的安裝和熟悉
可參考網(wǎng)頁:
http://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/tutorial.html
http://m.itdecent.cn/p/7a146c848388
—— 網(wǎng)頁結(jié)構(gòu)分析
用firefox打開reddit,搜索chat
得到的網(wǎng)頁為https://www.reddit.com/search?q=chat&type=sr&count=4&before=t5_2uul1
下圖是搜索結(jié)果頁面,然后有很多個(gè)分板塊,來看看如何一步一步分析得到每一句對話。
注:下面查看xpath的方式都是用Firebug查看的,比較方便
1. 獲取同一頁上的不同板塊

以第二個(gè)板塊為例,它的鏈接網(wǎng)頁為
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
現(xiàn)在來看看第一個(gè)板塊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. 獲取下一頁
再來看下一頁的網(wǎng)頁為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
規(guī)律不是很明顯,所以來看看第一頁中的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]
為什么最后多了一個(gè)[2]是因?yàn)槎嗔艘粋€(gè)prev按鈕,所以來看看
<a rel="nofollow next">next ?</a>
#下面是第一頁的
<a rel="nofollow next">next ?</a>
找到共同點(diǎn)為都有rel="nofollow next",所以獲取方式可以通過把第一頁當(dāng)作特殊情況或者通過這個(gè)共同點(diǎn)來獲取。
如果采取第一種方案:
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. 獲取板塊里面的每個(gè)發(fā)言頁面
看看第一個(gè)板塊chat板塊的結(jié)構(gòu)

# 第一個(gè)發(fā)言的xpath
/html/body/div[5]/div/div[1]/div[2]/div/p[1]/a
鏈接到的網(wǎng)站為:
https://www.reddit.com/r/chat/comments/5q77js/rchat_is_seeking_capable_mods_with_css_experience/
# 第二個(gè)發(fā)言的xpath
/html/body/div[5]/div/div[3]/div[2]/div/p[1]/a
第一個(gè)發(fā)言在html中的顯示:
<a class="title may-blank " data-event-action="title" href="/r/chat/comments/5q77js
/rchat_is_seeking_capable_mods_with_css_experience/" 略</a>
第二個(gè)發(fā)言在html中的顯示:
<a class="title may-blank " data-event-action="title" href="/r/chat/comments/6tivrr/26m_lets_do_it/" 略</a>
共同點(diǎn)就是data-event-action="title"
所以獲取方式為:
talks_page = selector.xpath('/html/body/div[5]//div[@data-event-action="title"]/@href').extract()
因?yàn)閞eddit不同板塊的結(jié)構(gòu)可能不同,所以的話再看一個(gè)板塊,第二個(gè)板塊的第一個(gè)發(fā)言的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. 獲取每一個(gè)發(fā)言頁面的對話
先看看發(fā)言頁面長什么樣子

最外圈的xpath為:/html/body/div[5]/div[2]/div[3]
第一個(gè)人的評論然后往下依次為:
對應(yīng)圖中的hello
/html/body/div[5]/div[2]/div[3]/+div[1]/+div[2]/form/div/div/p
對應(yīng)圖中的Hi :)
/html/body/div[5]/div[2]/div[3]/+div[1]/+div[3]/div/div[1]/+div[2]/form/div/div/p
對應(yīng)圖中的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
然后下面的第二個(gè)人發(fā)起的評論為
/html/body/div[5]/div[2]/div[3]/+div[3]/+div[2]/form/div/div/p
可以按照構(gòu)造規(guī)律從外往里提取文本,但是這樣比較麻煩,來看看在html中的顯示:
<div class="usertext-body may-blank-within md-container ">
<div class="md">
<p>hello</p>
</div>
</div>
發(fā)現(xiàn)class="usertext-body may-blank-within md-container "這個(gè)都是存在的,算是一個(gè)共同點(diǎn)。
然后在html中觀察每一個(gè)人發(fā)起的評論區(qū)域的html顯示中都會(huì)有data-type="comment"。
所以便有一種提取方法:
-
提取每個(gè)人發(fā)起的對話區(qū)域:
comment_zone = selector.xpath('//div[@data-type="comment"]') -
用循環(huán)提取每一句對話
for conversation in comment_zone: talk = conversation.xpath('//div[@class="usertext-body may-blank-within md-container "]/div/p/text()').extract()
但是在每一輪對話中,就像下面這種,有針對一句話的兩個(gè)人的不同回答,那怎么辦?

這時(shí)候可以給scrappy定義的item多加一點(diǎn)屬性,除了對話本身,還得加一點(diǎn)id之類的標(biāo)示,每個(gè)人發(fā)起的回復(fù)有一個(gè)id,然后后期再處理。
也可以在寫py文件時(shí)就處理,為后面省一點(diǎn)時(shí),處理邏輯可以是遞歸。
不過這里因?yàn)閿?shù)量也夠大了,所以這種情況就直接忽略或者跳過就好了,省去一些麻煩。
編寫爬蟲代碼
框架使用scrapy
略
開始爬取
略
注:上面的代碼中可能有細(xì)節(jié)錯(cuò)誤,主要提供一個(gè)爬蟲的框架和思想介紹,不關(guān)注細(xì)節(jié)