2017-02-20 257 views
0

我認爲我的問題是由一些對某些scrapy概念的誤解造成的。所以我會很感激,如果有人能夠向我解釋這一點。ItemLoader爲什麼從一個元素創建一個列表

讓我們想象一下,我有以下蜘蛛:

# -*- coding: utf-8 -*- 
import scrapy 
from scrapy.loader import ItemLoader 
from reddit.items import RedditItem 
from scrapy.loader.processors import TakeFirst 


class RedditspiderSpider(scrapy.Spider): 
    name = "redditspider" 
    allowed_domains = ["wwww.reddit.com"] 
    start_urls = [ 
     'https://www.reddit.com/r/starcraft/comments/5t8v7i/community_feedback_update_widow_mines_carriers/?st=iz7ba37h&sh=b7e9bd35'] 

    def parse(self, response): 
     l = ItemLoader(item=RedditItem(), response=response) 

     comments = response.xpath(
      '//div[contains(@class,"usertext-body may-blank-within md-container ")]/div') 
     comments = comments[1:] 
     for comment_it in comments: 
      comment = comment_it.extract() 
      l.add_value('comment', comment) 
      yield l.load_item() 

RedditItem通過以下方式定義:

from scrapy.item import Item, Field 
from w3lib.html import remove_tags 
from scrapy.loader.processors import TakeFirst 


def _remove_tags(input): 
    return input 


class RedditItem(Item): 
    comment = Field(input_processor=_remove_tags, output_processor=TakeFirst()) 

所以一切都很簡單明瞭。現在,我的問題。在第一個代碼示例l加載程序有一個字段comments。據我所知,當我做l.add_value('comment', comment),這個字段的輸入處理器被觸發。 這是正確的嗎?

據我所知,這是正確的。在l.add_value('comment', comment)comment是一個字符串,而不是一個列表。但是,當我在_remove_tags中設置斷點時,我發現input實際上是長度爲1的列表。所以我的主要問題是爲什麼會發生?爲什麼我傳遞一個字符串並在那裏看到一個列表?

我看着scrapy源代碼,發現這是_add_value(線90):value = arg_to_iter(value)。這讓事情變得非常清楚,這似乎是我看到長度爲1的列表的原因。

這條線背後的設計推理是什麼?這是因爲在scrapy我可以從不同的xpath/css請求填充項目中的相同字段?如果是這樣,那對我來說很有意義。那麼問題是:我該如何解決這個問題?我只是在輸入處理器中應用map(_remove_tags, input)?這會是一個推薦的解決方案嗎?或者我錯了?

感謝

+0

你確定'comment = comment_it.extract()'是一個字符串嗎? – eLRuLL

+0

@eLRuLL是的。在add_value類型(註釋)---> Out [2]:unicode附近設置一個斷點。似乎是Unicode字符串 –

回答

1

是,scrapy裝載機設計用於處理在同一領域,你可以測試多次插入:現在

from scrapy.loader.processors import Identity 

class RedditItem(Item): 
    comment = Field(input_processor=Identity(), output_processor=Identity()) 

l = ItemLoader(item=RedditItem(), response=response) 
l.add_value('comment', 'first comment') 
l.add_value('comment', 'second comment') 

print l.output_value('comment') # ['first comment', 'second comment'] 

,正因爲如此,你可以檢查here什麼推薦的處理器用於scrapy程序員使用的輸入和輸出(在default_output_processordefault_input_processor之內)。

正如你所看到的,他們有一個稱爲MapCompose的處理器,它接收當前值的每個條目並應用每個定義爲參數的方法。

+0

因此,一個很好的解決方法是在input_processor中執行map(_remove_tags,input),然後使用TakeFirst作爲輸出處理器?我正確地得到這個嗎? –

+0

'MapCompose(_remove_tags)' – eLRuLL

+0

@sof_dff是的,你可以看到一個[示例](https://doc.scrapy.org/en/latest/topics/loaders.html?highlight=remove_tags#declaring-input-and-輸出處理器),只是在文檔中做到這一點,但請注意下劃線。 – guival

相關問題