一、網(wǎng)絡爬蟲的定義
網(wǎng)絡爬蟲,即Web Spider,是一個很形象的名字。
把互聯(lián)網(wǎng)比喻成一個蜘蛛網(wǎng),那么Spider就是在網(wǎng)上爬來爬去的蜘蛛。
網(wǎng)絡蜘蛛是通過網(wǎng)頁的鏈接地址來尋找網(wǎng)頁的。
從網(wǎng)站某一個頁面(通常是首頁)開始,讀取網(wǎng)頁的內(nèi)容,找到在網(wǎng)頁中的其它鏈接地址,
然后通過這些鏈接地址尋找下一個網(wǎng)頁,這樣一直循環(huán)下去,直到把這個網(wǎng)站所有的網(wǎng)頁都抓取完為止。
如果把整個互聯(lián)網(wǎng)當成一個網(wǎng)站,那么網(wǎng)絡蜘蛛就可以用這個原理把互聯(lián)網(wǎng)上所有的網(wǎng)頁都抓取下來。
這樣看來,網(wǎng)絡爬蟲就是一個爬行程序,一個抓取網(wǎng)頁的程序。
網(wǎng)絡爬蟲的基本操作是抓取網(wǎng)頁。
那么如何才能隨心所欲地獲得自己想要的頁面?
我們先從URL開始。
二、瀏覽網(wǎng)頁的過程
抓取網(wǎng)頁的過程其實和讀者平時使用IE瀏覽器瀏覽網(wǎng)頁的道理是一樣的。
比如說你在瀏覽器的地址欄中輸入 www.baidu.com 這個地址。
打開網(wǎng)頁的過程其實就是瀏覽器作為一個瀏覽的“客戶端”,向服務器端發(fā)送了 一次請求,把服務器端的文件“抓”到本地,再進行解釋、展現(xiàn)。
HTML是一種標記語言,用標簽標記內(nèi)容并加以解析和區(qū)分。
瀏覽器的功能是將獲取到的HTML代碼進行解析,然后將原始的代碼轉(zhuǎn)變成我們直接看到的網(wǎng)站頁面。
三、URI和URL的概念和舉例
簡單的來講,URL就是在瀏覽器端輸入的 http://www.baidu.com 這個字符串。
在理解URL之前,首先要理解URI的概念。
什么是URI?
Web上每種可用的資源,如 HTML文檔、圖像、視頻片段、程序等都由一個通用資源標志符(Universal Resource Identifier, URI)進行定位。
URI通常由三部分組成:
①訪問資源的命名機制;
②存放資源的主機名;
③資源自身 的名稱,由路徑表示。
如下面的URI:
http://www.why.com.cn/myhtml/html1223/
我們可以這樣解釋它:
①這是一個可以通過HTTP協(xié)議訪問的資源,
②位于主機 www.why.com.cn上,
③通過路徑“/myhtml/html1223”訪問。
四、利用urllib2通過指定的URL抓取網(wǎng)頁內(nèi)容
在Python中,我們使用urllib2這個組件來抓取網(wǎng)頁。urllib2是Python的一個獲取URLs(Uniform Resource Locators)的組件。它以urlopen函數(shù)的形式提供了一個非常簡單的接口。
import urllib2
req = urllib2.Request('http://www.baidu.com')
response = urllib2.urlopen(req)
the_page = response.read()
print the_page
在HTTP請求時,允許你做額外的兩件事:
1.發(fā)送data表單數(shù)據(jù)
這個內(nèi)容相信做過Web端的都不會陌生,有時候你希望發(fā)送一些數(shù)據(jù)到URL(通常URL與CGI[通用網(wǎng)關接口]腳本,或其他WEB應用程序掛接)。
在HTTP中,這個經(jīng)常使用熟知的POST請求發(fā)送。
這個通常在你提交一個HTML表單時由你的瀏覽器來做。
并不是所有的POSTs都來源于表單,你能夠使用POST提交任意的數(shù)據(jù)到你自己的程序。
一般的HTML表單,data需要編碼成標準形式。然后做為data參數(shù)傳到Request對象。
編碼工作使用urllib的函數(shù)而非urllib2。
values = {'name' : 'WHY',
'location' : 'SDU',
'language' : 'Python' }
data = urllib.urlencode(values) # 編碼工作
req = urllib2.Request(url, data) # 發(fā)送請求同時傳data表單
response = urllib2.urlopen(req) #接受反饋的信息
the_page = response.read() #讀取反饋的內(nèi)容
如果沒有傳送data參數(shù),urllib2使用GET方式的請求。
GET和POST請求的不同之處是POST請求通常有"副作用",
它們會由于某種途徑改變系統(tǒng)狀態(tài)(例如提交成堆垃圾到你的門口)。
Data同樣可以通過在Get請求的URL本身上面編碼來傳送。
import urllib2
import urllib
data = {}
data['name'] = 'WHY'
data['location'] = 'SDU'
data['language'] = 'Python'
url_values = urllib.urlencode(data)
print url_values
name=Somebody+Here&language=Python&location=Northampton
url = 'http://www.example.com/example.cgi'
full_url = url + '?' + url_values
data = urllib2.open(full_url)
這樣就實現(xiàn)了Data數(shù)據(jù)的Get傳送。
2.設置Headers到http請求
有一些站點不喜歡被程序(非人為訪問)訪問,或者發(fā)送不同版本的內(nèi)容到不同的瀏覽器。
默認的urllib2把自己作為“Python-urllib/x.y”(x和y是Python主版本和次版本號,例如Python-urllib/2.7),
這個身份可能會讓站點迷惑,或者干脆不工作。
瀏覽器確認自己身份是通過User-Agent頭,當你創(chuàng)建了一個請求對象,你可以給他一個包含頭數(shù)據(jù)的字典。
下面的例子發(fā)送跟上面一樣的內(nèi)容,但把自身模擬成Internet Explorer。
import urllib
import urllib2
url = 'http://www.someserver.com/cgi-bin/register.cgi'
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
values = {'name' : 'WHY',
'location' : 'SDU',
'language' : 'Python' }
headers = { 'User-Agent' : user_agent }
data = urllib.urlencode(values)
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
the_page = response.read()
五、異常的處理和HTTP狀態(tài)碼的分類
先來說一說HTTP的異常處理問題。
當urlopen不能夠處理一個response時,產(chǎn)生urlError。
不過通常的Python APIs異常如ValueError,TypeError等也會同時產(chǎn)生。
HTTPError是urlError的子類,通常在特定HTTP URLs中產(chǎn)生。
1.URLError
通常,URLError在沒有網(wǎng)絡連接(沒有路由到特定服務器),或者服務器不存在的情況下產(chǎn)生。
這種情況下,異常同樣會帶有"reason"屬性,它是一個tuple(可以理解為不可變的數(shù)組),
包含了一個錯誤號和一個錯誤信息。
我們建一個urllib2_test06.py來感受一下異常的處理:
import urllib2
req = urllib2.Request('http://www.baibai.com')
try: urllib2.urlopen(req)
except urllib2.URLError, e:
print e.reason
按下F5,可以看到打印出來的內(nèi)容是:
[Errno 11001] getaddrinfo failed
也就是說,錯誤號是11001,內(nèi)容是getaddrinfo failed
2.HTTPError
服務器上每一個HTTP 應答對象response包含一個數(shù)字"狀態(tài)碼"。
有時狀態(tài)碼指出服務器無法完成請求。默認的處理器會為你處理一部分這種應答。
例如:假如response是一個"重定向",需要客戶端從別的地址獲取文檔,urllib2將為你處理。
其他不能處理的,urlopen會產(chǎn)生一個HTTPError。
典型的錯誤包含"404"(頁面無法找到),"403"(請求禁止),和"401"(帶驗證請求)。
HTTP狀態(tài)碼表示HTTP協(xié)議所返回的響應的狀態(tài)。
比如客戶端向服務器發(fā)送請求,如果成功地獲得請求的資源,則返回的狀態(tài)碼為200,表示響應成功。
如果請求的資源不存在, 則通常返回404錯誤。
HTTP狀態(tài)碼通常分為5種類型,分別以1~5五個數(shù)字開頭,由3位整數(shù)組成:
200:請求成功 處理方式:獲得響應的內(nèi)容,進行處理
201:請求完成,結(jié)果是創(chuàng)建了新資源。新創(chuàng)建資源的URI可在響應的實體中得到 處理方式:爬蟲中不會遇到
202:請求被接受,但處理尚未完成 處理方式:阻塞等待
204:服務器端已經(jīng)實現(xiàn)了請求,但是沒有返回新的信 息。如果客戶是用戶代理,則無須為此更新自身的文檔視圖。 處理方式:丟棄
300:該狀態(tài)碼不被HTTP/1.0的應用程序直接使用, 只是作為3XX類型回應的默認解釋。存在多個可用的被請求資源。 處理方式:若程序中能夠處理,則進行進一步處理,如果程序中不能處理,則丟棄
301:請求到的資源都會分配一個永久的URL,這樣就可以在將來通過該URL來訪問此資源 處理方式:重定向到分配的URL
302:請求到的資源在一個不同的URL處臨時保存 處理方式:重定向到臨時的URL
304 請求的資源未更新 處理方式:丟棄
400 非法請求 處理方式:丟棄
401 未授權(quán) 處理方式:丟棄
403 禁止 處理方式:丟棄
404 沒有找到 處理方式:丟棄
5XX 回應代碼以“5”開頭的狀態(tài)碼表示服務器端發(fā)現(xiàn)自己出現(xiàn)錯誤,不能繼續(xù)執(zhí)行請求 處理方式:丟棄
HTTPError實例產(chǎn)生后會有一個整型'code'屬性,是服務器發(fā)送的相關錯誤號。
Error Codes錯誤碼
因為默認的處理器處理了重定向(300以外號碼),并且100-299范圍的號碼指示成功,所以你只能看到400-599的錯誤號碼。
BaseHTTPServer.BaseHTTPRequestHandler.response是一個很有用的應答號碼字典,顯示了HTTP協(xié)議使用的所有的應答號。
當一個錯誤號產(chǎn)生后,服務器返回一個HTTP錯誤號,和一個錯誤頁面。
你可以使用HTTPError實例作為頁面返回的應答對象response。
這表示和錯誤屬性一樣,它同樣包含了read,geturl,和info方法。
import urllib2
req = urllib2.Request('http://bbs.csdn.net/callmewhy')
try:
urllib2.urlopen(req)
except urllib2.URLError, e:
print e.code
#print e.read()
按下F5可以看見輸出了404的錯誤碼,也就說沒有找到這個頁面。
3.Wrapping
所以如果你想為HTTPError或URLError做準備,將有兩個基本的辦法。推薦使用第二種。
from urllib2 import Request, urlopen, URLError, HTTPError
req = Request('http://bbs.csdn.net/callmewhy')
try:
response = urlopen(req)
except HTTPError, e:
print 'The server couldn\'t fulfill the request.'
print 'Error code: ', e.code
except URLError, e:
print 'We failed to reach a server.'
print 'Reason: ', e.reason
else:
print 'No exception was raised.'
# everything is fine
和其他語言相似,try之后捕獲異常并且將其內(nèi)容打印出來。
這里要注意的一點,except HTTPError 必須在第一個,否則except URLError將同樣接受到HTTPError 。
因為HTTPError是URLError的子類,如果URLError在前面它會捕捉到所有的URLError(包括HTTPError )。
from urllib2 import Request, urlopen, URLError, HTTPError
req = Request('http://bbs.csdn.net/callmewhy')
try:
response = urlopen(req)
except URLError, e:
if hasattr(e, 'reason'):
print 'We failed to reach a server.'
print 'Reason: ', e.reason
elif hasattr(e, 'code'):
print 'The server couldn\'t fulfill the request.'
print 'Error code: ', e.code
else:
print 'No exception was raised.'
# everything is fine
六、Opener與Handler的介紹和實例應用
在開始后面的內(nèi)容之前,先來解釋一下urllib2中的兩個個方法:info and geturl
urlopen返回的應答對象response(或者HTTPError實例)有兩個很有用的方法info()和geturl()
1.geturl():
這個返回獲取的真實的URL,這個很有用,因為urlopen(或者opener對象使用的)或許會有重定向。獲取的URL或許跟請求URL不同。
以人人中的一個超級鏈接為例
from urllib2 import Request, urlopen, URLError, HTTPError
old_url = 'http://rrurl.cn/b1UZuP'
req = Request(old_url)
response = urlopen(req)
print 'Old url :' + old_url
print 'Real url :' + response.geturl()
運行結(jié)果如下:

2.info():
這個返回對象的字典對象,該字典描述了獲取的頁面情況。通常是服務器發(fā)送的特定頭headers。目前是httplib.HTTPMessage 實例。
經(jīng)典的headers包含"Content-length","Content-type",和其他內(nèi)容。
from urllib2 import Request, urlopen, URLError, HTTPError
old_url = 'http://www.baidu.com'
req = Request(old_url)
response = urlopen(req)
print 'Info():'
print response.info()
運行結(jié)果如下:

下面來說一說urllib2中的兩個重要概念:Openers和Handlers。
1.Openers:
當你獲取一個URL你使用一個opener(一個urllib2.OpenerDirector的實例)。
正常情況下,我們使用默認opener:通過urlopen。
但你能夠創(chuàng)建個性的openers。
2.Handles:
Openers使用處理器handlers,所有的“繁重”工作由handlers處理。
每個handlers知道如何通過特定協(xié)議打開URLs,或者如何處理URL打開時的各個方面。
例如HTTP重定向或者HTTP cookies。
如果你希望用特定處理器獲取URLs你會想創(chuàng)建一個openers,例如獲取一個能處理cookie的opener,或者獲取一個不重定向的opener。
要創(chuàng)建一個 opener,可以實例化一個OpenerDirector,
然后調(diào)用.add_handler(some_handler_instance)。
同樣,可以使用build_opener,這是一個更加方便的函數(shù),用來創(chuàng)建opener對象,他只需要一次函數(shù)調(diào)用。
build_opener默認添加幾個處理器,但提供快捷的方法來添加或更新默認處理器。
其他的處理器handlers你或許會希望處理代理,驗證,和其他常用但有點特殊的情況。
install_opener 用來創(chuàng)建(全局)默認opener。這個表示調(diào)用urlopen將使用你安裝的opener。
Opener對象有一個open方法。
該方法可以像urlopen函數(shù)那樣直接用來獲取urls:通常不必調(diào)用install_opener,除了為了方便。
說完了上面兩個內(nèi)容,下面我們來看一下基本認證的內(nèi)容,這里會用到上面提及的Opener和Handler。
Basic Authentication 基本驗證
為了展示創(chuàng)建和安裝一個handler,我們將使用HTTPBasicAuthHandler。
當需要基礎驗證時,服務器發(fā)送一個header(401錯誤碼) 請求驗證。這個指定了scheme 和一個‘realm’,看起來像這樣:Www-authenticate: SCHEME realm="REALM".
例如
Www-authenticate: Basic realm="cPanel Users"
客戶端必須使用新的請求,并在請求頭里包含正確的姓名和密碼。
這是“基礎驗證”,為了簡化這個過程,我們可以創(chuàng)建一個HTTPBasicAuthHandler的實例,并讓opener使用這個handler就可以啦。
HTTPBasicAuthHandler使用一個密碼管理的對象來處理URLs和realms來映射用戶名和密碼。
如果你知道realm(從服務器發(fā)送來的頭里)是什么,你就能使用HTTPPasswordMgr。
通常人們不關心realm是什么。那樣的話,就能用方便的HTTPPasswordMgrWithDefaultRealm。
這個將在你為URL指定一個默認的用戶名和密碼。
這將在你為特定realm提供一個其他組合時得到提供。
我們通過給realm參數(shù)指定None提供給add_password來指示這種情況。
最高層次的URL是第一個要求驗證的URL。你傳給.add_password()更深層次的URLs將同樣合適。
說了這么多廢話,下面來用一個例子演示一下上面說到的內(nèi)容。
# -*- coding: utf-8 -*-
import urllib2
# 創(chuàng)建一個密碼管理者
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
# 添加用戶名和密碼
top_level_url = "http://example.com/foo/"
# 如果知道 realm, 我們可以使用他代替 ``None``.
# password_mgr.add_password(None, top_level_url, username, password)
password_mgr.add_password(None, top_level_url,'why', '1223')
# 創(chuàng)建了一個新的handler
handler = urllib2.HTTPBasicAuthHandler(password_mgr)
# 創(chuàng)建 "opener" (OpenerDirector 實例)
opener = urllib2.build_opener(handler)
a_url = 'http://www.baidu.com/'
# 使用 opener 獲取一個URL
opener.open(a_url)
# 安裝 opener.
# 現(xiàn)在所有調(diào)用 urllib2.urlopen 將用我們的 opener.
urllib2.install_opener(opener)
注意:以上的例子我們僅僅提供我們的HHTPBasicAuthHandler給build_opener。
默認的openers有正常狀況的handlers:ProxyHandler,UnknownHandler,HTTPHandler,HTTPDefaultErrorHandler, HTTPRedirectHandler,F(xiàn)TPHandler, FileHandler, HTTPErrorProcessor。
代碼中的top_level_url 實際上可以是完整URL(包含"http:",以及主機名及可選的端口號)。
例如:http://example.com/。
也可以是一個“authority”(即主機名和可選的包含端口號)。
例如:“example.com” or “example.com:8080”。
后者包含了端口號。
七、urllib2的使用細節(jié)與抓站技巧
前面說到了urllib2的簡單入門,下面整理了一部分urllib2的使用細節(jié)。
1.Proxy 的設置
urllib2 默認會使用環(huán)境變量 http_proxy 來設置 HTTP Proxy。
如果想在程序中明確控制 Proxy 而不受環(huán)境變量的影響,可以使用代理。
import urllib2
enable_proxy = True
proxy_handler = urllib2.ProxyHandler({"http" : 'http://some-proxy.com:8080'})
null_proxy_handler = urllib2.ProxyHandler({})
if enable_proxy:
opener = urllib2.build_opener(proxy_handler)
else:
opener = urllib2.build_opener(null_proxy_handler)
urllib2.install_opener(opener)
這里要注意的一個細節(jié),使用 urllib2.install_opener() 會設置 urllib2 的全局 opener 。
這樣后面的使用會很方便,但不能做更細致的控制,比如想在程序中使用兩個不同的 Proxy 設置等。
比較好的做法是不使用 install_opener 去更改全局的設置,而只是直接調(diào)用 opener 的 open 方法代替全局的 urlopen 方法。
2.Timeout 設置
import urllib2
response = urllib2.urlopen('http://www.google.com', timeout=10)
3.在 HTTP Request 中加入特定的 Header
要加入 header,需要使用 Request 對象:
import urllib2
request = urllib2.Request('http://www.baidu.com/')
request.add_header('User-Agent', 'fake-client')
response = urllib2.urlopen(request)
print response.read()
對有些 header 要特別留意,服務器會針對這些 header 做檢查
User-Agent : 有些服務器或 Proxy 會通過該值來判斷是否是瀏覽器發(fā)出的請求
Content-Type : 在使用 REST 接口時,服務器會檢查該值,用來確定 HTTP Body 中的內(nèi)容該怎樣解析。常見的取值有:
application/xml : 在 XML RPC,如 RESTful/SOAP 調(diào)用時使用
application/json : 在 JSON RPC 調(diào)用時使用
application/x-www-form-urlencoded : 瀏覽器提交 Web 表單時使用
在使用服務器提供的 RESTful 或 SOAP 服務時, Content-Type 設置錯誤會導致服務器拒絕服務
4.Redirect
urllib2 默認情況下會針對 HTTP 3XX 返回碼自動進行 redirect 動作,無需人工配置。要檢測是否發(fā)生了 redirect 動作,只要檢查一下 Response 的 URL 和 Request 的 URL 是否一致就可以了。
import urllib2
my_url = 'http://www.google.cn'
response = urllib2.urlopen(my_url)
redirected = response.geturl() == my_url
print redirected
my_url = 'http://rrurl.cn/b1UZuP'
response = urllib2.urlopen(my_url)
redirected = response.geturl() == my_url
print redirected
如果不想自動 redirect,除了使用更低層次的 httplib 庫之外,還可以自定義HTTPRedirectHandler 類。
import urllib2
class RedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_301(self, req, fp, code, msg, headers):
print "301"
pass
def http_error_302(self, req, fp, code, msg, headers):
print "303"
pass
opener = urllib2.build_opener(RedirectHandler)
opener.open('http://rrurl.cn/b1UZuP')
5.Cookie
urllib2 對 Cookie 的處理也是自動的。如果需要得到某個 Cookie 項的值,可以這么做:
import urllib2
import cookielib
cookie = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
response = opener.open('http://www.baidu.com')
for item in cookie:
print 'Name = '+item.name
print 'Value = '+item.value
運行之后就會輸出訪問百度的Cookie值:

6.使用 HTTP 的 PUT 和 DELETE 方法
urllib2 只支持 HTTP 的 GET 和 POST 方法,如果要使用 HTTP PUT 和 DELETE ,只能使用比較低層的 httplib 庫。雖然如此,我們還是能通過下面的方式,使 urllib2 能夠發(fā)出 PUT 或DELETE 的請求:
import urllib2
request = urllib2.Request(uri, data=data)
request.get_method = lambda: 'PUT' # or 'DELETE'
response = urllib2.urlopen(request)
7.得到 HTTP 的返回碼
對于 200 OK 來說,只要使用 urlopen 返回的 response 對象的 getcode() 方法就可以得到 HTTP 的返回碼。但對其它返回碼來說,urlopen 會拋出異常。這時候,就要檢查異常對象的 code 屬性了:
import urllib2
try:
response = urllib2.urlopen('http://bbs.csdn.net/why')
except urllib2.HTTPError, e:
print e.code
8.Debug Log
使用 urllib2 時,可以通過下面的方法把 debug Log 打開,這樣收發(fā)包的內(nèi)容就會在屏幕上打印出來,方便調(diào)試,有時可以省去抓包的工作
import urllib2
httpHandler = urllib2.HTTPHandler(debuglevel=1)
httpsHandler = urllib2.HTTPSHandler(debuglevel=1)
opener = urllib2.build_opener(httpHandler, httpsHandler)
urllib2.install_opener(opener)
response = urllib2.urlopen('http://www.google.com')
這樣就可以看到傳輸?shù)臄?shù)據(jù)包內(nèi)容了:

9.表單的處理
登錄必要填表,表單怎么填?
首先利用工具截取所要填表的內(nèi)容。
比如我一般用firefox+httpfox插件來看看自己到底發(fā)送了些什么包。
以verycd為例,先找到自己發(fā)的POST請求,以及POST表單項。
可以看到verycd的話需要填username,password,continueURI,fk,login_submit這幾項,其中fk是隨機生成的(其實不太隨機,看上去像是把epoch時間經(jīng)過簡單的編碼生成的),需要從網(wǎng)頁獲取,也就是說得先訪問一次網(wǎng)頁,用正則表達式等工具截取返回數(shù)據(jù)中的fk項。continueURI顧名思義可以隨便寫,login_submit是固定的,這從源碼可以看出。還有username,password那就很顯然了:
# -*- coding: utf-8 -*-
import urllib
import urllib2
postdata=urllib.urlencode({
'username':'汪小光',
'password':'why888',
'continueURI':'http://www.verycd.com/',
'fk':'',
'login_submit':'登錄'
})
req = urllib2.Request(
url = 'http://secure.verycd.com/signin',
data = postdata
)
result = urllib2.urlopen(req)
print result.read()
10.偽裝成瀏覽器訪問
某些網(wǎng)站反感爬蟲的到訪,于是對爬蟲一律拒絕請求
這時候我們需要偽裝成瀏覽器,這可以通過修改http包中的header來實現(xiàn)
#…
headers = {
'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'
}
req = urllib2.Request(
url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/',
data = postdata,
headers = headers
)
#...
11.對付"反盜鏈"
某些站點有所謂的反盜鏈設置,其實說穿了很簡單,
就是檢查你發(fā)送請求的header里面,referer站點是不是他自己,
所以我們只需要像把headers的referer改成該網(wǎng)站即可,以cnbeta為例:
#...
headers = {
'Referer':'http://www.cnbeta.com/articles'
}
#...
headers是一個dict數(shù)據(jù)結(jié)構(gòu),你可以放入任何想要的header,來做一些偽裝。
例如,有些網(wǎng)站喜歡讀取header中的X-Forwarded-For來看看人家的真實IP,可以直接把X-Forwarde-For改了。
八、一個簡單的百度貼吧的小爬蟲
# -*- coding: utf-8 -*-
#---------------------------------------
# 程序:百度貼吧爬蟲
# 版本:0.1
# 作者:why
# 日期:2013-05-14
# 語言:Python 2.7
# 操作:輸入帶分頁的地址,去掉最后面的數(shù)字,設置一下起始頁數(shù)和終點頁數(shù)。
# 功能:下載對應頁碼內(nèi)的所有頁面并存儲為html文件。
#---------------------------------------
import string, urllib2
#定義百度函數(shù)
def baidu_tieba(url,begin_page,end_page):
for i in range(begin_page, end_page+1):
sName = string.zfill(i,5) + '.html'#自動填充成六位的文件名
print '正在下載第' + str(i) + '個網(wǎng)頁,并將其存儲為' + sName + '......'
f = open(sName,'w+')
m = urllib2.urlopen(url + str(i)).read()
f.write(m)
f.close()
#-------- 在這里輸入?yún)?shù) ------------------
# 這個是山東大學的百度貼吧中某一個帖子的地址
#bdurl = 'http://tieba.baidu.com/p/2296017831?pn='
#iPostBegin = 1
#iPostEnd = 10
bdurl = str(raw_input(u'請輸入貼吧的地址,去掉pn=后面的數(shù)字:\n'))
begin_page = int(raw_input(u'請輸入開始的頁數(shù):\n'))
end_page = int(raw_input(u'請輸入終點的頁數(shù):\n'))
#-------- 在這里輸入?yún)?shù) ------------------
#調(diào)用
baidu_tieba(bdurl,begin_page,end_page)