注:(此篇為切換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)。

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),如下圖:

了解了結(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é)果。




于是,我又測(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é)果截圖:
