在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ urllib2 的使用細(xì)節(jié)與抓站技巧
一個(gè)簡(jiǎn)單的百度貼吧的小爬蟲
亮劍!爬蟲框架小抓抓 Scrapy 閃亮登場(chǎng)!
Opener 與 Handler 的介紹和實(shí)例應(yīng)用
百度貼吧的網(wǎng)絡(luò)爬蟲(v0.4)源碼及解析
異常的處理和 HTTP 狀態(tài)碼的分類
利用 urllib2 通過(guò)指定的 URL 抓取網(wǎng)頁(yè)內(nèi)容
Python 中的正則表達(dá)式教程
爬蟲框架 Scrapy 的第一個(gè)爬蟲示例入門教程
抓取網(wǎng)頁(yè)的含義和 URL 基本構(gòu)成
urllib2 的使用細(xì)節(jié)與抓站技巧
一個(gè)爬蟲的誕生全過(guò)程(以山東大學(xué)績(jī)點(diǎn)運(yùn)算為例)
糗事百科的網(wǎng)絡(luò)爬蟲(v0.3)源碼及解析(簡(jiǎn)化更新)

urllib2 的使用細(xì)節(jié)與抓站技巧

前面說(shuō)到了 urllib2 的簡(jiǎn)單入門,下面整理了一部分 urllib2 的使用細(xì)節(jié)。

Proxy 的設(shè)置

urllib2 默認(rèn)會(huì)使用環(huán)境變量 http_proxy 來(lái)設(shè)置 HTTP Proxy。如果想在程序中明確控制 Proxy 而不受環(huán)境變量的影響,可以使用代理。

新建 test14 來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的代理 Demo:

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)  

這里要注意的一個(gè)細(xì)節(jié),使用 urllib2.install_opener() 會(huì)設(shè)置 urllib2 的全局 opener 。 這樣后面的使用會(huì)很方便,但不能做更細(xì)致的控制,比如想在程序中使用兩個(gè)不同的 Proxy 設(shè)置等。 比較好的做法是不使用 install_opener 去更改全局的設(shè)置,而只是直接調(diào)用 opener 的 open 方法代替全局的 urlopen 方法。

Timeout 設(shè)置

在老版 Python 中(Python2.6前),urllib2 的 API 并沒有暴露 Timeout 的設(shè)置,要設(shè)置 Timeout 值,只能更改 Socket 的全局 Timeout 值。

import urllib2  
import socket  
socket.setdefaulttimeout(10) # 10 秒鐘后超時(shí)  
urllib2.socket.setdefaulttimeout(10) # 另一種方式  

在 Python 2.6 以后,超時(shí)可以通過(guò) urllib2.urlopen() 的 timeout 參數(shù)直接設(shè)置。

import urllib2  
response = urllib2.urlopen('http://www.google.com', timeout=10)  

在 HTTP Request 中加入特定的 Header

要加入 header,需要使用 Request 對(duì)象:

import urllib2  
request = urllib2.Request('http://www.baidu.com/')  
request.add_header('User-Agent', 'fake-client')  
response = urllib2.urlopen(request)  
print response.read()  

對(duì)有些 header 要特別留意,服務(wù)器會(huì)針對(duì)這些 header 做檢查

  • User-Agent : 有些服務(wù)器或 Proxy 會(huì)通過(guò)該值來(lái)判斷是否是瀏覽器發(fā)出的請(qǐng)求
  • Content-Type : 在使用 REST 接口時(shí),服務(wù)器會(huì)檢查該值,用來(lái)確定 HTTP Body 中的內(nèi)容該怎樣解析。常見的取值有:
  • application/xml : 在 XML RPC,如 RESTful/SOAP 調(diào)用時(shí)使用
  • application/json : 在 JSON RPC 調(diào)用時(shí)使用
  • application/x-www-form-urlencoded : 瀏覽器提交 Web 表單時(shí)使用

在使用服務(wù)器提供的 RESTful 或 SOAP 服務(wù)時(shí), Content-Type 設(shè)置錯(cuò)誤會(huì)導(dǎo)致服務(wù)器拒絕服務(wù)

Redirect

