本文主要分為兩個部分:一部分是網(wǎng)絡爬蟲的概述蚕甥,幫助大家詳細了解網(wǎng)絡爬蟲项鬼;另一部分是HTTP請求的Python實現(xiàn)邑遏,幫助大家了解Python中實現(xiàn)HTTP請求的各種方式穆端,以便具備編寫HTTP網(wǎng)絡程序的能力忠售。
本文以爬取這個網(wǎng)站例? oeblog.comhttp://www.sv20.com/
01
網(wǎng)絡爬蟲概述
接下來從網(wǎng)絡爬蟲的概念传惠、用處與價值和結(jié)構(gòu)等三個方面,讓大家對網(wǎng)絡爬蟲有一個基本的了解稻扬。
1. 網(wǎng)絡爬蟲及其應用
隨著網(wǎng)絡的迅速發(fā)展卦方,萬維網(wǎng)成為大量信息的載體,如何有效地提取并利用這些信息成為一個巨大的挑戰(zhàn)泰佳,網(wǎng)絡爬蟲應運而生盼砍。網(wǎng)絡爬蟲(又被稱為網(wǎng)頁蜘蛛、網(wǎng)絡機器人)逝她,是一種按照一定的規(guī)則浇坐,自動地抓取萬維網(wǎng)信息的程序或者腳本。下面通過圖3-1展示一下網(wǎng)絡爬蟲在互聯(lián)網(wǎng)中起到的作用:
編輯
▲圖3-1 網(wǎng)絡爬蟲
網(wǎng)絡爬蟲按照系統(tǒng)結(jié)構(gòu)和實現(xiàn)技術(shù)黔宛,大致可以分為以下幾種類型:通用網(wǎng)絡爬蟲近刘、聚焦網(wǎng)絡爬蟲、增量式網(wǎng)絡爬蟲、深層網(wǎng)絡爬蟲觉渴。實際的網(wǎng)絡爬蟲系統(tǒng)通常是幾種爬蟲技術(shù)相結(jié)合實現(xiàn)的介劫。
搜索引擎(Search Engine),例如傳統(tǒng)的通用搜索引擎baidu案淋、Yahoo和Google等蜕猫,是一種大型復雜的網(wǎng)絡爬蟲,屬于通用性網(wǎng)絡爬蟲的范疇哎迄。但是通用性搜索引擎存在著一定的局限性:
不同領(lǐng)域回右、不同背景的用戶往往具有不同的檢索目的和需求,通用搜索引擎所返回的結(jié)果包含大量用戶不關(guān)心的網(wǎng)頁漱挚。
通用搜索引擎的目標是盡可能大的網(wǎng)絡覆蓋率翔烁,有限的搜索引擎服務器資源與無限的網(wǎng)絡數(shù)據(jù)資源之間的矛盾將進一步加深。
萬維網(wǎng)數(shù)據(jù)形式的豐富和網(wǎng)絡技術(shù)的不斷發(fā)展旨涝,圖片蹬屹、數(shù)據(jù)庫、音頻白华、視頻多媒體等不同數(shù)據(jù)大量出現(xiàn)慨默,通用搜索引擎往往對這些信息含量密集且具有一定結(jié)構(gòu)的數(shù)據(jù)無能為力,不能很好地發(fā)現(xiàn)和獲取弧腥。
通用搜索引擎大多提供基于關(guān)鍵字的檢索厦取,難以支持根據(jù)語義信息提出的查詢。
為了解決上述問題管搪,定向抓取相關(guān)網(wǎng)頁資源的聚焦爬蟲應運而生虾攻。
聚焦爬蟲是一個自動下載網(wǎng)頁的程序,它根據(jù)既定的抓取目標更鲁,有選擇地訪問萬維網(wǎng)上的網(wǎng)頁與相關(guān)的鏈接霎箍,獲取所需要的信息。與通用爬蟲不同澡为,聚焦爬蟲并不追求大的覆蓋漂坏,而將目標定為抓取與某一特定主題內(nèi)容相關(guān)的網(wǎng)頁,為面向主題的用戶查詢準備數(shù)據(jù)資源媒至。
說完了聚焦爬蟲顶别,接下來再說一下增量式網(wǎng)絡爬蟲。增量式網(wǎng)絡爬蟲是指對已下載網(wǎng)頁采取增量式更新和只爬行新產(chǎn)生的或者已經(jīng)發(fā)生變化網(wǎng)頁的爬蟲塘慕,它能夠在一定程度上保證所爬行的頁面是盡可能新的頁面筋夏。
和周期性爬行和刷新頁面的網(wǎng)絡爬蟲相比蒂胞,增量式爬蟲只會在需要的時候爬行新產(chǎn)生或發(fā)生更新的頁面图呢,并不重新下載沒有發(fā)生變化的頁面,可有效減少數(shù)據(jù)下載量,及時更新已爬行的網(wǎng)頁蛤织,減小時間和空間上的耗費赴叹,但是增加了爬行算法的復雜度和實現(xiàn)難度。
例如:想獲取趕集網(wǎng)的招聘信息指蚜,以前爬取過的數(shù)據(jù)沒有必要重復爬取乞巧,只需要獲取更新的招聘數(shù)據(jù),這時候就要用到增量式爬蟲摊鸡。
最后說一下深層網(wǎng)絡爬蟲绽媒。Web頁面按存在方式可以分為表層網(wǎng)頁和深層網(wǎng)頁。表層網(wǎng)頁是指傳統(tǒng)搜索引擎可以索引的頁面免猾,以超鏈接可以到達的靜態(tài)網(wǎng)頁為主構(gòu)成的Web頁面是辕。深層網(wǎng)絡是那些大部分內(nèi)容不能通過靜態(tài)鏈接獲取的、隱藏在搜索表單后的猎提,只有用戶提交一些關(guān)鍵詞才能獲得的Web頁面获三。
例如用戶登錄或者注冊才能訪問的頁面∠撬眨可以想象這樣一個場景:爬取貼吧或者論壇中的數(shù)據(jù)疙教,必須在用戶登錄后,有權(quán)限的情況下才能獲取完整的數(shù)據(jù)伞租。
2. 網(wǎng)絡爬蟲結(jié)構(gòu)
下面用一個通用的網(wǎng)絡爬蟲結(jié)構(gòu)來說明網(wǎng)絡爬蟲的基本工作流程贞谓,如圖3-4所示。
編輯
▲圖3-4 網(wǎng)絡爬蟲結(jié)構(gòu)
網(wǎng)絡爬蟲的基本工作流程如下:
首先選取一部分精心挑選的種子URL葵诈。
將這些URL放入待抓取URL隊列经宏。
從待抓取URL隊列中讀取待抓取隊列的URL,解析DNS驯击,并且得到主機的IP烁兰,并將URL對應的網(wǎng)頁下載下來,存儲進已下載網(wǎng)頁庫中徊都。此外沪斟,將這些URL放進已抓取URL隊列。
分析已抓取URL隊列中的URL暇矫,從已下載的網(wǎng)頁數(shù)據(jù)中分析出其他URL主之,并和已抓取的URL進行比較去重,最后將去重過的URL放入待抓取URL隊列李根,從而進入下一個循環(huán)槽奕。
02
HTTP請求的Python實現(xiàn)
通過上面的網(wǎng)絡爬蟲結(jié)構(gòu),我們可以看到讀取URL房轿、下載網(wǎng)頁是每一個爬蟲必備而且關(guān)鍵的功能粤攒,這就需要和HTTP請求打交道所森。接下來講解Python中實現(xiàn)HTTP請求的三種方式:urllib2/urllib、httplib/urllib以及Requests夯接。
1. urllib2/urllib實現(xiàn)
urllib2和urllib是Python中的兩個內(nèi)置模塊焕济,要實現(xiàn)HTTP功能,實現(xiàn)方式是以urllib2為主盔几,urllib為輔晴弃。
1.1 首先實現(xiàn)一個完整的請求與響應模型
urllib2提供一個基礎(chǔ)函數(shù)urlopen,通過向指定的URL發(fā)出請求來獲取數(shù)據(jù)逊拍。最簡單的形式是:
import?urllib2
response=urllib2.urlopen('http://www.zhihu.com')
html=response.read()
print?html
其實可以將上面對http://www.zhihu.com的請求響應分為兩步上鞠,一步是請求,一步是響應芯丧,形式如下:
import?urllib2
#?請求
request=urllib2.Request('http://www.zhihu.com')
#?響應
response?=?urllib2.urlopen(request)
html=response.read()
print?html
上面這兩種形式都是GET請求旗国,接下來演示一下POST請求,其實大同小異注整,只是增加了請求數(shù)據(jù)能曾,這時候用到了urllib。示例如下:
import?urllib
import?urllib2
url?=?'http://www.xxxxxx.com/login'
postdata?=?{'username'?:?'qiye',
'password'?:?'qiye_pass'}
#?info?需要被編碼為urllib2能理解的格式肿轨,這里用到的是urllib
data?=?urllib.urlencode(postdata)
req?=?urllib2.Request(url,?data)
response?=?urllib2.urlopen(req)
html?=?response.read()
但是有時會出現(xiàn)這種情況:即使POST請求的數(shù)據(jù)是對的寿冕,但是服務器拒絕你的訪問。這是為什么呢?問題出在請求中的頭信息椒袍,服務器會檢驗請求頭驼唱,來判斷是否是來自瀏覽器的訪問,這也是反爬蟲的常用手段驹暑。
1.2 請求頭headers處理
將上面的例子改寫一下玫恳,加上請求頭信息,設置一下請求頭中的User-Agent域和Referer域信息优俘。
import?urllib
import?urllib2
url?=?'http://www.xxxxxx.com/login'
user_agent?=?'Mozilla/4.0?(compatible;?MSIE?5.5;?Windows?NT)'
referer='http://www.xxxxxx.com/'
postdata?=?{'username'?:?'qiye',
'password'?:?'qiye_pass'}
#?將user_agent,referer寫入頭信息
headers={'User-Agent':user_agent,'Referer':referer}
data?=?urllib.urlencode(postdata)
req?=?urllib2.Request(url,?data,headers)
response?=?urllib2.urlopen(req)
html?=?response.read()
也可以這樣寫京办,使用add_header來添加請求頭信息,修改如下:
import?urllib
import?urllib2
url?=?'http://www.xxxxxx.com/login'
user_agent?=?'Mozilla/4.0?(compatible;?MSIE?5.5;?Windows?NT)'
referer='http://www.xxxxxx.com/'
postdata?=?{'username'?:?'qiye',
'password'?:?'qiye_pass'}
data?=?urllib.urlencode(postdata)
req?=?urllib2.Request(url)
#?將user_agent,referer寫入頭信息
req.add_header('User-Agent',user_agent)
req.add_header('Referer',referer)
req.add_data(data)
response?=?urllib2.urlopen(req)
html?=?response.read()
對有些header要特別留意帆焕,服務器會針對這些header做檢查惭婿,例如:
User-Agent:有些服務器或Proxy會通過該值來判斷是否是瀏覽器發(fā)出的請求。
Content-Type:在使用REST接口時叶雹,服務器會檢查該值财饥,用來確定HTTP Body中的內(nèi)容該怎樣解析。在使用服務器提供的RESTful或SOAP服務時折晦,Content-Type設置錯誤會導致服務器拒絕服務钥星。常見的取值有:application/xml(在XML RPC,如RESTful/SOAP調(diào)用時使用)满着、application/json(在JSON RPC調(diào)用時使用)谦炒、application/x-www-form-urlencoded(瀏覽器提交Web表單時使用)贯莺。
Referer:服務器有時候會檢查防盜鏈。
1.3 Cookie處理
urllib2對Cookie的處理也是自動的编饺,使用CookieJar函數(shù)進行Cookie的管理。如果需要得到某個Cookie項的值响驴,可以這么做:
import?urllib2
import?cookielib
cookie?=?cookielib.CookieJar()
opener?=?urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
response?=?opener.open('http://www.zhihu.com')
for?item?in?cookie:
print?item.name+':'+item.value
但是有時候會遇到這種情況透且,我們不想讓urllib2自動處理,我們想自己添加Cookie的內(nèi)容豁鲤,可以通過設置請求頭中的Cookie域來做:
import??urllib2
opener?=?urllib2.build_opener()
opener.addheaders.append(?(?'Cookie',?'email='?+?"xxxxxxx@163.com"?)?)
req?=?urllib2.Request(?"http://www.zhihu.com/"?)
response?=?opener.open(req)
print?response.headers
retdata?=?response.read()
1.4 Timeout設置超時
在Python2.6之前的版本秽誊,urllib2的API并沒有暴露Timeout的設置,要設置Timeout值琳骡,只能更改Socket的全局Timeout值锅论。示例如下:
import?urllib2
import?socket
socket.setdefaulttimeout(10)?#?10?秒鐘后超時
urllib2.socket.setdefaulttimeout(10)?#?另一種方式
在Python2.6及新的版本中,urlopen函數(shù)提供了對Timeout的設置楣号,示例如下:
import?urllib2
request=urllib2.Request('http://www.zhihu.com')
response?=?urllib2.urlopen(request,timeout=2)
html=response.read()
print?html
1.5 獲取HTTP響應碼
對于200 OK來說最易,只要使用urlopen返回的response對象的getcode()方法就可以得到HTTP的返回碼。但對其他返回碼來說炫狱,urlopen會拋出異常藻懒。這時候,就要檢查異常對象的code屬性了视译,示例如下:
import?urllib2
try:
response?=?urllib2.urlopen('http://www.google.com')
print?response
except?urllib2.HTTPError?as?e:
if?hasattr(e,?'code'):
print?'Error?code:',e.code
1.6 重定向
urllib2默認情況下會針對HTTP 3XX返回碼自動進行重定向動作嬉荆。要檢測是否發(fā)生了重定向動作,只要檢查一下Response的URL和Request的URL是否一致就可以了酷含,示例如下:
import?urllib2
response?=?urllib2.urlopen('http://www.zhihu.cn')
isRedirected?=?response.geturl()?==?'http://www.zhihu.cn'
如果不想自動重定向鄙早,可以自定義HTTPRedirectHandler類,示例如下:
import?urllib2
class?RedirectHandler(urllib2.HTTPRedirectHandler):
def?http_error_301(self,?req,?fp,?code,?msg,?headers):
pass
def?http_error_302(self,?req,?fp,?code,?msg,?headers):
result?=?urllib2.HTTPRedirectHandler.http_error_301(self,?req,?fp,?code,
msg,?headers)
result.status?=?code
result.newurl?=?result.geturl()
return?result
opener?=?urllib2.build_opener(RedirectHandler)
opener.open('http://www.zhihu.cn')
1.7 Proxy的設置
在做爬蟲開發(fā)中椅亚,必不可少地會用到代理限番。urllib2默認會使用環(huán)境變量http_proxy來設置HTTP Proxy。但是我們一般不采用這種方式呀舔,而是使用ProxyHandler在程序中動態(tài)設置代理扳缕,示例代碼如下:
import?urllib2
proxy?=?urllib2.ProxyHandler({'http':?'127.0.0.1:8087'})
opener?=?urllib2.build_opener([proxy,])
urllib2.install_opener(opener)
response?=?urllib2.urlopen('http://www.zhihu.com/')
print?response.read()
這里要注意的一個細節(jié),使用urllib2.install_opener()會設置urllib2的全局opener别威,之后所有的HTTP訪問都會使用這個代理躯舔。這樣使用會很方便,但不能做更細粒度的控制省古,比如想在程序中使用兩個不同的Proxy設置粥庄,這種場景在爬蟲中很常見。比較好的做法是不使用install_opener去更改全局的設置豺妓,而只是直接調(diào)用opener的open方法代替全局的urlopen方法惜互,修改如下:
import?urllib2
proxy?=?urllib2.ProxyHandler({'http':?'127.0.0.1:8087'})
opener?=?urllib2.build_opener(proxy,)
response?=?opener.open("http://www.zhihu.com/")
print?response.read()
2. httplib/urllib實現(xiàn)
httplib模塊是一個底層基礎(chǔ)模塊布讹,可以看到建立HTTP請求的每一步,但是實現(xiàn)的功能比較少训堆,正常情況下比較少用到描验。在Python爬蟲開發(fā)中基本上用不到,所以在此只是進行一下知識普及坑鱼。下面介紹一下常用的對象和函數(shù):
創(chuàng)建HTTPConnection對象:
class httplib.HTTPConnection(host[, port[, strict[, timeout[, source_address]]]])膘流。
發(fā)送請求:
HTTPConnection.request(method, url[, body[, headers]])。
獲得響應:
HTTPConnection.getresponse()鲁沥。
讀取響應信息:
HTTPResponse.read([amt])呼股。
獲得指定頭信息:
HTTPResponse.getheader(name[, default])。
獲得響應頭(header, value)元組的列表:
HTTPResponse.getheaders()画恰。
獲得底層socket文件描述符:
HTTPResponse.fileno()彭谁。
獲得頭內(nèi)容:
HTTPResponse.msg。
獲得頭http版本:
HTTPResponse.version允扇。
獲得返回狀態(tài)碼:
HTTPResponse.status缠局。
獲得返回說明:
HTTPResponse.reason。
接下來演示一下GET請求和POST請求的發(fā)送考润,首先是GET請求的示例甩鳄,如下所示:
import?httplib
conn?=None
try:
conn?=?httplib.HTTPConnection("www.zhihu.com")
conn.request("GET",?"/")
response?=?conn.getresponse()
print?response.status,?response.reason
print?'-'?*?40
headers?=?response.getheaders()
for?h?in?headers:
print?h
print?'-'?*?40
print?response.msg
except?Exception,e:
print?e
finally:
if?conn:
conn.close()
POST請求的示例如下:
import?httplib,?urllib
conn?=?None
try:
params?=?urllib.urlencode({'name':?'qiye',?'age':?22})
headers?=?{"Content-type":?"application/x-www-form-urlencoded"
,?"Accept":?"text/plain"}
conn?=?httplib.HTTPConnection("www.zhihu.com",?80,?timeout=3)
conn.request("POST",?"/login",?params,?headers)
response?=?conn.getresponse()
print?response.getheaders()?#?獲取頭信息
print?response.status
print?response.read()
except?Exception,?e:
print?e
finally:
if?conn:
conn.close()
3. 更人性化的Requests
Python中Requests實現(xiàn)HTTP請求的方式,是本人極力推薦的额划,也是在Python爬蟲開發(fā)中最為常用的方式妙啃。Requests實現(xiàn)HTTP請求非常簡單,操作更加人性化俊戳。
Requests庫是第三方模塊揖赴,需要額外進行安裝。Requests是一個開源庫抑胎,源碼位于:
GitHub: https://github.com/kennethreitz/requests
希望大家多多支持作者燥滑。
使用Requests庫需要先進行安裝,一般有兩種安裝方式:
使用pip進行安裝阿逃,安裝命令為:pip install requests铭拧,不過可能不是最新版。
直接到GitHub上下載Requests的源代碼恃锉,下載鏈接為:
https://github.com/kennethreitz/requests/releases
將源代碼壓縮包進行解壓搀菩,然后進入解壓后的文件夾,運行setup.py文件即可破托。
如何驗證Requests模塊安裝是否成功呢肪跋?在Python的shell中輸入import requests,如果不報錯土砂,則是安裝成功州既。如圖3-5所示谜洽。
編輯
▲圖3-5 驗證Requests安裝
3.1 首先還是實現(xiàn)一個完整的請求與響應模型
以GET請求為例,最簡單的形式如下:
import?requests
r?=?requests.get('http://www.baidu.com')
print?r.content
大家可以看到比urllib2實現(xiàn)方式的代碼量少吴叶。接下來演示一下POST請求阐虚,同樣是非常簡短,更加具有Python風格蚌卤。示例如下:
import?requests
postdata={'key':'value'}
r?=?requests.post('http://www.xxxxxx.com/login',data=postdata)
print?r.content
HTTP中的其他請求方式也可以用Requests來實現(xiàn)实束,示例如下:
r?=?requests.put('http://www.xxxxxx.com/put',?data?=?{'key':'value'})
r?=?requests.delete('http://www.xxxxxx.com/delete')
r?=?requests.head('http://www.xxxxxx.com/get')
r?=?requests.options('http://www.xxxxxx.com/get')
接著講解一下稍微復雜的方式,大家肯定見過類似這樣的URL:
http://zzk.cnblogs.com/s/blogpost?Keywords=blog:qiyeboy&pageindex=1
就是在網(wǎng)址后面緊跟著“?”造寝,“?”后面還有參數(shù)磕洪。那么這樣的GET請求該如何發(fā)送呢吭练?肯定有人會說诫龙,直接將完整的URL帶入即可,不過Requests還提供了其他方式鲫咽,示例如下:
import?requests
payload?=?{'Keywords':?'blog:qiyeboy','pageindex':1}
r?=?requests.get('http://zzk.cnblogs.com/s/blogpost',?params=payload)
print?r.url
通過打印結(jié)果签赃,我們看到最終的URL變成了:
http://zzk.cnblogs.com/s/blogpost?Keywords=blog:qiyeboy&pageindex=1
3.2 響應與編碼
還是從代碼入手,示例如下:
import?requests
r?=?requests.get('http://www.baidu.com')
print?'content-->'+r.content
print?'text-->'+r.text
print?'encoding-->'+r.encoding
r.encoding='utf-8'
print?'new?text-->'+r.text
其中r.content返回的是字節(jié)形式分尸,r.text返回的是文本形式锦聊,r.encoding返回的是根據(jù)HTTP頭猜測的網(wǎng)頁編碼格式。
輸出結(jié)果中:“text-->”之后的內(nèi)容在控制臺看到的是亂碼箩绍,“encoding-->”之后的內(nèi)容是ISO-8859-1(實際上的編碼格式是UTF-8)孔庭,由于Requests猜測編碼錯誤,導致解析文本出現(xiàn)了亂碼材蛛。Requests提供了解決方案圆到,可以自行設置編碼格式,r.encoding='utf-8'設置成UTF-8之后卑吭,“new text-->”的內(nèi)容就不會出現(xiàn)亂碼芽淡。
但是這種手動的方式略顯笨拙,下面提供一種更加簡便的方式:chardet豆赏,這是一個非常優(yōu)秀的字符串/文件編碼檢測模塊挣菲。安裝方式如下:
pip?install?chardet
安裝完成后,使用chardet.detect()返回字典掷邦,其中confidence是檢測精確度白胀,encoding是編碼形式。示例如下:
import?requests
r?=?requests.get('http://www.baidu.com')
print?chardet.detect(r.content)
r.encoding?=?chardet.detect(r.content)['encoding']
print?r.text
直接將chardet探測到的編碼抚岗,賦給r.encoding實現(xiàn)解碼纹笼,r.text輸出就不會有亂碼了。
除了上面那種直接獲取全部響應的方式苟跪,還有一種流模式廷痘,示例如下:
import?requests
r?=?requests.get('http://www.baidu.com',stream=True)
print?r.raw.read(10)
設置stream=True標志位蔓涧,使響應以字節(jié)流方式進行讀取,r.raw.read函數(shù)指定讀取的字節(jié)數(shù)笋额。
3.3 請求頭headers處理
Requests對headers的處理和urllib2非常相似元暴,在Requests的get函數(shù)中添加headers參數(shù)即可。示例如下:
import?requests
user_agent?=?'Mozilla/4.0?(compatible;?MSIE?5.5;?Windows?NT)'
headers={'User-Agent':user_agent}
r?=?requests.get('http://www.baidu.com',headers=headers)
print?r.content
3.4 響應碼code和響應頭headers處理
獲取響應碼是使用Requests中的status_code字段兄猩,獲取響應頭使用Requests中的headers字段茉盏。示例如下:
import?requests
r?=?requests.get('http://www.baidu.com')
if?r.status_code?==?requests.codes.ok:
print?r.status_code#?響應碼
print?r.headers#?響應頭
print?r.headers.get('content-type')#?推薦使用這種獲取方式,獲取其中的某個字段
print?r.headers['content-type']#?不推薦使用這種獲取方式
else:
r.raise_for_status()
上述程序中枢冤,r.headers包含所有的響應頭信息鸠姨,可以通過get函數(shù)獲取其中的某一個字段,也可以通過字典引用的方式獲取字典值淹真,但是不推薦讶迁,因為如果字段中沒有這個字段,第二種方式會拋出異常核蘸,第一種方式會返回None巍糯。
r.raise_for_status()是用來主動地產(chǎn)生一個異常,當響應碼是4XX或5XX時客扎,raise_for_status()函數(shù)會拋出異常祟峦,而響應碼為200時,raise_for_status()函數(shù)返回None徙鱼。
3.5 Cookie處理
如果響應中包含Cookie的值宅楞,可以如下方式獲取Cookie字段的值,示例如下:
import?requests
user_agent?=?'Mozilla/4.0?(compatible;?MSIE?5.5;?Windows?NT)'
headers={'User-Agent':user_agent}
r?=?requests.get('http://www.baidu.com',headers=headers)
#?遍歷出所有的cookie字段的值
for?cookie?in?r.cookies.keys():
print?cookie+':'+r.cookies.get(cookie)
如果想自定義Cookie值發(fā)送出去袱吆,可以使用以下方式厌衙,示例如下:
import?requests
user_agent?=?'Mozilla/4.0?(compatible;?MSIE?5.5;?Windows?NT)'
headers={'User-Agent':user_agent}
cookies?=?dict(name='qiye',age='10')
r?=?requests.get('http://www.baidu.com',headers=headers,cookies=cookies)
print?r.text
還有一種更加高級,且能自動處理Cookie的方式杆故,有時候我們不需要關(guān)心Cookie值是多少迅箩,只是希望每次訪問的時候,程序自動把Cookie的值帶上处铛,像瀏覽器一樣饲趋。Requests提供了一個session的概念,在連續(xù)訪問網(wǎng)頁撤蟆,處理登錄跳轉(zhuǎn)時特別方便奕塑,不需要關(guān)注具體細節(jié)。使用方法示例如下:
import?Requests
oginUrl?=?'http://www.xxxxxxx.com/login'
s?=?requests.Session()
#首先訪問登錄界面家肯,作為游客龄砰,服務器會先分配一個cookie
r?=?s.get(loginUrl,allow_redirects=True)
datas={'name':'qiye','passwd':'qiye'}
#向登錄鏈接發(fā)送post請求,驗證成功,游客權(quán)限轉(zhuǎn)為會員權(quán)限
r?=?s.post(loginUrl,?data=datas,allow_redirects=?True)
print?r.text
上面的這段程序换棚,其實是正式做Python開發(fā)中遇到的問題式镐,如果沒有第一步訪問登錄的頁面,而是直接向登錄鏈接發(fā)送Post請求固蚤,系統(tǒng)會把你當做非法用戶娘汞,因為訪問登錄界面時會分配一個Cookie,需要將這個Cookie在發(fā)送Post請求時帶上夕玩,這種使用Session函數(shù)處理Cookie的方式之后會很常用你弦。
3.6 重定向與歷史信息
處理重定向只是需要設置一下allow_redirects字段即可,例如:
r=requests.get('http://www.baidu.com',allow_redirects=True)
將allow_redirects設置為True燎孟,則是允許重定向禽作;設置為False,則是禁止重定向揩页。如果是允許重定向旷偿,可以通過r.history字段查看歷史信息,即訪問成功之前的所有請求跳轉(zhuǎn)信息碍沐。示例如下:
import?requests
r?=?requests.get('http://github.com')
print?r.url
print?r.status_code
print?r.history
打印結(jié)果如下:
https://github.com/
200
(,)
上面的示例代碼顯示的效果是訪問GitHub網(wǎng)址時狸捅,會將所有的HTTP請求全部重定向為HTTPS衷蜓。
3.7 超時設置
超時選項是通過參數(shù)timeout來進行設置的累提,示例如下:
requests.get('http://github.com',?timeout=2)
3.8 代理設置
使用代理Proxy,你可以為任意請求方法通過設置proxies參數(shù)來配置單個請求:
import?requests
proxies?=?{
"http":?"http://0.10.1.10:3128",
"https":?"http://10.10.1.10:1080",
}
requests.get("http://example.org",?proxies=proxies)
也可以通過環(huán)境變量HTTP_PROXY和HTTPS_PROXY?來配置代理磁浇,但是在爬蟲開發(fā)中不常用斋陪。你的代理需要使用HTTP Basic Auth,可以使用http://user:password@host/語法:
proxies?=?{
"http":?"http://user:pass@10.10.1.10:3128/",
}
03
小結(jié)
本文主要講解了網(wǎng)絡爬蟲的結(jié)構(gòu)和應用置吓,以及Python實現(xiàn)HTTP請求的幾種方法。希望大家對本文中的網(wǎng)絡爬蟲工作流程和Requests實現(xiàn)HTTP請求的方式重點吸收消化。
本文摘編自《Python爬蟲開發(fā)與項目實戰(zhàn)》涨醋,經(jīng)出版方授權(quán)發(fā)布功蜓。
關(guān)于作者:范傳輝,資深網(wǎng)蟲戴质,Python開發(fā)者度宦,參與開發(fā)了多項網(wǎng)絡應用,在實際開發(fā)中積累了豐富的實戰(zhàn)經(jīng)驗,并善于總結(jié)告匠,貢獻了多篇技術(shù)文章廣受好評戈抄。研究興趣是網(wǎng)絡安全、爬蟲技術(shù)后专、數(shù)據(jù)分析划鸽、驅(qū)動開發(fā)等技術(shù)。