Urllib庫是Python中的一個(gè)功能強(qiáng)大、用于操作URL,并在做爬蟲的時(shí)候經(jīng)常要用到的庫。在Python2.x中,分為Urllib庫和Urllib2庫,Python3.x之后都合并到Urllib庫中,使用方法稍有不同。本文介紹的是Python3中的urllib庫。
什么是Urllib庫
Urllib是Python提供的一個(gè)用于操作URL的模塊,我們爬取網(wǎng)頁的時(shí)候,經(jīng)常需要用到這個(gè)庫。
升級合并后,模塊中的包的位置變化的地方較多。在此,列舉一些常見的位置變動(dòng),方便之前用Python2.x的朋友在使用Python3.x的時(shí)候可以快速掌握。
常見的變化有:
- 在Pytho2.x中使用import urllib2-------對應(yīng)的,在Python3.x中會(huì)使用import urllib.request,urllib.error。
- 在Pytho2.x中使用import urllib-------對應(yīng)的,在Python3.x中會(huì)使用import urllib.request,urllib.error,urllib.parse。
- 在Pytho2.x中使用import urlparse-------對應(yīng)的,在Python3.x中會(huì)使用import urllib.parse。
- 在Pytho2.x中使用import urlopen-------對應(yīng)的,在Python3.x中會(huì)使用import urllib.request.urlopen。
- 在Pytho2.x中使用import urlencode-------對應(yīng)的,在Python3.x中會(huì)使用import urllib.parse.urlencode。
- 在Pytho2.x中使用import urllib.quote-------對應(yīng)的,在Python3.x中會(huì)使用import urllib.request.quote。
- 在Pytho2.x中使用cookielib.CookieJar-------對應(yīng)的,在Python3.x中會(huì)使用http.CookieJar。
- 在Pytho2.x中使用urllib2.Request-------對應(yīng)的,在Python3.x中會(huì)使用urllib.request.Request。
快速使用Urllib爬取網(wǎng)頁
以上我們對Urllib庫做了簡單的介紹,接下來講解如何使用Urllib快速爬取一個(gè)網(wǎng)頁。
首先需要導(dǎo)入用到的模塊:urllib.request
import urllib.request
在導(dǎo)入了模塊之后,我們需要使用urllib.request.urlopen打開并爬取一個(gè)網(wǎng)頁,此時(shí),可以輸入如下代碼爬取百度首頁(www.baidu.com),爬取后,將爬取的網(wǎng)頁賦給了變量file:
>>>file=urllib.request.urlopen('www.baidu.com')
此時(shí),我們還需要將對應(yīng)的網(wǎng)頁內(nèi)容讀取出來,可以使用file.read()讀取全部內(nèi)容,或者也可以使用file.readline()讀取一行內(nèi)容。
>>>data=file.read() #讀取全部
>>>dataline=file.readline() #讀取一行內(nèi)容
讀取內(nèi)容常見的有3種方式,其用法是:
- read()讀取文件的全部內(nèi)容,與readlines()不同的是,read()會(huì)把讀取到的內(nèi)容賦給一個(gè)字符串變量。
- readlines()讀取文件的全部內(nèi)容,readlines()會(huì)把讀取到的內(nèi)容賦值給一個(gè)列表變量。
- readline()讀取文件的一行內(nèi)容。
此時(shí),我們已經(jīng)成功實(shí)現(xiàn)了一個(gè)網(wǎng)頁的爬取,那么我們?nèi)绾螌⑴廊〉木W(wǎng)頁以網(wǎng)頁的形式保存在本地呢?
思路如下:
- 爬取一個(gè)網(wǎng)頁并將爬取到的內(nèi)容讀取出來賦給一個(gè)變量。
- 以寫入的方式打開一個(gè)本地文件,命名為*.html等網(wǎng)頁格式。
- 將步驟1中的變量寫入該文件中。
- 關(guān)閉該文件
我們剛才已經(jīng)成功獲取到了百度首頁的內(nèi)容并讀取賦給了變量data,接下來,可以通過以下代碼實(shí)現(xiàn)將爬取到的網(wǎng)頁保存在本地。
>>>fhandle=open("./1.html","wb")
>>>fhandle.write(data)
>>>fhandle.close()
此時(shí),1.html已竄在我們指定的目錄下,用瀏覽器打開該文件,就可以看到我們爬取的網(wǎng)頁界面。
除此之外,urllib中還有一些常見的用法。
如果希望返回與當(dāng)前環(huán)境有關(guān)的信息,我們可以使用info()返回,比如可以執(zhí)行:
>>>file.info()
<http.client.HTTPMessage object at 0x0000000003623D68>
可以看到,輸出了對應(yīng)的info,調(diào)用格式則為:“爬取的網(wǎng)頁.info()”,我們之前爬取到的網(wǎng)頁賦給了變量file,所以此時(shí)通過file調(diào)用。
如果我們希望獲取當(dāng)前爬取網(wǎng)頁的狀態(tài)碼,我們可以使用getcode(),若返回200為正確,返回其他則不正確。在該例中,我們可以執(zhí)行:
>>>file.getcode()
200
如果想要獲取當(dāng)前所爬取的URL地址,我們可以使用geturl()來實(shí)現(xiàn)。
>>>file.geturl()
'http://www.baidu.com'
一般來說,URL標(biāo)準(zhǔn)中只會(huì)允許一部分ASCII字符比如數(shù)字、字母、部分符號等,而其他的一些字符,比如漢字等,是不符合URL標(biāo)準(zhǔn)的。此時(shí),我們需要編碼。
如果要進(jìn)行編碼,我們可以使用urllib.request.quote()進(jìn)行,比如,我們?nèi)绻獙Π俣染W(wǎng)址進(jìn)行編碼:
>>>urllib.request.quote('http://www.baidu.com')
'http%3A//www.baidu.com'
那么相應(yīng)的,有時(shí)候需要對編碼的網(wǎng)址進(jìn)行解碼
>>>urllib.request.unquote('http%3A//www.baidu.com')
'http://www.baidu.com'
瀏覽器的模擬—Headers屬性
有的時(shí)候,我們無法爬取一些網(wǎng)頁,會(huì)出現(xiàn)403錯(cuò)誤,因?yàn)檫@些網(wǎng)頁為了防止別人惡意采集其信息所以進(jìn)行了一些反爬蟲的設(shè)置。
那么如果我們向爬取這些網(wǎng)頁的信息,應(yīng)該怎么辦呢?
可以設(shè)置一些Headers信息,模擬成瀏覽器去訪問這些網(wǎng)站,此時(shí),就能夠解決這個(gè)問題了。
那我們該添加什么頭部信息呢?
我們需要讓爬蟲模擬成瀏覽器,模擬成瀏覽器可以設(shè)置User-Agent信息。
任意打開一個(gè)網(wǎng)頁,比如打開百度。然后按F12,會(huì)出現(xiàn)一個(gè)窗口。切換到Network標(biāo)簽頁:
然后單擊網(wǎng)頁中的“百度一下”,即讓網(wǎng)頁發(fā)生一個(gè)動(dòng)作。
此時(shí),我們可以觀察到下方的窗口出現(xiàn)了一些數(shù)據(jù)。將界面右上方的標(biāo)簽切換到“Headers”中,即可以看到了對應(yīng)的頭信息,此時(shí)往下拖動(dòng),就可以找到User-Agent字樣的一串信息。這一串信息即是我們下面模擬瀏覽器所需要用到的信息。我們將其復(fù)制出來。如圖:


