python爬蟲入門 實(shí)戰(zhàn)(一)---爬糗事百科初窺XPath


注:(此篇為切換Markdown編輯器調(diào)整了格式重發(fā)的……強(qiáng)迫癥,原來用富文本編輯器寫的太丑了)

今天第一次嘗試用python寫爬蟲,在w3shcool學(xué)習(xí)了一下XPath,用來找結(jié)點(diǎn)獲取內(nèi)容。過程中遇到幾個(gè)小問題,在這里記錄一下并分享給其他初學(xué)者。本文以爬取糗事百科為例,這里用的是python2.7。

出現(xiàn)的問題:

  • socket.error: [Errno 10054]
  • xpath尋找結(jié)點(diǎn)的相對(duì)路徑的寫法

糗事百科是一個(gè)很容易爬的網(wǎng)站,不需要登錄。熱門段子的URL是:http://www.qiushibaike.com/hot/page/2/

發(fā)送請(qǐng)求獲取html源碼

直接發(fā)送請(qǐng)求獲取網(wǎng)頁(yè)內(nèi)容就好了,page后面的數(shù)字可以用來翻頁(yè)。我們先來試一試直接發(fā)送請(qǐng)求并輸出response的內(nèi)容。注意請(qǐng)求要設(shè)置headers的內(nèi)容,可以審查元素查看需要設(shè)置的內(nèi)容。

# -*- coding:utf-8 -*-
import urllib
import urllib2

page=1
url='http://www.qiushibaike.com/hot/page/'+str(page)

user_agent='Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36'
headers={'User-Agent':user_agent}

request=urllib2.Request(url,headers=headers)
response=urllib2.urlopen(request)
str_html= response.read()
response.close()

print str_html

運(yùn)行沒有問題,成功輸出了網(wǎng)頁(yè)源碼內(nèi)容。這里筆者出現(xiàn)一個(gè)疏忽,一開始因?yàn)闆]有close掉response,以至于遠(yuǎn)端主機(jī)重置了鏈接,出現(xiàn)socket.error: [Errno 10054] ??赡艹霈F(xiàn)該錯(cuò)誤的還有其他原因,具體可以參考這篇:python socket 超時(shí)設(shè)置 errno 10054

用xpath解析并找到目標(biāo)結(jié)點(diǎn)

我們先嘗試從簡(jiǎn)單的開始,把當(dāng)前頁(yè)面的所有段子的作者名字爬下來輸出。首先先審查元素,看看頁(yè)面的結(jié)構(gòu)。

從上圖可以看到,所有的段子以瀑布流的形式放在一個(gè)id="content-left"的div里面,段子有共同的特點(diǎn)class="article block untagged mb15"
那我們先獲取所有段子的整個(gè)div結(jié)點(diǎn)

tree=html.fromstring(str_html)
nodes=tree.xpath('//div[@id="content-left"]/div[@class="article block untagged mb15"]')

xpath的語(yǔ)法可以參考w3shcool里的XPath 教程,或者其他資料。
然后我們繼續(xù)看段子的內(nèi)容結(jié)構(gòu),如下圖:

我們可以發(fā)現(xiàn)每個(gè)段子的第一個(gè)子div就是包含作者(用戶)名字和頭像信息的div,有共同的特點(diǎn)class="author clearfix",然后具體的名字信息在該div下的子元素第二個(gè)a標(biāo)簽里的h2標(biāo)簽里。
了解了結(jié)構(gòu)我們可以進(jìn)行提取名字了。

tree=html.fromstring(str_html)
nodes=tree.xpath('//div[@id="content-left"]/div[@class="article block untagged mb15"]')
for node in nodes: 
  res_author=node.xpath('//div[@class="author clearfix"]/a[2]/h2')[0].text 
  print res_author

對(duì)于之前找到的每個(gè)段子結(jié)點(diǎn),我們?cè)僬业?code>class="author clearfix"的子div,再找到第二個(gè)a標(biāo)簽下的h2并獲取其text內(nèi)容,即可。但事實(shí)上上圖是一個(gè)錯(cuò)誤的寫法,我們先運(yùn)行一下看結(jié)果。

結(jié)果所有段子結(jié)點(diǎn)貌似都輸出了同一個(gè)作者名字,但從頁(yè)面看,只有第一個(gè)作者是這個(gè)名字。修改后的正確代碼如下:
去掉了node.xpath路徑的開頭兩個(gè)正斜杠,一切都正常了。這是什么原因呢。我又看了一下w3school上的教程,里面寫到:
相對(duì)路徑前面沒有斜杠,而有兩個(gè)斜杠是表示:
看起來有點(diǎn)拗口,但我猜測(cè)應(yīng)該是用“//”都是從整個(gè)文檔開始找的,除非在之前加個(gè)特定元素,才會(huì)在特定元素的所有后代中找。
于是,我又測(cè)試了一下(下圖),符合我的猜測(cè),但可能是巧合,所以暫時(shí)先這么理解,如果有懂的同學(xué)看到這篇文章,希望可以給我講解一下。

從上圖結(jié)果看,用“//”果然可以從整個(gè)文檔中找到所有的段子作者,所以之前的代碼為什么會(huì)對(duì)所有的段子都輸出同一個(gè)作者呢,(猜測(cè))是因?yàn)槊看窝h(huán)都從整個(gè)文檔找了一遍,而每次都是輸出下標(biāo)為[0]的作者名字,當(dāng)然就是一樣的。
而修改后,變成了每個(gè)段子結(jié)點(diǎn)下的相對(duì)尋址,對(duì)于每個(gè)段子只有一個(gè)作者,所以下標(biāo)為[0]的結(jié)果就是該條段子的作者名字了。

爬取所有段子的主要信息(作者,內(nèi)容,點(diǎn)贊和評(píng)論數(shù))

既然作者名字會(huì)爬,其他的文字信息也類似,都是用相對(duì)路徑的寫法找到。直接上完整代碼:(本文只簡(jiǎn)單實(shí)現(xiàn)爬取文字內(nèi)容,沒有爬取圖片。)

# -*- coding:utf-8 -*-
from lxml import html
import urllib
import urllib2

page=1
url='http://www.qiushibaike.com/hot/page/'+str(page)user_agent='Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36'
headers={'User-Agent':user_agent}

request=urllib2.Request(url,headers=headers)
response=urllib2.urlopen(request)
str_html= response.read()
response.close()

tree=html.fromstring(str_html)
nodes=tree.xpath('//div[@id="content-left"]/div[@class="article block untagged mb15"]')

#循環(huán)對(duì)每個(gè)段子結(jié)點(diǎn)進(jìn)行輸出
for node in nodes: 
  #解析每個(gè)段子
  res_author=node.xpath('div[@class="author clearfix"]/a[2]/h2')[0].text 
  content=node.xpath('a[@class="contentHerf"]/div[@class="content"]/span')  [0].text 
  num_vote=node.xpath('div[@class="stats"]/span[@class="stats-vote"]/i')[0].text 
  num_comments=node.xpath('div[@class="stats"]/span[@class="stats-comments"]/a[@class="qiushi_comments"]/i')[0].text 

  #輸出指定內(nèi)容
  print u"作者:"+res_author 
  print "---------------------------------------------------------" 
  print u"內(nèi)容:"+content 
  print "---------------------------------------------------------" 
  print u"點(diǎn)贊:"+num_vote+u",評(píng)論:"+num_comments+"\n"

運(yùn)行結(jié)果截圖:

本文參考:

Python爬蟲實(shí)戰(zhàn)一之爬取糗事百科段子 | 靜覓
XPath 教程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容