帶你入門Python爬蟲,8個(gè)常用爬蟲技巧盤點(diǎn)

python作為一門高級(jí)編程語言,它的定位是優(yōu)雅、明確和簡(jiǎn)單。 我 學(xué)用python 差不多一年時(shí)間了 ,用得最多的還是各類爬蟲腳本:寫過抓代理本機(jī)驗(yàn)證的腳本,寫過論壇中自動(dòng)登錄自動(dòng)發(fā)貼的腳本,寫過自動(dòng)收郵件的腳本,寫過簡(jiǎn)單的驗(yàn)證碼識(shí)別的腳本。

image

這些腳本有一個(gè)共性,都是和web相關(guān)的,總要用到獲取鏈接的一些方法, 故 累積 了 不少爬蟲抓站的經(jīng)驗(yàn),在此總結(jié)一下,那么以后做東西也就不用重復(fù)勞動(dòng)了。

1、基本抓取網(wǎng)頁(yè)

get方法

import urllib2 url = "http://www.baidu.com" response = urllib2.urlopen(url) print response.read()

post方法

import urllib import urllib2 url = "http://abcde.com" form = {'name':'abc','password':'1234'} form_data = urllib.urlencode(form) request = urllib2.Request(url,form_data) response = urllib2.urlopen(request) print response.read()

2.使用代理服務(wù)器

這在某些情況下比較有用,比如IP被封了,或者比如IP訪問的次數(shù)受到限制等等。

import urllib2

proxy_support = urllib2.ProxyHandler({'http':'http://XX.XX.XX.XX:XXXX'})

opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)

urllib2.install_opener(opener)

content = urllib2.urlopen('http://XXXX').read()

3.Cookies處理

import urllib2, cookielib

cookie_support= urllib2.HTTPCookieProcessor(cookielib.CookieJar())

opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)

urllib2.install_opener(opener)

content = urllib2.urlopen('http://XXXX').read()

是的沒錯(cuò),如果想同時(shí)用代理和cookie,那就加入proxy_support然后operner改為

opener=urllib2.build_opener(proxy_support, cookie_support, urllib2.HTTPHandler)

4.偽裝成瀏覽器訪問

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

)

5、頁(yè)面解析

對(duì)于頁(yè)面解析最強(qiáng)大的當(dāng)然是正則表達(dá)式,這個(gè)對(duì)于不同網(wǎng)站不同的使用者都不一樣,就不用過多的說明。

image

其次就是解析庫(kù)了,常用的有兩個(gè)lxml和BeautifulSoup。 對(duì)于這兩個(gè)庫(kù),我的評(píng)價(jià)是,都是HTML/XML的處理庫(kù),Beautifulsoup純python實(shí)現(xiàn),效率低,但是功能實(shí)用,比如能用通過結(jié)果搜索獲得某個(gè)HTML節(jié)點(diǎn)的源碼;lxmlC語言編碼,高效,支持Xpath 。

6.驗(yàn)證碼的處理

碰到驗(yàn)證碼咋辦?這里分兩種情況處理:

google那種驗(yàn)證碼, 沒辦法。

簡(jiǎn)單的驗(yàn)證碼:字符個(gè)數(shù)有限,只使用了簡(jiǎn)單的平移或旋轉(zhuǎn)加噪音而沒有扭曲的,這種還是有可能可以處理的,一般思路是旋轉(zhuǎn)的轉(zhuǎn)回來,噪音去掉,然后劃分單個(gè)字符,劃分好了以后再通過特征提取的方法(例如PCA)降維并生成特征庫(kù),然后把驗(yàn)證碼和特征庫(kù)進(jìn)行比較。這個(gè)比較復(fù)雜,這里就不展開了,具體做法請(qǐng)弄本相關(guān)教科書好好研究一下。

  1. gzip/deflate支持

現(xiàn)在的網(wǎng)頁(yè)普遍支持gzip壓縮,這往往可以解決大量傳輸時(shí)間,以VeryCD的主頁(yè)為例,未壓縮版本247K,壓縮了以后45K,為原來的1/5。這就意味著抓取速度會(huì)快5倍。

然而python的urllib/urllib2默認(rèn)都不支持壓縮,要返回壓縮格式,必須在request的header里面寫明’accept-encoding’,然后讀取response后更要檢查header查看是否有’content-encoding’一項(xiàng)來判斷是否需要解碼,很繁瑣瑣碎。如何讓urllib2自動(dòng)支持gzip, defalte呢?

