Python 爬蟲——單線程舔亭、多線程些膨、多進(jìn)程對比

用 python 挺久了,但并沒有深入了解過多線程多進(jìn)程之類的知識钦铺,最近看了許多關(guān)于多線程多進(jìn)程的知識订雾,記錄簡單的實現(xiàn)過程。

方案

  • 爬取某網(wǎng)站 20 頁圖片矛洞,每頁大概 20~30 張圖片
  • 該網(wǎng)站沒有反爬措施
  • 爬蟲全速爬取洼哎,不設(shè)置休眠時間
  • 依次爬取每頁的圖片鏈接,保存至一個列表中(對于單線程沼本、多進(jìn)程方案)噩峦,保存至隊列(對于多線程方案),這一步使用單線程抽兆;然后用 urllib 下載圖片识补,這一步使用單線程、多線程辫红、多進(jìn)程分別爬取
  • 依次使用單線程凭涂、多線程祝辣、多進(jìn)程爬取相同的資源

共同代碼

下面的代碼是單線程、多線程切油、多進(jìn)程都要用到的基本代碼蝙斜。

import ... #省略...
folder_path3 = 'C://Users/Stone/Desktop/jiandan3/'
header = {
    ... # 省略...
}
image_links = []
def get_links(page):  # 獲取圖片鏈接
    for i in xrange(page):
        url = "https://some.net/pic/page-{}".format(str(i))
        response = requests.get(url, headers=header)
        soup = BeautifulSoup(response.text, "lxml")
        links = soup.select("div.row img")
        for pic_tag in links:  # 獲取圖片鏈接
            pic_link = pic_tag.get('src')
            if pic_link.startswith("http"):
                image_links.append(pic_link)
                # myqueue.put(pic_link)
            else:
                pic_link = 'http:' + pic_link
                image_links.append(pic_link)
                #myqueue.put(pic_link)
def download_pic(url): # 下載圖片
    img_name = "{}".format(os.path.basename(url))
    urllib.urlretrieve(url, folder_path3 + img_name)
    print "{} download seccessfully!".format(img_name)

單線程

單線程代碼比較簡單,獲取完 20 頁的圖片鏈接后澎胡,用 download_pic 方法一個一個下載圖片 :

if __name__ == '__main__':
    start_time = time.time()
    get_links(20)  # 爬取20頁
    for link in image_links:
        download_pic(link)  # 下載圖片
    end_time = time.time()
    print "all done!"
    print end_time - start_time 

此段代碼運行完后孕荠,統(tǒng)計數(shù)據(jù)如下:

爬取圖片數(shù)量 耗時
571張 102.9秒

多進(jìn)程

多進(jìn)程使用的是 multiprocessing 包下的 Pool類,它會根據(jù)電腦所擁有的核心自動創(chuàng)建 Pool 類的實例滤馍,也可以手動傳入?yún)?shù)岛琼;在 Pool 這個類中有 mapmap_async兩種方法,map 方法是阻塞的巢株,也就是 map 方法之后的代碼必須等待 map 方法執(zhí)行完成才能繼續(xù)進(jìn)行槐瑞,下面測試 map 方法:

if __name__ == '__main__':
    start_time = time.time()
    get_links(20)
    pool = Pool()
    pool.map(download_pic, image_links)        # 同步/阻塞     
    end_time = time.time()
    print "all done!"
    print end_time - start_time    # 多進(jìn)程

map 方法測試結(jié)果:

爬取圖片數(shù)量 耗時
571張 37.88秒

使用 map_async 方法爬取:

if __name__ == '__main__':
    start_time = time.time()
    get_links(20)
    pool = Pool()
    pool.map_async(download_pic, image_links)  # 異步
    pool.close()    # 關(guān)閉進(jìn)程連接 
    pool.join()      # 等待 map_async 函數(shù)執(zhí)行完成阁苞,在這阻塞 
    end_time = time.time()
    print "all done!"
    print end_time - start_time 

map_async 方法是異步的困檩,這一整段代碼運行到 map_async 方法時,不會等待這個方法完成那槽,而是繼續(xù)后面的代碼邏輯面哥,而 map_async 方法也在背后繼續(xù)進(jìn)行著香府;其中有個問題就是,當(dāng)后面的代碼運行完之后,就要停止特石,那么map_async 方法沒有運行完也會被停止弓叛,所以上面的代碼比 map 方法多了兩行镶苞,join 方法的功能就是等待map_async 函數(shù)執(zhí)行完成肝断,測試結(jié)果:

