概述
代碼編寫完成時(shí)間:2017.12.28
寫文章時(shí)間:2017.12.29
看完中國大學(xué)MOOC上的爬蟲教程后,覺得自己之前的學(xué)習(xí)完全是野蠻生長,決定把之前學(xué)的東西再梳理一遍,主要是覺得自己寫的程序和老師寫的差別太大,有很多學(xué)習(xí)的地方,決定用老師所教的和自己已有的知識融合,形成新的知識。
爬蟲的第一步當(dāng)然獲取到網(wǎng)頁,所以可以專門寫一個(gè)程序來獲取網(wǎng)頁,以后對此進(jìn)行不斷改進(jìn)就行,不必重復(fù)制造輪子。
準(zhǔn)備
此程序用到的庫主要是requests庫,還有現(xiàn)在的網(wǎng)站一般都有反爬蟲措施,最常見的是檢查瀏覽器的頭部信息,所以對頭部信息進(jìn)行偽裝的操作可以說是很必要的,為此可以引入fake_useragent庫,引入:
from fake_useragent import UserAgent
import requests
編寫
對爬取網(wǎng)頁代碼的編寫,一般都用requests的get方法對網(wǎng)頁進(jìn)行訪問,對于get方法,為了反爬蟲和良好的體驗(yàn),可以增加一些參數(shù)來增加約束:
response = requests.get(url, headers=headers, timeout=10)
發(fā)現(xiàn)對百度首頁的爬取增不增加頭部信息返回的內(nèi)容是不一樣的,增加了之后可以明顯看到返回的內(nèi)容變多和排版更加人性化。
然后要返回text屬性所包含的內(nèi)容,還有一個(gè)很重要的網(wǎng)頁編碼問題,如果編碼設(shè)置的不對,那么返回的text可能是亂碼,因?yàn)楝F(xiàn)在國際上一般都使用UTF-8編碼,所以我直接令網(wǎng)頁的編碼為UTF-8:
response.encoding = 'utf-8'
其實(shí)按照老師的寫法是這樣的:
response.encoding = response.apparent_encoding
但這樣每次都要根據(jù)網(wǎng)頁的源代碼對編碼進(jìn)行判斷,無疑是要花費(fèi)一點(diǎn)時(shí)間的,干脆使用UTF-8這個(gè)萬金油省事,反正requests一般都是用來爬取單個(gè)網(wǎng)站的內(nèi)容,編碼不對再改就行了,沒什么大不了的。
現(xiàn)在基本上能完成對靜態(tài)網(wǎng)頁的訪問并返回源代碼了。
優(yōu)化
沒看視頻之前,我就是寫到上面那一步之后就收工了,因?yàn)橥瓿闪嘶竟δ苈铮峭ㄟ^和老師的學(xué)習(xí),我知道這樣使不行的,因?yàn)檫@樣的代碼不夠健壯,出錯(cuò)了就直接崩潰,現(xiàn)在代碼量少?zèng)]有關(guān)系,但是以后代碼量大了,就會(huì)有很大的麻煩,所以這是非常不好的習(xí)慣,好的程序應(yīng)該有良好的對異常處理功能,然后我引入可能發(fā)生的異常:
from requests import Timeout, HTTPError
Timeout是可能請求超時(shí)的異常,因?yàn)樾@網(wǎng)不穩(wěn)定,這種情況是十分常見的;HTTPError是請求HTTP頁面的時(shí)候可能發(fā)生的異常,比如常見的404錯(cuò)誤。
下面是改進(jìn)的代碼:
from fake_useragent import UserAgent
import requests
from requests import Timeout, HTTPError
ua = UserAgent() #能夠獲得瀏覽器種類信息的實(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)
通過上述代碼,除了捕獲引入的兩個(gè)異常外,為了保險(xiǎn)起見,把其他的所有異常就統(tǒng)一進(jìn)行了處理,對于超時(shí)異常,就遞歸調(diào)用,重新訪問;還有對返回的response增加了一行代碼判斷:
response.raise_for_status()
作用是如果返回的狀態(tài)碼不是正常的200,就拋出HTTP錯(cuò)誤。
一些網(wǎng)頁不能正常訪問也返回200狀態(tài)碼,真是有毒,這個(gè)有點(diǎn)無解,目前除了人工判斷,還沒有其他辦法。
總結(jié)
一個(gè)簡單的獲取網(wǎng)頁的框架的代碼已經(jīng)完成了,雖然比較“寒酸”,但基本功能也有了,也有對一些異常的處理,健壯性提升了一點(diǎn),直覺上覺得還有許多不足,但是我相信,隨著不斷地進(jìn)步,此程序就可以變得更加完善的。