Python WebbingGrap 探索一

? ? 前端時間自學了python的基本語法,為深入了解python,就打算真正的鼓搗些東西,加深記憶。據說,python經常用來網頁抓取(爬蟲),故而新手小試,并記之。

網頁數據采集多線程設計:

1>輸入:多個線程共享一個任務隊列,如果該任務方案支持網絡,可設計為分布式集群采集;2>輸出:最簡單的做法是直接將采集數據放入數據庫,但頻繁操作數據庫會增加耗時,故而多個輸出可共享一個消息隊列,再用線程處理消息隊列;事實上該消息隊列可模擬為OS經典生產者和消費者模式中的共享緩沖池。

1.網例一之:python多線程數據采集

要點1:python多線程

python的多線程編程,這里題外話的說一下線程和進程的區別:1>進程(有時被稱為重量級進程)是程序的一次執行每個進程都有自己的地址空間,內存,數據棧以及其他記錄其運行軌跡的輔助數據(os層面)。進程可通過fork和spawn操作來完成其他任務,但由于各自內存獨立,故只能使用進程間通訊(IPC),而不能直接共享信息;2>線程(有時被稱為輕量級進程)與進程相似,不同是所有的線程運行在同一個進程中,共享相同的運行環境(包括數據空間,故可方便通訊)。線程有開始、順序執行和結束三部分,持有自己的指令指針,記錄自己運行到什么地方。線程的運行可能被中斷(搶占)或睡眠(暫時被掛起),以讓步于其他線程。線程一般都是并發執行的,事實上在單CPU系統中真正的并發是不可能的,每個線程會被安排成每次只占用CPU運行一段時間。多個線程共同訪問同一片數據有可能導致數據結果的不一致的問題,這叫做競態條件。

至于Python的多線程,由于其原始解釋器CPython中存在著GIL(Global Interpreter Lock,全局解釋器鎖),雖然CPython線程庫直接封裝了系統的原生線程,但(整體進程)同一時間只會獲得一個GIL線程執行,直到解釋器遇到I/O操作或者操作次數達到一定數目時才會釋放GIL。故即使多線程也只是做分時切換而已。

所以如果你的Python代碼是CPU密集型,此時多線程的代碼很有可能是線性執行的,這種情況下多線程是雞肋,效率可能還不如單線程因;但如果你的代碼是IO密集型,Python多線程可以明顯提高效率。

但如果確實需要在CPU密集型的代碼里用并行,可以用multiprocessing庫。這個庫是基于multi process實現了類multi thread的API接口,并且用pickle部分地實現了變量共享。

如果確實理不清Python代碼是CPU密集型還是IO密集型,那么分別嘗試下面的兩種Python多線程方法:

1>from multiprocessing import Pool(這就是基于multithread實現了multiprocessing的API,多進程同步);

2>from multiprocessing.dummy import Pool(這是多線程實現的同步)兩種方式都跑一下,哪個速度快用哪個就行了。

一般使用:

threading模塊中的Thread類可用來創建線程,創建方法有如下兩種:1.通過繼承Thread類,重寫它的run方法;2.創建一個threading.Thread對象,在初始化函數(__init__)中將可調用對象作為參數傳入:threading.Thread.__init__(self,name=threadname)。

要點2. 目標數據及相關第三方packages

采集目標:淘寶;?采集數據:某一關鍵詞領域的淘寶店鋪名稱、URL地址、店鋪等級;?

