有些情況下,例如爬取大的站點(diǎn),我們希望能暫停爬取,之后再恢復(fù)運(yùn)行。
Scrapy 通過(guò)如下工具支持這個(gè)功能:
要啟用持久化支持,你只需要通過(guò) JOBDIR 設(shè)置 job directory 選項(xiàng)。這個(gè)路徑將會(huì)存儲(chǔ) 所有的請(qǐng)求數(shù)據(jù)來(lái)保持一個(gè)單獨(dú)任務(wù)的狀態(tài)(例如:一次 spider 爬取(a spider run))。必須要注意的是,這個(gè)目錄不允許被不同的 spider 共享,甚至是同一個(gè) spider 的不同 jobs/runs 也不行。也就是說(shuō),這個(gè)目錄就是存儲(chǔ)一個(gè) 單獨(dú) job 的狀態(tài)信息。
要啟用一個(gè)爬蟲(chóng)的持久化,運(yùn)行以下命令:
scrapy crawl somespider -s JOBDIR=crawls/somespider-1
然后,你就能在任何時(shí)候安全地停止爬蟲(chóng)(按 Ctrl-C 或者發(fā)送一個(gè)信號(hào))。恢復(fù)這個(gè)爬蟲(chóng)也是同樣的命令:
scrapy crawl somespider -s JOBDIR=crawls/somespider-1
有的時(shí)候,你希望持續(xù)保持一些運(yùn)行長(zhǎng)時(shí)間的蜘蛛的狀態(tài)。這時(shí)您可以使用 spider.state 屬性,該屬性的類型必須是 dict。scrapy 提供了內(nèi)置擴(kuò)展負(fù)責(zé)在 spider 啟動(dòng)或結(jié)束時(shí),從工作路徑(job directory)中序列化、存儲(chǔ)、加載屬性。
下面這個(gè)例子展示了使用 spider state 的回調(diào)函數(shù)(callback)(簡(jiǎn)潔起見(jiàn),省略了其他的代碼):
def parse_item(self, response):
# parse item here
self.state['items_count'] = self.state.get('items_count', 0) + 1
如果你想要使用 Scrapy 的持久化支持,還有一些東西您需要了解:
Cookies 是有有效期的(可能過(guò)期)。所以如果你沒(méi)有把你的爬蟲(chóng)及時(shí)恢復(fù),那么他可能在被調(diào)度回去的時(shí)候 就不能工作了。當(dāng)然如果你的爬蟲(chóng)不依賴 cookies 就不會(huì)有這個(gè)問(wèn)題了。
請(qǐng)求是由 pickle 進(jìn)行序列化的,所以你需要確保你的請(qǐng)求是可被 pickle 序列化的。 這里最常見(jiàn)的問(wèn)題是在在 request 回調(diào)函數(shù)中使用 lambda 方法,導(dǎo)致無(wú)法序列化。
例如,這樣就會(huì)有問(wèn)題:
def some_callback(self, response):
somearg = 'test'
return scrapy.Request('http://www.example.com', callback=lambda r: self.other_callback(r, somearg))
def other_callback(self, response, somearg):
print "the argument passed is:", somearg
這樣才對(duì):
def some_callback(self, response):
somearg = 'test'
return scrapy.Request('http://www.example.com', meta={'somearg': somearg})
#這里的實(shí)例代碼有錯(cuò),應(yīng)該是(譯者注)
# return scrapy.Request('http://www.example.com', meta={'somearg': somearg}, callback=self.other_callback)
def other_callback(self, response):
somearg = response.meta['somearg']
print "the argument passed is:", somearg