讓你的爬蟲效率提升40倍 python 多進(jìn)程+協(xié)程 爬蟲

多進(jìn)程

關(guān)于多進(jìn)程爬蟲和多進(jìn)程方面的知識可以參考崔慶才的博客python文檔


協(xié)程

關(guān)于協(xié)程的介紹,強(qiáng)烈推薦大家看看這份指南


由于GIL的原因,python解釋器中總是只有一個線程存在雏门,因此很難利用多線程來達(dá)到并行的目的搓逾。但多進(jìn)程并不受此限制尺迂,因此我們可以利用python中的多進(jìn)程來達(dá)到并行的目的具温。同時,我們可以在每個進(jìn)程中使用協(xié)程來實現(xiàn)異步的處理癞揉。綜上纸肉,我們可以利用多進(jìn)程+協(xié)程來極大的提升我們爬蟲的效率。


導(dǎo)入模塊

from multiprocessing import Pool, cpu_count
import requests
from gevent import monkey
from gevent.pool import Pool as ge_pool
from gevent.queue import Queue
import json
import copy
failed_urls = []      # 用于記錄爬取失敗的url喊熟,以備后續(xù)的繼續(xù)爬取
finished_urls = []    # 用于記錄爬取成功的url

分割url柏肪,在這里大家需要提前準(zhǔn)備好自己的url,因為作者是先爬取了所有所需網(wǎng)頁的url后芥牌,再來爬取每個url的內(nèi)容的

def split_urls(urls):
    if not urls:
        print('no url in urls')
        return [urls]
    num_urls = len(urls)
    num_cpus = cpu_count()
    if num_urls < num_cpus:
        return [urls]
    num_urls_per_cpu = int(num_urls / num_cpus)
    splitted_urls = []
    for i in range(num_cpus):
        if i == 0:
            splitted_urls.append(urls[: (i + 1) * num_urls_per_cpu])
        elif i == num_cpus - 1:
            splitted_urls.append(urls[i * num_urls_per_cpu:])
        else:
            splitted_urls.append(urls[i * num_urls_per_cpu: (i + 1) * num_urls_per_cpu])

    return splitted_urls

注意:在這里我們是根據(jù)自己機(jī)器的cpu核心數(shù)來劃分url的烦味,這樣可以充分利用機(jī)器的cpu。不建議開啟多于自己機(jī)器cpu核心數(shù)的線程數(shù)量壁拉,因為這會造成不必要的線程切換的時間上的浪費谬俄。


抓取網(wǎng)頁

def crawling_web(url):
    try:
        res = requests.get(url, headers=headers, cookies=cookies,  timeout=10)
        data = json.loads(res.text).get('data')
        print('success crawled {}'.format(url))
        finished_urls.append(url)
    except:
        failed_urls.append(url)
        print('fali to crawle {}'.format(url))

注意:由于作者所爬取的網(wǎng)頁比較簡單,得到的數(shù)據(jù)是以json格式展示的弃理,所以不需要過多的處理溃论,如果讀者需要對爬取的網(wǎng)頁做進(jìn)一步的處理,可以另寫一個處理的函數(shù)痘昌;讀者需要自己準(zhǔn)備好自己的headers和cookies以及proxies


協(xié)程

def greenlet_crawler(urls):
    greenlet_pool = ge_pool(10)
    for url in urls:
        greenlet_pool.apply_async(crawling_web, (url, ))
    greenlet_pool.join()

我們在這里使用了一個pool來維護(hù)10個協(xié)程钥勋,pool里面的協(xié)程異步的爬取網(wǎng)頁炬转。


多進(jìn)程以及調(diào)度器

def scheduler(urls):
    global failed_urls
    failed_urls = []
    splitted_urls = split_urls(urls)
    process_pool = Pool(processes=cpu_count())
    for urls in splitted_urls:
        process_pool.apply_async(greenlet_crawler, (urls,))
    process_pool.close()
    process_pool.join()
    if not failed_urls:
        scheduler(copy.deepcopy(failed_urls))

scheduler中多進(jìn)程部分的代碼如下

 process_pool = Pool(processes=cpu_count())
    for urls in splitted_urls:
        process_pool.apply_async(greenlet_crawler, (urls,))
    process_pool.close()
    process_pool.join()

我們開啟了與自己機(jī)器cpu核心數(shù)相同的線程,并使用線程池來維護(hù)這些線程算灸。
注意:因為我們無法保證每個網(wǎng)頁都被成功抓取下來了返吻,因此我們需要對抓取失敗的url再次進(jìn)行抓取,這里我們在sheduler中使用了遞歸的方式來保證失敗的url會被再次抓取乎婿。


if __name__ == '__main__':
    scheduler(urls)

結(jié)語: 只要我們能夠保持線程的并行以及每個線程內(nèi)部多個協(xié)程之間的異步,我們就可以使用多進(jìn)程+協(xié)程的方式來大幅提升我們的爬蟲的效率街佑,作者使用這種方式相比于單線程的爬蟲谢翎,速度的提升是20-40倍(當(dāng)然每個人要面對的場景以及所使用的資源都不一樣,這個速度的比值僅供參考)沐旨,最后還是推薦大家在爬蟲的時候試試這種多進(jìn)程+協(xié)程的方式森逮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市磁携,隨后出現(xiàn)的幾起案子褒侧,更是在濱河造成了極大的恐慌,老刑警劉巖谊迄,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闷供,死亡現(xiàn)場離奇詭異,居然都是意外死亡统诺,警方通過查閱死者的電腦和手機(jī)歪脏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粮呢,“玉大人婿失,你說我怎么就攤上這事∽墓眩” “怎么了豪硅?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長挺物。 經(jīng)常有香客問我懒浮,道長,這世上最難降的妖魔是什么姻乓? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任嵌溢,我火速辦了婚禮,結(jié)果婚禮上蹋岩,老公的妹妹穿的比我還像新娘赖草。我一直安慰自己,他們只是感情好剪个,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布秧骑。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乎折。 梳的紋絲不亂的頭發(fā)上绒疗,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機(jī)與錄音骂澄,去河邊找鬼吓蘑。 笑死,一個胖子當(dāng)著我的面吹牛坟冲,可吹牛的內(nèi)容都是我干的磨镶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼健提,長吁一口氣:“原來是場噩夢啊……” “哼琳猫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起私痹,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤脐嫂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后紊遵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體账千,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年暗膜,在試婚紗的時候發(fā)現(xiàn)自己被綠了蕊爵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡桦山,死狀恐怖攒射,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情恒水,我是刑警寧澤会放,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站钉凌,受9級特大地震影響咧最,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜御雕,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一矢沿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酸纲,春花似錦捣鲸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愁溜。三九已至,卻和暖如春外厂,著一層夾襖步出監(jiān)牢的瞬間冕象,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工汁蝶, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留渐扮,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓掖棉,卻偏偏與公主長得像席爽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子啊片,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354

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