代码之家  ›  专栏  ›  技术社区  ›  Mohsin ForRealHomie

Return:第一次遇到的结果为scrapy

  •  2
  • Mohsin ForRealHomie  · 技术社区  · 8 年前

    问题陈述:

    解析之后,我将每个URL发送到parse_links以从中提取电子邮件地址。

    解析后,如果我从该链接中找到电子邮件地址并返回结果,我希望停止迭代。

    在循环中,假设有2个URL: example.com/contact example.com/about

    如果从中找到电子邮件地址: example.com/contact 那幺我不想放弃第二个。但我从所有链接中得到了电子邮件地址。

    这是我的密码:

    def parse(self, response):
        urls = [
            instance.url for instance in LinkExtractor(
                allow_domains='example.com'
            ).extract_links(response)
        ]
    
        for url in sorted(urls, reverse=True):
            request = Request(url, callback=self.parse_links)
            yield request
    
    def parse_links(self, response):
        item = EmailScraperItem()
        mailrex = '[\w\.-]+@[\w\.-]+'
        result = response.xpath('//a[@href]').re('%s' % mailrex)
        if result:
            item['emails'] = result  # here how can I send first value and ignore other results
        return item
    

    运行爬虫后,我得到以下输出:

    2017-01-30 20:31:27 [scrapy.core.scraper] DEBUG: Scraped from <200 http://example.com/contact/>
    {'emails': ['abc@example.com']}  # first result
    
    2017-01-30 20:31:29 [scrapy.core.scraper] DEBUG: Scraped from <200 http://example.com/about/>
    {'emails': ['xyz@example.com']}  # second result
    

    我只想要第一个。

    1 回复  |  直到 5 年前
        1
  •  1
  •   mizhgun    8 年前

    由于Scrapy的异步特性,您甚至不能确定响应将以与发出响应相同的顺序到达回调。您可以做的是获取URL列表,并将其传递给 meta ,并按如下顺序访问URL:

    def parse(self, response):
        urls = [
            instance.url for instance in LinkExtractor(
                allow_domains='example.com'
            ).extract_links(response)
        ]
    
        try:
           # take url and pass remaining to the callback
           return Request(urls.pop(), callback=self.parse_links, meta={'urls': urls})
        except IndexError:
           pass
    
    def parse_links(self, response):
        item = EmailScraperItem()
        mailrex = '[\w\.-]+@[\w\.-]+'
        result = response.xpath('//a[@href]').re('%s' % mailrex)
        if result:
            item['emails'] = result  # here how can I send first value and ignore other results
            return item
        # if no emails found, request next url from list
        try:
           urls = response.meta['urls']
           return Request(urls.pop(), callback=self.parse_links, meta={'urls': urls})
        except IndexError:
           pass