其實(shí)可以繼承BaseHanlder類,然后build_opener的方式來處理:

import urllib2

from gzip import GzipFile

from StringIO import StringIO

class ContentEncodingProcessor(urllib2.BaseHandler):

"""A handler to add gzip capabilities to urllib2 requests """

add headers to requests

def http_request(self, req):

req.add_header("Accept-Encoding", "gzip, deflate")

return req

decode

def http_response(self, req, resp):

old_resp = resp

gzip

if resp.headers.get("content-encoding") == "gzip":

gz = GzipFile(

fileobj=StringIO(resp.read()),

mode="r"

)

resp = urllib2.addinfourl(gz, old_resp.headers, old_resp.url, old_resp.code)

resp.msg = old_resp.msg

deflate

if resp.headers.get("content-encoding") == "deflate":

gz = StringIO( deflate(resp.read()) )

resp = urllib2.addinfourl(gz, old_resp.headers, old_resp.url, old_resp.code) # 'class to add info() and

resp.msg = old_resp.msg

return resp

deflate support

import zlib

def deflate(data): # zlib only provides the zlib compress format, not the deflate format;

try: # so on top of all there's this workaround:

return zlib.decompress(data, -zlib.MAX_WBITS)

except zlib.error:

return zlib.decompress(data)

然后就簡(jiǎn)單了,

encoding_support = ContentEncodingProcessor

opener = urllib2.build_opener( encoding_support, urllib2.HTTPHandler )

直接用opener打開網(wǎng)頁(yè),如果服務(wù)器支持gzip/defalte則自動(dòng)解壓縮

content = opener.open(url).read()

8、多線程并發(fā)抓取

單線程太慢的話,就需要多線程了,這里給個(gè)簡(jiǎn)單的線程池模板這個(gè)程序只是簡(jiǎn)單地打印了1-10,但是可以看出是并發(fā)的。

雖然說Python的多線程很雞肋,但是對(duì)于爬蟲這種網(wǎng)絡(luò)頻繁型,還是能一定程度提高效率的。

from threading import Thread from Queue import Queue from time import sleep # q是任務(wù)隊(duì)列#NUM是并發(fā)線程總數(shù) #JOBS是有多少任務(wù) q = Queue() NUM = 2 JOBS = 10 #具體的處理函數(shù),負(fù)責(zé)處理單個(gè)任務(wù) def do_somthing_using(arguments): print arguments #這個(gè)是工作進(jìn)程,負(fù)責(zé)不斷從隊(duì)列取數(shù)據(jù)并處理 def working(): while True: arguments = q.get() do_somthing_using(arguments) sleep(1) q.task_done() #fork NUM個(gè)線程等待隊(duì)列 for i in range(NUM): t = Thread(target=working) t.setDaemon(True) t.start() #把JOBS排入隊(duì)列 for i in range(JOBS): q.put(i) #等待所有JOBS完成 q.join()

9. 總結(jié)

閱讀Python編寫的代碼感覺像在閱讀英語一樣,這讓使用者可以專注于解決問題而不是去搞明白語言本身。Python雖然是基于C語言編寫,但是摒棄了C中復(fù)雜的指針,使其變得簡(jiǎn)明易學(xué)。并且作為開源軟件,Python允許對(duì)代碼進(jìn)行閱讀,拷貝甚至改進(jìn)。這些性能成就了Python的高效率,有“人生苦短,我用Python”之說,是一種十分精彩又強(qiáng)大的語言。

總而言之, 開始學(xué) Python一定要 注意 這 4 點(diǎn):

1.代碼規(guī)范,這本身就是一個(gè)非常好的習(xí)慣,如果開始不養(yǎng)好好的代碼規(guī)劃,以后會(huì)很痛苦 。

2.多動(dòng)手,少看書,很多人學(xué)Python就一味的看書,這不是學(xué)數(shù)學(xué)物理,你看例題可能就會(huì)了,學(xué)習(xí)Python主要是學(xué)習(xí)編程思想。

3.勤練習(xí),學(xué)完新的知識(shí)點(diǎn),一定要記得如何去應(yīng)用,不然學(xué)完就會(huì)忘,學(xué)我們這行主要都是實(shí)際操作。

4.學(xué)習(xí)要有效率,如果自己都覺得效率非常低,那就停不停,找一下原因,去問問過來人這是為什么 。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容