概述
代碼編寫(xiě)完成時(shí)間:2017.12.28
寫(xiě)文章時(shí)間:2017.12.29
看完中國(guó)大學(xué)MOOC上的爬蟲(chóng)教程后,覺(jué)得自己之前的學(xué)習(xí)完全是野蠻生長(zhǎng)子刮,決定把之前學(xué)的東西再梳理一遍,主要是覺(jué)得自己寫(xiě)的程序和老師寫(xiě)的差別太大钟沛,有很多學(xué)習(xí)的地方溜腐,決定用老師所教的和自己已有的知識(shí)融合,形成新的知識(shí)耻卡。
爬蟲(chóng)的第一步當(dāng)然獲取到網(wǎng)頁(yè),所以可以專(zhuān)門(mén)寫(xiě)一個(gè)程序來(lái)獲取網(wǎng)頁(yè)牲尺,以后對(duì)此進(jìn)行不斷改進(jìn)就行劲赠,不必重復(fù)制造輪子。
準(zhǔn)備
此程序用到的庫(kù)主要是requests庫(kù)秸谢,還有現(xiàn)在的網(wǎng)站一般都有反爬蟲(chóng)措施凛澎,最常見(jiàn)的是檢查瀏覽器的頭部信息,所以對(duì)頭部信息進(jìn)行偽裝的操作可以說(shuō)是很必要的估蹄,為此可以引入fake_useragent庫(kù)塑煎,引入:
from fake_useragent import UserAgent
import requests
編寫(xiě)
對(duì)爬取網(wǎng)頁(yè)代碼的編寫(xiě),一般都用requests的get方法對(duì)網(wǎng)頁(yè)進(jìn)行訪問(wèn)臭蚁,對(duì)于get方法最铁,為了反爬蟲(chóng)和良好的體驗(yàn),可以增加一些參數(shù)來(lái)增加約束:
response = requests.get(url, headers=headers, timeout=10)
發(fā)現(xiàn)對(duì)百度首頁(yè)的爬取增不增加頭部信息返回的內(nèi)容是不一樣的垮兑,增加了之后可以明顯看到返回的內(nèi)容變多和排版更加人性化冷尉。
然后要返回text屬性所包含的內(nèi)容,還有一個(gè)很重要的網(wǎng)頁(yè)編碼問(wèn)題系枪,如果編碼設(shè)置的不對(duì)雀哨,那么返回的text可能是亂碼,因?yàn)楝F(xiàn)在國(guó)際上一般都使用UTF-8編碼私爷,所以我直接令網(wǎng)頁(yè)的編碼為UTF-8:
response.encoding = 'utf-8'
其實(shí)按照老師的寫(xiě)法是這樣的:
response.encoding = response.apparent_encoding
但這樣每次都要根據(jù)網(wǎng)頁(yè)的源代碼對(duì)編碼進(jìn)行判斷雾棺,無(wú)疑是要花費(fèi)一點(diǎn)時(shí)間的,干脆使用UTF-8這個(gè)萬(wàn)金油省事衬浑,反正requests一般都是用來(lái)爬取單個(gè)網(wǎng)站的內(nèi)容捌浩,編碼不對(duì)再改就行了,沒(méi)什么大不了的工秩。
現(xiàn)在基本上能完成對(duì)靜態(tài)網(wǎng)頁(yè)的訪問(wèn)并返回源代碼了尸饺。
優(yōu)化
沒(méi)看視頻之前,我就是寫(xiě)到上面那一步之后就收工了助币,因?yàn)橥瓿闪嘶竟δ苈锢颂峭ㄟ^(guò)和老師的學(xué)習(xí),我知道這樣使不行的奠支,因?yàn)檫@樣的代碼不夠健壯馋辈,出錯(cuò)了就直接崩潰抚芦,現(xiàn)在代碼量少?zèng)]有關(guān)系倍谜,但是以后代碼量大了迈螟,就會(huì)有很大的麻煩,所以這是非常不好的習(xí)慣尔崔,好的程序應(yīng)該有良好的對(duì)異常處理功能答毫,然后我引入可能發(fā)生的異常:
from requests import Timeout, HTTPError
Timeout是可能請(qǐng)求超時(shí)的異常,因?yàn)樾@網(wǎng)不穩(wěn)定季春,這種情況是十分常見(jiàn)的洗搂;HTTPError是請(qǐng)求HTTP頁(yè)面的時(shí)候可能發(fā)生的異常,比如常見(jiàn)的404錯(cuò)誤载弄。
下面是改進(jìn)的代碼:
from fake_useragent import UserAgent
import requests
from requests import Timeout, HTTPError
ua = UserAgent() #能夠獲得瀏覽器種類(lèi)信息的實(shí)例
def get_page(url):
try:
headers = {'User-Agent':ua.random} #隨機(jī)獲得頭部信息
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
response.encoding = 'utf-8'
return response.text
except Timeout:
print('requests timeout')
get_page(url)
except HTTPError:
print('the http error(maybe status is not 200)')
except:
print('other error')
url = 'https://www.baidu.com/'
html = get_page(url)
print(html)
通過(guò)上述代碼耘拇,除了捕獲引入的兩個(gè)異常外,為了保險(xiǎn)起見(jiàn)宇攻,把其他的所有異常就統(tǒng)一進(jìn)行了處理惫叛,對(duì)于超時(shí)異常,就遞歸調(diào)用逞刷,重新訪問(wèn)嘉涌;還有對(duì)返回的response增加了一行代碼判斷:
response.raise_for_status()
作用是如果返回的狀態(tài)碼不是正常的200,就拋出HTTP錯(cuò)誤夸浅。
一些網(wǎng)頁(yè)不能正常訪問(wèn)也返回200狀態(tài)碼仑最,真是有毒,這個(gè)有點(diǎn)無(wú)解帆喇,目前除了人工判斷警医,還沒(méi)有其他辦法。
總結(jié)
一個(gè)簡(jiǎn)單的獲取網(wǎng)頁(yè)的框架的代碼已經(jīng)完成了坯钦,雖然比較“寒酸”法严,但基本功能也有了,也有對(duì)一些異常的處理葫笼,健壯性提升了一點(diǎn)深啤,直覺(jué)上覺(jué)得還有許多不足,但是我相信路星,隨著不斷地進(jìn)步溯街,此程序就可以變得更加完善的。