要想先爬取網(wǎng)頁(yè),我們首先要做的是把這個(gè)網(wǎng)頁(yè)下載下來(lái),我們使用python urllib2模塊來(lái)下載一個(gè)URL:
```
import urllib2
def download(url) :
return urllib2.url.pen(url).read ()
```
當(dāng)傳入url參數(shù)時(shí), 該函數(shù)將會(huì)下載網(wǎng)頁(yè)并返回其HTML。 不過(guò), 這個(gè) 代碼片段存在一個(gè)問(wèn)題, 即當(dāng)下載網(wǎng)頁(yè)時(shí), 我們可能會(huì)遇到一些無(wú)法控制的 錯(cuò)誤,比如請(qǐng)求的頁(yè)面可能不存在。 此時(shí),urllib2 會(huì)拋出異常,然后退出腳本。安全起見(jiàn),下面再給出一個(gè)更健壯的版本,可以捕獲這些異常。
```
import urllib2
def download(url) :
print 'Downloading:',url?
try:
html = urllib2.urlopen(url) .read()
?? ? except urllib2.URLError as e:
print 'Downlad error',e.reason
html = None
return html
```
現(xiàn)在,當(dāng)出現(xiàn)下錯(cuò)誤時(shí),該函數(shù)能夠捕獲異常,然后返回None.
下載的時(shí)候遇到的錯(cuò)誤經(jīng)常是臨時(shí)性的,比如服務(wù)器過(guò)載時(shí)返回的503錯(cuò)誤。
互聯(lián)網(wǎng)工程組定義了http錯(cuò)誤的完整列表,可參考https://tools.ietf.org/html/rfc7231#section- 6,從該文檔中,我們可以了解到4xx錯(cuò)誤發(fā)生在請(qǐng)求存在問(wèn)題時(shí),而5xx錯(cuò)誤發(fā)生在服務(wù)端存在問(wèn)題,所以我們只要確保download函數(shù)發(fā)生5xx錯(cuò)誤時(shí)重試下載即可。
```
def download(url,num_retries=2):
print 'Downloading:',url?
try:
html = urllib2.urlopen(url) .read()
except urllib2.URLError as e:
print 'Downlad error',e.reason
html = None
if num_retries > 0:
? ? ? ? ? ? if hasattr(e,'code') and 500 <= e.code < 600:
? ? ? ? ? ? ? ? return download(url,num_retries-1)
? ? return? html
```
現(xiàn)在,如果download函數(shù)遇到5XX錯(cuò)誤碼時(shí),將會(huì)遞歸調(diào)用函數(shù)自身進(jìn)行重試,此外,函數(shù)還增加了一個(gè)參數(shù),用于設(shè)定重試下載的次數(shù),默認(rèn)為2次。
默認(rèn)的情況下,urllib2使用python-urllib/2.7作為用戶代理下載網(wǎng)頁(yè)內(nèi)容,如果能使用可辨識(shí)的用戶代理則更好,這樣可以避免我們網(wǎng)絡(luò)爬蟲(chóng)遇到的一些問(wèn)題,為了下載更加可靠,我們需要控制用戶代理的設(shè)定,下面代碼對(duì)download函數(shù)進(jìn)行了修改,設(shè)定一個(gè)默認(rèn)的用戶代理”wswp”(既“Scraping with Python”的首字母縮寫(xiě))
```
def download(url,user_agent="wswp",num_retries=2):
? ? print("Downloading:" + url)
? ? headers = {"User-agent":user_agent}
? ? request = urllib2.Request(url,headers=headers)
? ? try:
? ? ? ? html = urllib2.urlopen(request).read()
? ? except urllib2.URLError as e:
? ? ? ? print("Download error" + e.reason)
? ? ? ? html = None
? ? ? ? if num_retries > 0:
? ? ? ? ? ? if hasattr(e,'code') and 500 <= e.code < 600:
? ? ? ? ? ? ? ? return download(url,user_agent,num_retries-1)
? ? return? html
```
最后,如果我們需要對(duì)這個(gè)文件進(jìn)行保存,可以使用python的文件操作,完整代碼如下:
```
import urllib2
def download(url,user_agent="wswp",num_retries=2):
? ? print("Downloading:" + url)
? ? headers = {"User-agent":user_agent}
? ? request = urllib2.Request(url,headers=headers)
? ? try:
? ? ? ? html = urllib2.urlopen(request).read()
? ? except urllib2.URLError as e:
? ? ? ? print("Download error" + e.reason)
? ? ? ? html = None
? ? ? ? if num_retries > 0:
? ? ? ? ? ? if hasattr(e,'code') and 500 <= e.code < 600:
? ? ? ? ? ? ? ? return download(url,user_agent,num_retries-1)
? ? return? html
down = download("http://www.itdecent.cn/")
htmlFile = open('jianshu.html',"a")
htmlFile.write(down)
```
是不是很簡(jiǎn)單呢?