基於python的scrapy爬蟲,關於增量爬取是怎麼處理的?
new to scrapy, 僅提供幾個思路,詳細解決方案,自己解決後後續跟進。
- 如果只是一次性的抓取某個網站的全部內容, 中途需要暫停並且恢復,只需要
scrapy crawl somespider -s JOBDIR=crawls/somespider-1
參考:Jobs: pausing and resuming crawls
- 如果需求是過濾某些url,但是網站的主入口不被過濾掉,比如典型的論壇類網站,你只想過濾掉帖子,但是卻不想過濾掉板塊,你可以定製一下requestSeen
scrapy/dupefilter.py at 0.24 · scrapy/scrapy · GitHub
python - how to filter duplicate requests based on url in scrapy
- 如果使所有網站的動態過濾,比如是不是多了一個新回復,在url上的變化並不能體現出來,搜索引擎採用的是一系列的演算法,判斷某一個頁面的更新時機。個人應用一般不會使用到(其實是自己也不懂,寫出來提供一下思路,也許你會呢)。大部分的網頁在進入下一級頁面的時候都會有一個類似於最後更新時間,最後活動時間等等,可以根據這個來進行判斷。
我當初就是因為無法增量抓取所以放棄 scrapy 的。
因為我們的場景,定時更新,增量抓取是非常重要的,這要求很強 url 去重,調度策略邏輯。
而 scrapy 的內存去重實在是太簡陋了。
我是這麼做的:
1. 資料庫里保存抓取網頁的url欄位,寫一個middleware,抓取一個新頁面的時候先在middleware里判斷一下資料庫里是不是已經存在這個新頁面的url,不存在的才做處理。
2. 保險起見,資料庫里的url欄位設置成unique索引。
通過正則去篩選出URL是否進入item(鏈接是否跟隨),然後通過下載器中間件和pipline控制一下就可以很好的解決了。
完美解決scrapy只採集詳情頁
這個是我當時的解決方案,可你一參考一下
目前似乎沒有官方方案,這裡有一個非官方的patch,可以存儲scrapy的狀態,下次運行時恢復。
原帖在這裡http://stackoverflow.com/questions/7312093/how-can-i-stop-a-scrapy-crawlspider-and-later-resume-where-it-left-off
時間線上出現了,這個已經提了很久的問題。 我不太清楚 scrapy 在問題剛提出來的時候是個什麼情況,但是在 14 年的時候, scrapy 的解決方案已經可以滿足絕大多數需求了。而且現在還有很不錯的文檔可以查 -&> Jobs: pausing and resuming crawls 。
我覺得個人或者小團隊任務的話,基於 scrapy 還是很不錯的,可擴展性很好,比如說這裡有人說對 scrapy 默認的去重方案不滿意,那其實你可以用自己的替換掉 scrapy 默認的 -&> python - how to filter duplicate requests based on url in scrapy 。不算是很難的事情。
當然,開源就是造輪子,對於造輪子我是鼓勵的,只要不讓我造就行了。對於只是讀取某幾個網站更新內容的爬蟲完全沒必要在python代碼中實現增量的功能,直接在item中增加Url欄位。
item["Url"] = response.url
然後在數據端把儲存url的column設置成unique。
之後在python代碼中捕獲資料庫commit時返回的異常,忽略掉或者轉入log中都可以。
我使用的是SqlAlchemy。我是這麼寫的
from sqlalchemy.exc import IntegrityError
class XxxPipeline(object):
def process_item(self, item, spider):
#一些session.add()
#........
try:
session.commit()
print "crawl %s done!" % item["Url"]
except IntegrityError:
print "skip %s ." % item["Url"]
return item
雖然每次crawl都會重複抓取一些數據,但最終結果庫內不會有相同的Url。
對於小規模的爬蟲,這種重複抓取的成本基本可以忽略。
自己寫一個bloom filter的過濾url的中間件不就行了嗎
網上有說支持增量的,我看了代碼+實際測試,還是覺得不是增量的...
我的做法是pipeline的open_spider時讀取所有item裡面的url,做成一個parsed_urls的list,在rule的process_link中過濾掉這些已經下載的url,如果需要的話可以再item裡面加入last_notify屬性進一步擴展...
另外我遇到過一個問題,pipeline處理完一個item後scrapy整個會卡住,你遇到過么?INFO: Crawled 255 pages (at 4 pages/min), scraped 8 items (at 3 items/min)
INFO: Crawled 255 pages (at 0 pages/min), scraped 8 items (at 0 items/min)
INFO: Crawled 255 pages (at 0 pages/min), scraped 8 items (at 0 items/min)
INFO: Crawled 255 pages (at 0 pages/min), scraped 8 items (at 0 items/min)
INFO: Crawled 255 pages (at 0 pages/min), scraped 8 items (at 0 items/min)
INFO: Crawled 255 pages (at 0 pages/min), scraped 8 items (at 0 items/min)
INFO: Crawled 255 pages (at 0 pages/min), scraped 8 items (at 0 items/min)
INFO: Crawled 255 pages (at 0 pages/min), scraped 8 items (at 0 items/min)
INFO: Crawled 255 pages (at 0 pages/min), scraped 8 items (at 0 items/min)
INFO: Crawled 255 pages (at 0 pages/min), scraped 8 items (at 0 items/min)
INFO: Crawled 255 pages (at 0 pages/min), scraped 8 items (at 0 items/min)
.......
除了用
-s JOBDIR=/tmp/progress
外,還可以使用這個 DeltaFetch 插件
GitHub - scrapy-plugins/scrapy-deltafetch: Scrapy spider middleware to ignore requests to pages containing items seen in previous crawls
文檔看 Github 的項目主頁就足夠了
推薦閱讀:
※GitHub 上有什麼值得學習,簡單的,易讀的 Python 項目?
※python開發一個項目要怎麼做?
※Python 閉包代碼理解?
※系統中同時有 python2和 python3,怎麼讓 ipython 選擇不同的版本啟動?
※想用Python做一款處理上市公司財務數據的軟體,應該學習哪幾個部分?