導(dǎo)讀 | urllib 模塊作為Python 3 處理 URL 的組件集合,如果你有 Python 2 的知識,那么你就會注意到 Python 2 中有 urllib 和 urllib2 兩個版本的模塊,這些現(xiàn)在都是 Python 3 的 urllib 包的一部分,具體如何來體現(xiàn)它們之間的關(guān)系 |
Python 3 的 urllib 模塊是一堆可以處理 URL 的組件集合。如果你有 Python 2 的知識,那么你就會注意到 Python 2 中有 urllib 和 urllib2 兩個版本的模塊。這些現(xiàn)在都是 Python 3 的 urllib 包的一部分。當(dāng)前版本的 urllib 包括下面幾部分:
- urllib.request
- urllib.error
- urllib.parse
- urllib.rebotparser
接下來我們會分開討論除了 urllib.error 以外的幾部分。官方文檔實(shí)際推薦你嘗試第三方庫, requests,一個高 級的 HTTP 客戶端接口。然而我依然認(rèn)為知道如何不依賴第三方庫打開 URL 并與之進(jìn)行交互是很有用的,而且這也可以幫助你理解為什么 requests 包是如此的流行。
urllib.requesturllib.request 模塊期初是用來打開和獲取 URL 的。讓我們看看你可以用函數(shù) urlopen 可以做的事:
>>>importurllib.request >>>url=urllib.request.urlopen(') >>>url.geturl() ' >>>url.info() <http.client.HTTPMessageobjectat0x7fddc2de04e0> >>>header=url.info() >>>header.as_string() ('Date:Fri,24Jun201618:21:19GMT/n' 'Expires:-1/n' 'Cache-Control:private,max-age=0/n' 'Content-Type:text/html;charset=ISO-8859-1/n' 'P3P:CP="ThisisnotaP3Ppolicy!See' ' 'Server:gws/n' 'X-XSS-Protection:1;mode=block/n' 'X-Frame-Options:SAMEORIGIN/n' 'Set-Cookie:' 'NID=80=tYjmy0JY6flsSVj7DPSSZNOuqdvqKfKHDcHsPIGu3xFv41LvH_Jg6LrUsDgkPrtM2hmZ3j9V76pS4K_cBg7pdwueMQfr0DFzw33SwpGex5qzLkXUvUVPfe9g699Qz4cx9ipcbU3HKwrRYA;' 'expires=Sat,24-Dec-201618:21:19GMT;path=/;domain=.google.com;HttpOnly/n' 'Alternate-Protocol:443:quic/n' 'Alt-Svc:quic=":443";ma=2592000;v="34,33,32,31,30,29,28,27,26,25"/n' 'Accept-Ranges:none/n' 'Vary:Accept-Encoding/n' 'Connection:close/n' '/n') >>>url.getcode() 200
在這里我們包含了需要的模塊,然后告訴它打開 Google 的 URL。現(xiàn)在我們就有了一個可以交互的 HTTPResponse 對象。我們要做的第一件事是調(diào)用方法 geturl ,它會返回根據(jù) URL 獲取的資源。這可以讓我們發(fā)現(xiàn) URL 是否進(jìn)行了重定向。
接下來調(diào)用 info ,它會返回網(wǎng)頁的元數(shù)據(jù),比如請求頭信息。因此,我們可以將結(jié)果賦給我們的 headers 變量,然后調(diào)用它的方法 as_string 。就可以打印出我們從 Google 收到的頭信息。你也可以通過 getcode 得到網(wǎng)頁的 HTTP 響應(yīng)碼,當(dāng)前情況下就是 200,意思是正常工作。
如果你想看看網(wǎng)頁的 HTML 代碼,你可以調(diào)用變量 url 的方法 read。我不準(zhǔn)備再現(xiàn)這個過程,因?yàn)檩敵鼋Y(jié)果太長了。
請注意 request 對象默認(rèn)發(fā)起 GET 請求,除非你指定了它的 data 參數(shù)。如果你給它傳遞了 data 參數(shù),這樣 request 對象將會變成 POST 請求。
下載文件urllib 一個典型的應(yīng)用場景是下載文件。讓我們看看幾種可以完成這個任務(wù)的方法:
>>>importurllib.request >>>url='http://www.blog.pythonlibrary.org/wp-content/uploads/2012/06/wxDbViewer.zip' >>>response=urllib.request.urlopen(url) >>>data=response.read() >>>withopen('/home/mike/Desktop/test.zip','wb')asfobj: ...fobj.write(data) ...
這個例子中我們打開一個保存在我的博客上的 zip 壓縮文件的 URL。然后我們讀出數(shù)據(jù)并將數(shù)據(jù)寫到磁盤。一個替代此操作的方案是使用 urlretrieve :
>>>importurllib.request >>>url='http://www.blog.pythonlibrary.org/wp-content/uploads/2012/06/wxDbViewer.zip' >>>tmp_file,header=urllib.request.urlretrieve(url) >>>withopen('/home/mike/Desktop/test.zip','wb')asfobj: ...withopen(tmp_file,'rb')astmp: ...fobj.write(tmp.read())
方法 urlretrieve 會把網(wǎng)絡(luò)對象拷貝到本地文件。除非你在使用 urlretrieve 的第二個參數(shù)指定你要保存文件的路徑,否則這個文件將被拷貝到臨時文件夾的隨機(jī)命名的一個文件中。這個可以為你節(jié)省一步操作,并且使代碼看起來更簡單:
>>>importurllib.request >>>url='http://www.blog.pythonlibrary.org/wp-content/uploads/2012/06/wxDbViewer.zip' >>>urllib.request.urlretrieve(url,'/home/mike/Desktop/blog.zip') ('/home/mike/Desktop/blog.zip', <http.client.HTTPMessageobjectat0x7fddc21c2470>)
如你所見,它返回了文件保存的路徑,以及從請求得來的頭信息。
設(shè)置你的用戶代理當(dāng)你使用瀏覽器訪問網(wǎng)頁時,瀏覽器會告訴網(wǎng)站它是誰。這就是所謂的 user-agent (用戶代理)字段。Python 的 urllib 會表示它自己為 Python-urllib/x.y , 其中 x 和 y 是你使用的 Python 的主、次版本號。有一些網(wǎng)站不認(rèn)識這個用戶代理字段,然后網(wǎng)站可能會有奇怪的表現(xiàn)或者根本不能正常工作。辛運(yùn)的是你可以很輕松的設(shè)置你自己的 user-agent 字段。
>>>importurllib.request >>>user_agent='Mozilla/5.0(X11;Ubuntu;Linuxx86_64;rv:47.0)Gecko/20100101Firefox/47.0' >>>url=' >>>headers={'User-Agent':user_agent} >>>request=urllib.request.Request(url,headers=headers) >>>withurllib.request.urlopen(request)asresponse: ...withopen('/home/mdriscoll/Desktop/user_agent.html','wb')asout: ...out.write(response.read())
這里設(shè)置我們的用戶代理為 Mozilla FireFox ,然后我們訪問 , 它會告訴我們它識別出的我們的 user-agent 字段。之后我們將 url 和我們的頭信息傳給 urlopen 創(chuàng)建一個 Request 實(shí)例。最后我們保存這個結(jié)果。如果你打開這個結(jié)果,你會看到我們成功的修改了自己的 user-agent 字段。使用這段代碼盡情的嘗試不同的值來看看它是如何改變的。
urllib.parseurllib.parse 庫是用來拆分和組合 URL 字符串的標(biāo)準(zhǔn)接口。比如,你可以使用它來轉(zhuǎn)換一個相對的 URL 為絕對的 URL。讓我們試試用它來轉(zhuǎn)換一個包含查詢的 URL :
>>>fromurllib.parseimporturlparse >>>result=urlparse(') >>>result ParseResult(scheme='https',netloc='duckduckgo.com',path='/',params='',query='q=python+stubbing&t=canonical&ia=qa',fragment='') >>>result.netloc 'duckduckgo.com' >>>result.geturl() ' >>>result.port None
這里我們導(dǎo)入了函數(shù) urlparse , 并且把一個包含搜索查詢字串的 duckduckgo 的 URL 作為參數(shù)傳給它。我的查詢字串是搜索關(guān)于 “python stubbing” 的文章。如你所見,它返回了一個 ParseResult 對象,你可以用這個對象了解更多關(guān)于 URL 的信息。舉個例子,你可以獲取到端口信息(本例中沒有端口信息)、網(wǎng)絡(luò)位置、路徑和很多其它東西。
提交一個 Web 表單這個模塊還有一個方法 urlencode 可以向 URL 傳輸數(shù)據(jù)。 urllib.parse 的一個典型使用場景是提交 Web 表單。讓我們通過搜索引擎 duckduckgo 搜索 Python 來看看這個功能是怎么工作的。
>>>importurllib.request >>>importurllib.parse >>>data=urllib.parse.urlencode({'q':'Python'}) >>>data 'q=Python' >>>url=' >>>full_url=url+'?'+data >>>response=urllib.request.urlopen(full_url) >>>withopen('/home/mike/Desktop/results.html','wb')asf: ...f.write(response.read())
這個例子很直接。基本上我們是使用 Python 而不是瀏覽器向 duckduckgo 提交了一個查詢。要完成這個我們需要使用 urlencode 構(gòu)建我們的查詢字符串。然后我們把這個字符串和網(wǎng)址拼接成一個完整的正確 URL ,然后使用 urllib.request 提交這個表單。最后我們就獲取到了結(jié)果然后保存到磁盤上。
urllib.robotparserrobotparser 模塊是由一個單獨(dú)的類 RobotFileParser 構(gòu)成的。這個類會回答諸如一個特定的用戶代理是否獲取已經(jīng)設(shè)置了 robot.txt 的網(wǎng)站的 URL。 robot.txt 文件會告訴網(wǎng)絡(luò)爬蟲或者機(jī)器人當(dāng)前網(wǎng)站的那些部分是不允許被訪問的。讓我們看一個簡單的例子:
>>>importurllib.robotparser >>>robot=urllib.robotparser.RobotFileParser() >>>robot.set_url(') None >>>robot.read() None >>>robot.can_fetch('*',') True >>>robot.can_fetch('*',') False
這里我們導(dǎo)入了 robot 分析器類,然后創(chuàng)建一個實(shí)例。然后我們給它傳遞一個表明網(wǎng)站 robots.txt 位置的 URL 。接下來我們告訴分析器來讀取這個文件。完成后,我們給它了一組不同的 URL 讓它找出那些我們可以爬取而那些不能爬取。我們很快就看到我們可以訪問主站但是不能訪問 cgi-bin 路徑。
總結(jié)一下現(xiàn)在你就有能力使用 Python 的 urllib 包了。在這一節(jié)里,我們學(xué)習(xí)了如何下載文件、提交 Web 表單、修改自己的用戶代理以及訪問 robots.txt。 urllib 還有一大堆附加功能沒有在這里提及,比如網(wǎng)站身份認(rèn)證。你可能會考慮在使用 urllib 進(jìn)行身份認(rèn)證之前切換到 requests 庫,因?yàn)?requests 已經(jīng)以更易用和易調(diào)試的方式實(shí)現(xiàn)了這些功能。我同時也希望提醒你 Python 已經(jīng)通過 http.cookies 模塊支持 Cookies 了,雖然在 request 包里也很好的封裝了這個功能。你應(yīng)該可能考慮同時試試兩個來決定那個最適合你。
原文來自: