web-dev-qa-db-fra.com

Passer un argument à une fonction de rappel

def parse(self, response):
    for sel in response.xpath('//tbody/tr'):
        item = HeroItem()
        item['hclass'] = response.request.url.split("/")[8].split('-')[-1]
        item['server'] = response.request.url.split('/')[2].split('.')[0]
        item['hardcore'] = len(response.request.url.split("/")[8].split('-')) == 3
        item['seasonal'] = response.request.url.split("/")[6] == 'season'
        item['rank'] = sel.xpath('td[@class="cell-Rank"]/text()').extract()[0].strip()
        item['battle_tag'] = sel.xpath('td[@class="cell-BattleTag"]//a/text()').extract()[1].strip()
        item['grift'] = sel.xpath('td[@class="cell-RiftLevel"]/text()').extract()[0].strip()
        item['time'] = sel.xpath('td[@class="cell-RiftTime"]/text()').extract()[0].strip()
        item['date'] = sel.xpath('td[@class="cell-RiftTime"]/text()').extract()[0].strip()
        url = 'https://' + item['server'] + '.battle.net/' + sel.xpath('td[@class="cell-BattleTag"]//a/@href').extract()[0].strip()

        yield Request(url, callback=self.parse_profile)

def parse_profile(self, response):
    sel = Selector(response)
    item = HeroItem()
    item['weapon'] = sel.xpath('//li[@class="slot-mainHand"]/a[@class="slot-link"]/@href').extract()[0].split('/')[4]
    return item

Eh bien, je racle une table entière dans la méthode d'analyse principale et j'ai pris plusieurs champs de cette table. L'un de ces champs est une URL et je veux l'explorer pour obtenir un tout nouveau tas de champs. Comment puis-je transmettre mon objet ITEM déjà créé à la fonction de rappel pour que le dernier élément conserve tous les champs?

Comme il est indiqué dans le code ci-dessus, je suis en mesure d'enregistrer les champs à l'intérieur de l'URL (code pour le moment) ou uniquement ceux du tableau (écrivez simplement yield item) mais je ne peux pas produire un seul objet avec tous les champs ensemble.

J'ai essayé cela, mais évidemment, cela ne fonctionne pas.

yield Request(url, callback=self.parse_profile(item))

def parse_profile(self, response, item):
    sel = Selector(response)
    item['weapon'] = sel.xpath('//li[@class="slot-mainHand"]/a[@class="slot-link"]/@href').extract()[0].split('/')[4]
    return item
19
vic

C'est pour cela que vous utiliseriez le mot clé meta.

def parse(self, response):
    for sel in response.xpath('//tbody/tr'):
        item = HeroItem()
        # Item assignment here
        url = 'https://' + item['server'] + '.battle.net/' + sel.xpath('td[@class="cell-BattleTag"]//a/@href').extract()[0].strip()

        yield Request(url, callback=self.parse_profile, meta={'hero_item': item})

def parse_profile(self, response):
    item = response.meta.get('hero_item')
    item['weapon'] = response.xpath('//li[@class="slot-mainHand"]/a[@class="slot-link"]/@href').extract()[0].split('/')[4]
    yield item

Notez également que faire sel = Selector(response) est un gaspillage de ressources et diffère de ce que vous avez fait plus tôt, donc je l'ai changé. Il est automatiquement mappé dans le response en tant que response.selector, Qui a également le raccourci pratique de response.xpath.

33
Rejected

Voici une meilleure façon de passer des arguments à la fonction de rappel:

def parse(self, response):
    request = scrapy.Request('http://www.example.com/index.html',
                             callback=self.parse_page2,
                             cb_kwargs=dict(main_url=response.url))
    request.cb_kwargs['foo'] = 'bar'  # add more arguments for the callback
    yield request

def parse_page2(self, response, main_url, foo):
    yield dict(
        main_url=main_url,
        other_url=response.url,
        foo=foo,
    )

source: https://docs.scrapy.org/en/latest/topics/request-response.html#topics-request-response-ref-request-callback-arguments

2
penduDev

J'ai eu un problème similaire avec le passage d'arguments supplémentaires de Tkinter et j'ai trouvé que cette solution fonctionnait (ici: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/extra-args.html ), converti en votre problème:

def parse(self, response):
    item = HeroItem()
    [...]
    def handler(self = self, response = response, item = item):
        """ passing as default argument values """
        return self.parse_profile(response, item)
    yield Request(url, callback=handler)
0
rolika