如何提取数据并将其附加到 scrapy 中的当前对象?

How can I extract data and append it to current object in scrapy?

所以我的问题是: 我有一个包含产品列表的网页。 每个产品在每个 div 的属性中定义了很多东西。 但是,其中一个字段不明确,所以我决定打开产品页面并从那里获取它,在那里我还找到了一些我认为可能对我的分析有用的其他数据。 但是,当我合并数据时,有些列是相同的,而另一些似乎已更新。

代码如下:

import scrapy
from scrapy.utils.response import open_in_browser

class getSalesData(scrapy.Spider):
    name = 'getsalesdata'

    start_urls = ['https://link']

    def __init__(self):
        self.params = ['data-id-cod', 'id', 'data-name','data-area' ,'data-zone' ,'data-items','data-ssellertype' ,
                       'data-surface' ,'price' ,'tva' ,'mobile-container-url']

        self.item = { "id_cod"              : 'null',
                      "id"                  : 'null',
                      "tip_prop"            : 'null',
                      "area"                : 'null',
                      "zone"                : 'null',
                      "no_items"            : 'null',
                      "seller_type"         : 'null',
                      "surface"             : 'null',
                      "surface_orig"        : 'null',
                      "price"               : 'null',
                      "currency"            : 'null',
                      "url"                 : 'null'
        }

        self.columns = { "data-id-cod"          : 'id_cod',
                         "id"                   : 'id',
                         "data-name"            : 'tip_prop',
                         "data-area"            : 'area',
                         "data-zone"            : 'zone',
                         "data-items"           : 'nr_items',
                         "data-ssellertype"     : 'seller_type',
                         "data-surface"         : 'surface',
                         "price"                : 'price',
                         "tva"                  : 'valuta',
                         "mobile-container-url" : 'url'
        }

    def parse(self, response):
        item = self.item
        for listing in response.css("div.box-an"):
            if not 'box-an ' in listing.attrib['class']:
                for parameter in self.params:
                    if parameter in ['price', 'tva']:
                        item[self.columns[parameter]] = \
                            (listing.css('span.' + parameter + '::text').get()).replace('.','') \
                                if (parameter in listing.get()) else item[self.columns[parameter]]

                    elif parameter in 'mobile-container-url':
                        url = listing.css('a.visible-xs.' + parameter).attrib['href'] \
                                if (parameter in listing.get()) else item[self.columns[parameter]]

                        #self.logger.info('----->>> At URL : ' + url)

                        item[self.columns[parameter]] = url

                    elif parameter in 'data-surface':
                        item['surface'] = str(int(listing.attrib[parameter])/100) \
                            if (int(listing.attrib[parameter])>1000) else listing.attrib[parameter]
                        item['surface_orig'] = listing.attrib[parameter] \
                            if (parameter in listing.get()) else item[self.columns[parameter]]

                    else:
                        item[self.columns[parameter]] = \
                            listing.attrib[parameter] if (parameter in listing.get()) else item[self.columns[parameter]]

            request = scrapy.Request(url=item['url'],
                                     callback=self.parseNextPage,
                                     meta={'item' : item})

            yield request

    def parseNextPage(self, response):
        item = response.meta['item']

        self.logger.info('Running on : ' + item['url'])

        #for spec in response.css('li.list-group-item.specificatii-oferta__lista--item'):
        for spec in response.css('ul.list-tab'):
            for lst in spec.css('li'):
                field = lst.css('li::text').get()
                #self.logger.info('Adding ' + field + '\n')
                item[field] = lst.css('span::text').get()

        return item

这是数据(请参阅相同的加星标项):

id_cod          id          tip_prop    no_items surface    surface_all
*A2Q00LMBUS9    *XA2Q0001E  *prodType1  2        41,21 mp   *46.89 mp
*A2Q00LMBUS9    *XA2Q0001E  *prodType1  3        140 mp     *46.89 mp

我感觉我不明白 self.item 是如何更新的,一些数据是从以前的 运行 中保留下来的,也许吧?

更新: 这很奇怪。 如果我使用此代码:

    request = scrapy.Request(url=item['url'],
                             callback=self.parseNextPage,
                             meta={'item' : {'id'     : item['id'] ,
                                             'id_cod' : item['id_cod'],
                                             'area'  : item['area'],
                                             'nr_items' : item['nr_items'],
                                             'seller_type'      : item['seller_type'],
                                             'surface' : item['suprafata'],
                                             'tip_prop' : item['tip_prop'],
                                             'url'             : item['url'],
                                             'currency'          : item['valuta'],
                                             'area'            : item['zona']
                                             }
                                   }
                             )

它工作正常。但是如果我使用这段代码:

request = scrapy.Request(url=item['url'],
                         callback=self.parseNextPage,
                         meta={'item' : item})

它不再起作用了。 Item 和我上面传递的字典是一样的。

因为 item 作为引用传递给 Request 的元数据,并且它所引用的内存在所有产品之间重复使用,所以一直被覆盖。

要修复在构造函数中删除声明 self.item 并在循环中简单地创建新项目:

...    
def init_item(self):
    return { "id_cod"              : 'null',
             "id"                  : 'null',
             "tip_prop"            : 'null',
             "area"                : 'null',
             "zone"                : 'null',
             "no_items"            : 'null',
             "seller_type"         : 'null',
             "surface"             : 'null',
             "surface_orig"        : 'null',
             "price"               : 'null',
             "currency"            : 'null',
             "url"                 : 'null'
    }

def parse(self, response):
    for listing in response.css("div.box-an"):
        item = self.init_item()
        if not 'box-an ' in listing.attrib['class']:
...