urllib2 默認(rèn)情況下會(huì)針對(duì) HTTP 3XX 返回碼自動(dòng)進(jìn)行 redirect 動(dòng)作,無(wú)需人工配置。要檢測(cè)是否發(fā)生了 redirect 動(dòng)作,只要檢查一下 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  

如果不想自動(dòng) redirect,除了使用更低層次的 httplib 庫(kù)之外,還可以自定義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')  

Cookie

urllib2 對(duì) Cookie 的處理也是自動(dòng)的。如果需要得到某個(gè) Cookie 項(xiàng)的值,可以這么做:

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  

運(yùn)行之后就會(huì)輸出訪問(wèn)百度的 Cookie 值:

http://wiki.jikexueyuan.com/project/python-crawler/images/4.png" alt="" />

使用 HTTP 的 PUT 和 DELETE 方法

urllib2 只支持 HTTP 的 GET 和 POST 方法,如果要使用 HTTP PUT 和 DELETE ,只能使用比較低層的 httplib 庫(kù)。雖然如此,我們還是能通過(guò)下面的方式,使 urllib2 能夠發(fā)出 PUT 或DELETE 的請(qǐng)求:

import urllib2  
request = urllib2.Request(uri, data=data)  
request.get_method = lambda: 'PUT' # or 'DELETE'  
response = urllib2.urlopen(request)  

得到 HTTP 的返回碼

對(duì)于 200 OK 來(lái)說(shuō),只要使用 urlopen 返回的 response 對(duì)象的 getcode() 方法就可以得到 HTTP 的返回碼。但對(duì)其它返回碼來(lái)說(shuō),urlopen 會(huì)拋出異常。這時(shí)候,就要檢查異常對(duì)象的 code 屬性了:

import urllib2  
try:  
    response = urllib2.urlopen('http://bbs.csdn.net/why')  
except urllib2.HTTPError, e:  
    print e.code  

Debug Log

使用 urllib2 時(shí),可以通過(guò)下面的方法把 debug Log 打開,這樣收發(fā)包的內(nèi)容就會(huì)在屏幕上打印出來(lái),方便調(diào)試,有時(shí)可以省去抓包的工作

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)容了:

http://wiki.jikexueyuan.com/project/python-crawler/images/5.png" alt="" />

表單的處理

登錄必要填表,表單怎么填?

首先利用工具截取所要填表的內(nèi)容。比如我一般用 firefox+httpfox 插件來(lái)看看自己到底發(fā)送了些什么包。 以 verycd 為例,先找到自己發(fā)的 POST 請(qǐng)求,以及 POST 表單項(xiàng)??梢钥吹?verycd 的話需要填 username,password,continueURI,fk,login_submit這幾項(xiàng),其中fk是隨機(jī)生成的(其實(shí)不太隨機(jī),看上去像是把 epoch 時(shí)間經(jīng)過(guò)簡(jiǎn)單的編碼生成的),需要從網(wǎng)頁(yè)獲取,也就是說(shuō)得先訪問(wèn)一次網(wǎng)頁(yè),用正則表達(dá)式等工具截取返回?cái)?shù)據(jù)中的 fk 項(xiàng)。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()   

偽裝成瀏覽器訪問(wèn)

某些網(wǎng)站反感爬蟲的到訪,于是對(duì)爬蟲一律拒絕請(qǐng)求。這時(shí)候我們需要偽裝成瀏覽器,這可以通過(guò)修改 http 包中的 header 來(lái)實(shí)現(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  
)  
\#...  

對(duì)付"反盜鏈"

某些站點(diǎn)有所謂的反盜鏈設(shè)置,其實(shí)說(shuō)穿了很簡(jiǎn)單,就是檢查你發(fā)送請(qǐng)求的 header 里面,referer 站點(diǎn)是不是他自己,所以我們只需要像把 headers 的 referer 改成該網(wǎng)站即可,以 cnbeta 為例:

\#...
headers = {
    'Referer':'http://www.cnbeta.com/articles'
}
\#...

headers 是一個(gè) dict 數(shù)據(jù)結(jié)構(gòu),你可以放入任何想要的 header,來(lái)做一些偽裝。 例如,有些網(wǎng)站喜歡讀取 header 中的 X-Forwarded-For 來(lái)看看人家的真實(shí) IP,可以直接把 X-Forwarde-For 改了。