我們可以得到該信息:
User-Agent:Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
X-Requested-With:XMLHttpRequest
接下來,我們講解如何讓爬蟲模擬成瀏覽器訪問頁面的設(shè)置方法。
import urllib.request
import urllib.parse
url='http://www.baidu.com'
hearder={
'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
}
request=urllib.request.Request(url,headers=header)
reponse=urllib.request.urlopen(request).read()
fhandle=open("./1.html","wb")
fhandle.write(reponse)
fhandle.close()
首先,設(shè)置要爬取的網(wǎng)址,然后調(diào)用urllib.request.Request()函數(shù)創(chuàng)建一個(gè)request對象,該函數(shù)第一個(gè)參數(shù)傳入url,第二個(gè)參數(shù)可以傳入數(shù)據(jù),默認(rèn)是傳入0數(shù)據(jù),第三個(gè)參數(shù)是傳入頭部,該參數(shù)也是有默認(rèn)值的,默認(rèn)是不傳任何頭部。
我們需要?jiǎng)?chuàng)建一個(gè)dict,將頭部信息以鍵值對的形式存入到dict對象中,然后將該dict對象傳入urllib.request.Request()函數(shù)第三個(gè)參數(shù)。
此時(shí),已經(jīng)成功設(shè)置好報(bào)頭,然后我們使用urlopen()打開該Request對象即可打開對應(yīng)的網(wǎng)址。
超時(shí)設(shè)置
有的時(shí)候,我們訪問一個(gè)網(wǎng)頁,如果該網(wǎng)頁長時(shí)間未響應(yīng),那么系統(tǒng)就會(huì)判斷該網(wǎng)頁超時(shí)了,即無法打開該網(wǎng)頁。
有的時(shí)候,我們需要根據(jù)自己的需要來設(shè)置超時(shí)的時(shí)間值。我們可以在urllib.request.urlopen()打開網(wǎng)址的時(shí)候,通過timeout字段設(shè)置。
設(shè)置格式為:urllib.request.urlopen(要打開的網(wǎng)址,timeout=時(shí)間值)。
HTTP協(xié)議請求實(shí)戰(zhàn)
如果要進(jìn)行客戶端與服務(wù)器端之間的消息傳遞,我們可以使用HTTP協(xié)議請求進(jìn)行。
HTTP協(xié)議請求主要分為6種類型,各類型的主要作用如下:
- GET請求:GET請求會(huì)通過URL網(wǎng)址傳遞信息,可以直接在URL中寫上要傳遞的信息,也可以由表單進(jìn)行傳遞。如果使用表單進(jìn)行傳遞,這表單中的信息會(huì)自動(dòng)轉(zhuǎn)為URL地址中的數(shù)據(jù),通過URL地址傳遞。
- POST請求:可以向服務(wù)器提交數(shù)據(jù),是一種比較主流也比較安全的數(shù)據(jù)傳遞方式,比如在登錄時(shí),經(jīng)常使用POST請求發(fā)送數(shù)據(jù)。
- PUT請求:請求服務(wù)器存儲一個(gè)資源,通常要指定存儲的位置。
- DELETE請求:請求服務(wù)器刪除一個(gè)資源。
- HEAD請求:請求獲取對應(yīng)的HTTP報(bào)頭信息。
- OPTIONS請求:可以獲取當(dāng)前URL所支持的請求類型。
除此之外,還有TRACE請求與CONNECT請求等。
接下來,將通過實(shí)例講解HTTP協(xié)議請求中的GET請求和POST請求,這兩種請求相對來說用的最多。
GET請求示例分析
有時(shí)想在百度上查詢一個(gè)關(guān)鍵詞,我們會(huì)打開百度首頁,并輸入該關(guān)鍵詞進(jìn)行查詢,那么這個(gè)過程怎樣使用爬蟲自動(dòng)實(shí)現(xiàn)呢?
我們首先需要對查詢過程進(jìn)行相應(yīng)的分析,可以打開百度首頁,然后輸入想檢索的關(guān)鍵詞,比如輸入“hello”,然后按回車鍵,我們觀察一下URL的變化,此時(shí)URL變成:
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu**&wd=hello**
可以發(fā)現(xiàn),對應(yīng)的查詢信息是通過URL傳遞的,這里采用的就是HTTP請求中的GET請求方法,我們將該網(wǎng)址提取出來進(jìn)行分析,字段ie的值為utf8,代表的是編碼信息,而字段wd為hello,剛好是我們要查詢的信息,所以字段wd應(yīng)該存儲的就是用戶檢索的關(guān)鍵詞。根據(jù)我們的猜測,化簡一下該網(wǎng)址,可以化簡為https://www.baidu.com/s?wd=hello ,將該網(wǎng)址復(fù)制到瀏覽器中,刷新一下,會(huì)發(fā)現(xiàn)該網(wǎng)址也能夠出現(xiàn)關(guān)鍵詞為‘hello’的搜索結(jié)果。
由此可見,我們在百度上查詢一個(gè)關(guān)鍵字時(shí),會(huì)使用GET請求,其中關(guān)鍵性字段是wd,網(wǎng)址格式為:https://www.baidu.com/s?wd=關(guān)鍵詞 。
分析到這里,你應(yīng)該大概知道我們該怎么用爬蟲實(shí)現(xiàn)自動(dòng)地在百度上查詢關(guān)鍵詞結(jié)果了。直接上代碼~
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import urllib.request
import urllib.parse
url='http://www.baidu.com/s?wd='
key='fengxin的博客'
key_code=urllib.request.quote(key) #因?yàn)閁RL里含中文,需要進(jìn)行編碼
url_all=url+key_code
header={
'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
} #頭部信息
request=urllib.request.Request(url_all,headers=header)
reponse=urllib.request.urlopen(request).read()
fh=open("./baidu.html","wb") #寫入文件中
fh.write(reponse)
fh.close()
此時(shí),我們用瀏覽器打開剛才保存的baidu.html文件,我們就可以看到我們剛才爬取的網(wǎng)頁結(jié)果,如圖:

