手把手教你利用爬蟲爬網(wǎng)頁(Python代碼)

本文主要分為兩個部分:一部分是網(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ù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市裸诽,隨后出現(xiàn)的幾起案子嫂用,更是在濱河造成了極大的恐慌,老刑警劉巖丈冬,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尸折,死亡現(xiàn)場離奇詭異,居然都是意外死亡殷蛇,警方通過查閱死者的電腦和手機实夹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粒梦,“玉大人亮航,你說我怎么就攤上這事≡让牵” “怎么了缴淋?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長泄朴。 經(jīng)常有香客問我重抖,道長,這世上最難降的妖魔是什么祖灰? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任钟沛,我火速辦了婚禮,結(jié)果婚禮上局扶,老公的妹妹穿的比我還像新娘恨统。我一直安慰自己,他們只是感情好三妈,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布畜埋。 她就那樣靜靜地躺著,像睡著了一般畴蒲。 火紅的嫁衣襯著肌膚如雪悠鞍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天模燥,我揣著相機與錄音咖祭,去河邊找鬼。 笑死涧窒,一個胖子當著我的面吹牛心肪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播纠吴,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼硬鞍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起固该,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤锅减,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后伐坏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體怔匣,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年桦沉,在試婚紗的時候發(fā)現(xiàn)自己被綠了每瞒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡纯露,死狀恐怖剿骨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情埠褪,我是刑警寧澤浓利,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站钞速,受9級特大地震影響贷掖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渴语,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一苹威、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧遵班,春花似錦屠升、人聲如沸潮改。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汇在。三九已至翰萨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間糕殉,已是汗流浹背亩鬼。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留阿蝶,地道東北人雳锋。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像羡洁,于是被迫代替她去往敵國和親玷过。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容