相關第三方packages:requests(http://devcharm.com/pages/11-python-modules-you-should-know);beautifulsoup4(PS:保證lxml model已安裝過);Redis

代碼部分:

1. search_config.py


#coding=utf-8

class config:

keyword ='青島' ? ?search_type ='shop' ? url='http://s.taobao.com/search?q='+ keyword ?+'&commend=all&search_type='+ search_type +'&sourceId=tb.index&initiative_id=tbindexz_20131207&app=shopsearch&s='

simple_scrapy.py

#coding=utf-8

import request

from bs4 import BeautifulSoup

from search_config import config

from Queue import Queue

import threading

class Scrapy(threading.Thread)

def __init__(self,threadname,queue,out_queue):

? ? threading.Thread.__init__(self,threadname)

? ? self.sharedata=queue

? ? self.out_queue=out_queue

? ? self.threadname=threadname

? ? print threadname+'start......'

def run(self):

? ? url=config.url+self.sharesata.get()

? ? response=requests.get(url)

? ? self.out_queue.put(response)

? ? print self.threadname+'end......'

class Parse(threading.Thread):

def __init__(self,threadname,queue,out_queue):

threading.Thread.__int__(self,name=threadname)

self.sharedata=queue

self.out_queue=out_queue

self.threadname=threadname

print threadname+'start......'

def run(self)

response=self.sharedata.get()

body=response.content

soup=BeautifulSoup(body)

ul_html=soup.find('ul',{'id':'list-container'})

lists=ul_html.findAll('li',{'class':'list-item'})

stores=[]

for list in lists

store={}

try:

info=list.findAll('a',{'trace':'shop'})

?for info in infos

? ? attrs=dict(info.attrs)

? ? if attrs.has_key('class'):

? ? ? ?if 'rank' in attrs['class']

? ? ? ? ? ?rank_string=attrs['class']

? ? ? ? ? rank_num=rank_string[-2:]

? ? ? ? ? if rank_num[0]=='-':

? ? ? ? ? ? store['rank']=rank_num[-1]

? ? ? ? ? else:

? ? ? ? ? ? store['rank']=rank_num

? ? ? ?if attrs.has_key('title')

? ? ? ? ? store['title']=attrs['title']

? ? ? ? ? store['href']=attrs['href']

? ? except ?AttibuteError:

? ? ? pass

if store:

? ?stores.append(store)

for store in stores:?

? ? print store['title'] +''+ store['rank']

print self.threadname +'end......'

def ?main():

? ? queue=Queue()

? ? targets=Queue()

? ? stores=Queue()

? ? scrapy=[]

? ? for i ?in range(0,13,6):#queue 原始請求#targets 等待解析的內容#stores解析完成的內容,這里為了簡單直觀,直接在線程中輸出了內容,并沒有使用該隊列

? ? ? ? queue.put(str(i))

? ? ? ? scrapy= Scrapy('scrapy', queue, targets)

? ? ? ? scrapy.start()

? ? ? ? parse= Parse('parse', targets, stores)

? ? ? ? parse.start()

if__name__=='__main__':

? ?main()

注解:1》使用BeautifulSoup庫,可以直接按照class或者id等html的attr來進行提取,相較于直接寫正則表達式難度系數降低很多,當然執行效率上,相應的也就大打折扣了。

2》通過scrapy線程不斷提供數據,parse線程從隊列中取出數據進行相應解析;作者將這二者寫到了同一個循環體中:即get一個response后隨即刻parse掉,但我認為這二者完全可以參照生產者消費者模式,將二者模塊分開,僅共享一消息隊列即可。

3》由于共享數據不存在安全問題,所以上面的例子都是非線程安全的,并沒有為共享數據加鎖,只是實現了最簡單的FIFO,所以也不會是因為鎖的開銷導致效率沒有得到真正提高

4》由于數據解析是CPU密集型操作,而網絡請求是I/O密集型操作,考慮上文說到的GIL,數據解析操作操作的多線程并不能帶來效率上的提升,相反可能因為線程的頻繁切換,導致效率下降;而網絡抓取的多線程則可以利用IO阻塞等待時的空閑時間執行其他線程,提升效率。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380

推薦閱讀更多精彩內容

  • 我們前面提到了進程是由若干線程組成的,一個進程至少有一個線程。多線程優點: 在一個進程中的多線程和主線程分享相同的...
    第八共同體閱讀 529評論 0 0
  • 1.進程和線程 隊列:1、進程之間的通信: q = multiprocessing.Queue()2、...
    一只寫程序的猿閱讀 1,119評論 0 17
  • Python的面向對象 類 Class 類變量 Class variable 數據成員 Data member 函...
    JasonJe閱讀 1,145評論 0 3
  • 線程 1.同步概念 1.多線程開發可能遇到的問題 同步不是一起的意思,是協同步調 假設兩個線程t1和t2都要對nu...
    TENG書閱讀 620評論 0 1
  • 線程 引言&動機 考慮一下這個場景,我們有10000條數據需要處理,處理每條數據需要花費1秒,但讀取數據只需要0....
    不浪漫的浪漫_ea03閱讀 372評論 0 0