爬取圖片數(shù)量 耗時
571張 38.54秒

多線程

使用多線程需要 threading 包中 Thread 類,以及配合 Queue 類丈钙,多線程中非驮,使用 Queue 代替 ListQueue 有多種雏赦,FIFO(先進(jìn)先出)劫笙、LIFO(后進(jìn)先出)、優(yōu)先級隊列星岗,在此方案中用 FIFO 隊列填大,在原代碼做出相應(yīng)改變:

myqueue = Queue()
....
if pic_link.startswith("http"):
# image_links.append(pic_link)
    myqueue.put(pic_link)
else:
    pic_link = 'http:' + pic_link
# image_links.append(pic_link)
    myqueue.put(pic_link)

此外,再封裝一個方法:

def woker():
    while not myqueue.empty():
        img_url = myqueue.get()
        download_pic(img_url)
        myqueue.task_done()
        
if __name__ == '__main__':
    start_time = time.time()
    get_links(20)
    for x in range(4):   # 根據(jù)電腦性能設(shè)置核心
        thread = Thread(target=woker)   # 創(chuàng)建線程
        thread.start()
    myqueue.join()
    print "all done!"
    print time.time() - start_time  # 多線程伍茄!

此段代碼的作用:判斷隊列是否為空栋盹,不為空則將里面的 url 取出給 download_pic 下載,下載完成后敷矫,調(diào)用 Queue 類的 task_done 例获,告知電腦此次任務(wù)完成,結(jié)束資源占用曹仗。

myqueue.join() 方法和多進(jìn)程中的 pool.join() 方法作用大致相同榨汤,防止主線程結(jié)束后殺掉子線程。

測試結(jié)果:

爬取圖片數(shù)量 耗時
555張 32.97秒

總結(jié)

方案結(jié)果匯總:

方案 爬取圖片數(shù)量/張 耗時/秒
單線程 571 102.9
多進(jìn)程 map 571 37.88
多進(jìn)程 map_async 571 38.54
多線程 555 32.97
  1. 多線程以 32.97 秒的時間排名第一
  2. 多進(jìn)程中的 map 和 map_async 效率相差不遠(yuǎn) 怎茫,位列第二
  3. 單線程速度最慢收壕,位列第三

此次爬取試驗中,多線程下載圖片相對其他方案來說少了 16 張轨蛤,具體原因還沒有查過蜜宪,影響較小,暫時不做處理祥山。

在網(wǎng)上的討論中圃验,多線程適用于網(wǎng)頁請求以及 I/O 讀寫操作,多進(jìn)程適用于 CPU 密集型操作缝呕,由于作者水平有限澳窑,還沒有對線程、進(jìn)程供常、全局解釋器鎖(GIL)等知識進(jìn)行深入了解摊聋,下一次,有機會在做深入學(xué)習(xí)栈暇。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末麻裁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子源祈,更是在濱河造成了極大的恐慌煎源,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件新博,死亡現(xiàn)場離奇詭異薪夕,居然都是意外死亡,警方通過查閱死者的電腦和手機赫悄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門原献,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人埂淮,你說我怎么就攤上這事姑隅。” “怎么了倔撞?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵讲仰,是天一觀的道長。 經(jīng)常有香客問我痪蝇,道長鄙陡,這世上最難降的妖魔是什么冕房? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮趁矾,結(jié)果婚禮上耙册,老公的妹妹穿的比我還像新娘。我一直安慰自己毫捣,他們只是感情好详拙,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蔓同,像睡著了一般饶辙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上斑粱,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天弃揽,我揣著相機與錄音,去河邊找鬼珊佣。 笑死蹋宦,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的咒锻。 我是一名探鬼主播冷冗,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼惑艇!你這毒婦竟也來了蒿辙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤滨巴,失蹤者是張志新(化名)和其女友劉穎思灌,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恭取,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡泰偿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜈垮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耗跛。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖攒发,靈堂內(nèi)的尸體忽然破棺而出调塌,到底是詐尸還是另有隱情,我是刑警寧澤惠猿,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布羔砾,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏姜凄。R本人自食惡果不足惜政溃,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望檀葛。 院中可真熱鬧玩祟,春花似錦腹缩、人聲如沸屿聋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽润讥。三九已至,卻和暖如春盘寡,著一層夾襖步出監(jiān)牢的瞬間楚殿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工竿痰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脆粥,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓影涉,卻偏偏與公主長得像变隔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蟹倾,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

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