通過以上實(shí)例我們可以知道,如果要使用GET請求,思路如下:
- 構(gòu)建對應(yīng)的URL地址,該URL地址包含GET請求的字段名和字段內(nèi)容等信息,并且URL地址滿足GET請求的格式,即“http://網(wǎng)址?字段名1=字段內(nèi)容1&字段名2=字段內(nèi)容2”
- 以對應(yīng)的URL為參數(shù),構(gòu)建Request對象。
- 通過urlopen()打開構(gòu)建的Request對象。
- 按需求進(jìn)行后續(xù)的處理操作,比如讀取網(wǎng)頁的內(nèi)容、將內(nèi)容寫入文件等。
POST請求實(shí)例分析
我們在進(jìn)行注冊、登錄等操作的時(shí)候,基本上都會(huì)遇到POST請求,接下來我們就為大家通過實(shí)例來分析如何通過爬蟲來實(shí)現(xiàn)POST請求。
在此,我們示例一下如何使用爬蟲通過POST表單傳遞信息。
給大家提供一個(gè)POST表單的測試網(wǎng)頁,做測試使用,網(wǎng)址為:
http://www./mypost
打開網(wǎng)址,會(huì)發(fā)現(xiàn)有一個(gè)表單。

如何通過爬蟲自動(dòng)實(shí)現(xiàn)這個(gè)傳遞過程呢?
因?yàn)檫@里所采用的傳遞方法是POST方法,所以如果要使用爬蟲自動(dòng)實(shí)現(xiàn),我們要構(gòu)造PSOT請求,實(shí)現(xiàn)思路如下:
- 設(shè)置好URL網(wǎng)址。
- 構(gòu)建表單數(shù)據(jù),并使用urllib.parse.urlencode對數(shù)據(jù)進(jìn)行編碼處理。
- 構(gòu)建Request對象,參數(shù)包括URL地址和要傳遞的數(shù)據(jù)。
- 添加頭部信息,模擬瀏覽器進(jìn)行爬取。
- 使用urllib.requesr.urlopen()打開對應(yīng)的Request對象。完成信息的傳遞。
- 后續(xù)處理,比如讀取網(wǎng)頁內(nèi)容,將內(nèi)容寫入文件等。
首先,需要設(shè)置好對應(yīng)的URL地址,分析該網(wǎng)頁,在單擊提交之后,會(huì)傳遞到當(dāng)前頁面進(jìn)行處理,所以處理的頁面應(yīng)該是http://www./mypost,所以,URL應(yīng)該設(shè)置為http://www./mypost。
然后我們需要構(gòu)建表單數(shù)據(jù),在該網(wǎng)頁上右擊“查看網(wǎng)頁源代碼”,找到對應(yīng)的form表單部分,然后進(jìn)行分析。如圖:

可以發(fā)現(xiàn),表單中的姓名對應(yīng)的輸入框中,name屬性值為"name",密碼對應(yīng)的輸入框中,name屬性值為"pass",所以,我們構(gòu)造的數(shù)據(jù)中會(huì)包含兩個(gè)字段,字段名分別是"name","pass’。字段值設(shè)置我們要傳遞的信息。格式為字典形式,即:
{字段名1:字段值1,字段名2:字段值2,…}
其他的跟上面的GET請求類似,直接上代碼~
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import urllib.request
import urllib.parse
url='http://www./mypost'
header={
'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
}
data={'name':'fengxin','pass':'123'}
postdata=urllib.parse.urlencode(data).encode('utf8') #進(jìn)行編碼
request=urllib.request.Request(url,postdata)
reponse=urllib.request.urlopen(request).read()
fhandle=open("./1.html","wb")
fhandle.write(reponse)
fhandle.close()
在瀏覽器中打開我們剛保存的1.html文件,可以看到,數(shù)據(jù)已經(jīng)成功提交。

|