這一篇垒拢,沒有項(xiàng)目旬迹,沒有教程。只不過是想記錄下最近對于分布式爬蟲的思考求类。半年前我去一家公司面試的時(shí)候奔垦,面試官問我什么是分布式爬蟲,我只能回呵呵噠仑嗅。在后來工作中漸漸地對這東西有了初步認(rèn)識。爬蟲無非兩樣?xùn)|西
- 網(wǎng)站的破解
- 爬取的效率
由于我很懶,爬蟲就隨便寫寫懟上服務(wù)器上跑就行了仓技,從來不考慮效率的問題鸵贬,所以用到分布式的情況很少。不過也有用到的時(shí)候脖捻,之前爬個(gè)youtube阔逼,除了爬取視頻信息又要下載視頻又要上傳視頻,還要下載縮略圖上傳縮略圖地沮。如果只用一個(gè)爬蟲去做的話嗜浮,其實(shí)也沒什么,就是會失業(yè)而已摩疑。然后我就開始嘗試去做分布式危融。我從網(wǎng)上看到的大部分分布式教程,都是用redis來儲存任務(wù)隊(duì)列雷袋,然后開啟幾個(gè)slave爬蟲來提高爬取速度吉殃。不過我當(dāng)時(shí)懶,懶得學(xué)redis楷怒,就直接用mongodb來存取任務(wù)隊(duì)列蛋勺。
master
爬蟲在網(wǎng)站的列表頁中爬取任務(wù)url去重后寫入mongo,然后開啟各個(gè)slave
爬蟲從mongo中領(lǐng)取任務(wù)鸠删,完成任務(wù)的就打上標(biāo)簽抱完。這是我的做法,用mongo的讀取速度應(yīng)該比不上用儲存在內(nèi)存的redis刃泡。但由于我的slave
爬蟲不僅要完成爬取任務(wù)還要進(jìn)行下載上傳多種操作巧娱,mongo比redis更適合。
不過看到網(wǎng)上把redis傳得神乎其神捅僵,我自然也得去了解家卖,不經(jīng)意間就看到了scrapy-redis這個(gè)包https://scrapy-redis.readthedocs.io/en/stable/
可是它的文檔內(nèi)容很少,可以了解的內(nèi)容不多庙楚,只能通過閱讀源碼去了解上荡。我一開始心想,為什么要有這個(gè)包馒闷?因?yàn)槲铱梢宰约涸谖业膕crapy項(xiàng)目里用redis來寫分布式爬蟲啊酪捡。無非就是一個(gè)爬蟲爬任務(wù)url,其他的爬蟲領(lǐng)任務(wù)來爬字段纳账。然后把scrapy-redis的示例跑起來我發(fā)現(xiàn)了不一樣的東西逛薇。使用這個(gè)包的爬蟲如果沒有獲得任務(wù)隊(duì)列,是可以掛起的疏虫,直到從redis中重新獲得任務(wù)隊(duì)列才會再跑起來永罚。如果是我自己寫的話啤呼,那我做不到讓爬蟲掛起等待任務(wù)隊(duì)列。
無意中我也看到了個(gè)celery的分布式爬蟲呢袱。celery這個(gè)我之前用過官扣,是完成異步任務(wù)的。之前在項(xiàng)目中是用在發(fā)郵件這個(gè)部分羞福。我看到網(wǎng)上的一篇文章的分布式爬蟲惕蹄,只看源碼我總覺得差了點(diǎn)什么。
代碼來源:http://p0sec.net/index.php/archives/58/
# !/usr/bin/python
# -*- coding: utf-8 -*-
from spider import getPageUrl
from spider import getUrl
from spider import getImg
import requests
import threading
x = 0
#run函數(shù)
def Run():
pageurls = getPageUrl.delay().get()#這個(gè)是celerytask
for i in range(1,len(pageurls)):
html = requests.get(pageurls[i]).text
urllist = getUrl.delay(html).get()#這個(gè)也是celerytask
for url in urllist:
url = 'http://umei.cc'+url
print url
ImgHtml = requests.get(url).text
imglist = getImg.delay(ImgHtml).get()#這個(gè)也是celerytask
for imgurl in imglist:
print imgurl
urllib.urlretrieve(imgurl,'/test/%s.jpg' % x)
global x
x += 1
if __name__ == '__main__':
Run()
我在上面標(biāo)注的三個(gè)celery task治专。一般的操作都是 task.delay()卖陵,直接異步完成任務(wù),不返回結(jié)果张峰±崮瑁可是這個(gè)爬蟲有個(gè)返回結(jié)果的操作get()。這我就看不懂了挟炬,這等待結(jié)果返回才開始下一步鸥滨,不成了堵塞么?
繼續(xù)拿我的Youtube爬蟲來探討谤祖,按我的理解婿滓,celery的任務(wù)都是異步完成的。也就是說粥喜,我的視頻爬取凸主,下載上傳全部異步完成。我只要寫個(gè)爬蟲爬取任務(wù)隊(duì)列额湘,然后建立寫異步task(下載視頻卿吐,上傳視頻,下載圖片锋华,上傳圖片)嗡官,畫個(gè)圖吧
通過task.delay()這個(gè)操作讓任務(wù)自己在后臺執(zhí)行并完成,完美毯焕!原來celery分布式爬蟲是這樣使用衍腥!
現(xiàn)在思路清晰了,也知道怎么做了纳猫。但素婆咸!我不想寫代碼去驗(yàn)證思路和效率!