【问题标题】:Return first encountered result in scrapy在scrapy中返回第一个遇到的结果
【发布时间】:2017-01-30 14:53:22
【问题描述】:

问题陈述:

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

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

在循环中假设有 2 个 URL:example.com/contactexample.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

我只想要第一个。

【问题讨论】:

    标签: python python-3.x web-scraping scrapy web-crawler


    【解决方案1】:

    由于 Scrapy 的异步特性,您甚至无法确定响应是否会以与发出它们相同的顺序到达回调。你可以做的是获取 urls 列表,用meta 传递它,然后像这样依次访问 urls:

    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
    

    【讨论】:

    • 你的方法很有魅力!谢谢,@mizhgun!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-02
    • 1970-01-01
    相关资源
    最近更新 更多