在填充item時, 有時會先在一個parser取得部分數據, 然后在另一個parser里再取得另一部分數據. 這就涉及到了在兩個parser間傳遞參數的問題.
可以先在第一個parser里取得數據, 然后把數據做為參數傳遞給第二個parser,在第二個parse里實例化Item.然后把所有數據都寫入這個item實例.
也可以在第一個parser里實例化Item,然后填充這個item實例. 再把item實例作為參數傳遞給第二個parser. 這里主要是把item做為參數傳遞.
由於在調用第二個parser時,往往都是通過回調函數來使用的,這就涉及到了給回調函數傳參的問題.
有兩種方法,:
第一種是通用方法,用匿名函數,所有回調函數都可以用這種方法進行方法傳遞參數.
第二種是scrapy.Request的方法,利用這個方法本身自帶的meta變量進行傳參
第一種方法代碼如下:
def parse(self, response):
# 確定章節在文章中的位
for i in response.xpath('//*[@id="list"]//dd/a/@href').extract()[13:]:
item = TianfushuItem()
# 取章節網頁.html前的四位數字做章節標識名,作為今后排序的依據.
item['name'] = int(i[-9:-5])
# 直接把item作為參數傳遞給下一個解析器
yield scrapy.Request(self.url + i, callback=lambda rsp, it=item: self.parse_item(response=rsp, item=it))
def parse_item(self, response, item):
item['content'] = '\t\t\t\t\t'*2 + response.xpath('//div[@class="bookname"]/h1/text()').extract()[0] + '\n\n\n'+ '\n\n\n'.join([' ' + i.strip() for i in response.xpath('//div[@id="content"]/text()').extract()
if i.strip()]) + '\n\n'
yield item
這種方法,把本來的回調函數用lambda函數裝起來, lambda函數接收2個值, 其中一個默認為item(必須在建立lambda函數的時候就把值傳給它,不然今后的值會變,for循環后的item已經不是當前的item了,實測),由於有了默認值,Request的返回的response對象會自動去填充lambda函數的另一個參數rsp.這樣, 被裝在里邊的函數就得到response對象和item.
第二種方法代碼示例如下:
def parse(self, response):
# 確定章節在文章中的位置,並寫入item
for i in response.xpath('//*[@id="list"]//dd/a/@href').extract()[13:]:
item = TianfushuItem()
# 取章節網頁.html前的四位數字做章節標識名,作為今后排序的依據.
item['name'] = int(i[-9:-5])
yield scrapy.Request(self.url + i, callback=self.parse_item, meta=({'item': item}))
def parse_item(self, response):
item = response.meta['item']
item['content'] = '\t\t\t\t\t'*2 + response.xpath('//div[@class="bookname"]/h1/text()').extract()[0] + '\n\n\n'+ '\n\n\n'.join([' ' + i.strip() for i in response.xpath('//div[@id="content"]/text()').extract()
if i.strip()]) + '\n\n'
yield item
通過meta參數做為橋梁.就把第一個parser實例化並作出部分填充的的item做為實參傳遞給了第二個parser