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


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

通過以上實例我們可以知道,如果要使用GET請求,思路如下:
POST請求實例分析
我們在進行注冊、登錄等操作的時候,基本上都會遇到POST請求,接下來我們就為大家通過實例來分析如何通過爬蟲來實現(xiàn)POST請求。
在此,我們示例一下如何使用爬蟲通過POST表單傳遞信息。
給大家提供一個POST表單的測試網(wǎng)頁,做測試使用,網(wǎng)址為:
http://www./mypost
打開網(wǎng)址,會發(fā)現(xiàn)有一個表單。

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

可以發(fā)現(xiàn),表單中的姓名對應的輸入框中,name屬性值為"name",密碼對應的輸入框中,name屬性值為"pass",所以,我們構(gòu)造的數(shù)據(jù)中會包含兩個字段,字段名分別是"name","pass’。字段值設置我們要傳遞的信息。格式為字典形式,即:
{字段名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') #進行編碼
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)成功提交。

|