【问题标题】:How to set exceptions inside "yield" for Scrapy?如何在 Scrapy 的“yield”中设置异常?
【发布时间】:2019-02-03 04:57:42
【问题描述】:

早安,

我正在尝试使用 Scrapy 抓取 GitHub。它在大多数情况下都有效,但有些页面在页面本身完成加载后会加载“贡献者”。 当 Scrapy 遇到这样的页面时,它会抛出以下错误: AttributeError: 'NoneType' object has no attribute 'strip' 并丢弃该 URL 中的所有其他内容。

有没有办法在“yield”中产生异常,以便 Scrapy 将“None”放入生成的 .CSV 而不是丢弃所有数据?

以下是相关代码:

rules = [
    Rule(LinkExtractor(allow=('Repositories'), restrict_xpaths=('//a[@rel="next"]'))),
    Rule(LinkExtractor(allow=('github'), restrict_xpaths=('//h3/a[@class="v-align-middle"]')), callback='parse_project'),
    Rule(LinkExtractor(allow=('commits/master'), restrict_xpaths=('//*[@class="commits"]/a')), follow=True, callback='parse_commits_page'),
    Rule(LinkExtractor(deny=('\+174'), restrict_xpaths=('//a[contains(text(), "Older")]')), follow=True, callback='parse_commits_page')
]

# Parse the main page of the project
def parse_project(self, response):
    yield {
        'author': response.xpath('//a[@rel="author"]/text()').extract(),
        'name': response.xpath('//strong[@itemprop="name"]/a/text()').extract(),
        'tags': [x.strip() for x in response.xpath('//a[contains(@class, "topic-tag")]/text()').extract()],
        'about': response.xpath('//*[@itemprop="about"]/text()').extract_first().strip(),
        'lang_name': response.xpath('//span[@class = "lang"]/text()').extract(),
        'lang_perc' : response.xpath('//span[@class = "percent"]/text()').extract(),
        'stars': response.xpath('//a[contains(@aria-label, "starred")]/text()').extract_first().strip(),
        'forks': response.xpath('//a[contains(@aria-label, "forked")]/text()').extract_first().strip(),
        'commits': response.xpath('//a[contains(., "commits")]/span/text()').extract_first().strip(),
        'contributors': response.xpath('//a[contains(., "contributor")]/span/text()').extract_first().strip(),
        'last_commits': None
    }

特别是,'contributors': response.xpath('//a[contains(., "contributor")]/span/text()').extract_first().strip(), 是给我带来麻烦的部分,也是我想要例外的地方。

附:我还尝试使用“scrapy-splash”让它等待页面

def pre_parse_project(self, response):
    yield scrapy_splash.SplashRequest(response.url, self.parse_project,
        args={
            'wait': 4,
        }
    )

但问题仍然存在,因此我想至少获取所有我能获取的数据并使用 API 填充贡献者的数量。

【问题讨论】:

    标签: javascript python html web-scraping scrapy


    【解决方案1】:

    代替:

    yield {
        'contributors': response.xpath(selector)\
                                .extract_first()\
                                .strip(),
    }
    

    你可以使用default参数(这样它就不会返回None):

    yield {
        'contributors': response.xpath(selector)\
                                .extract_first(default='')\
                                .strip(),
    }
    

    【讨论】:

    • 谢谢!这样看起来更优雅。
    【解决方案2】:

    你可以这样实现它:

    >>> test = None
    >>> test.strip() if test is not None else "fallback"
    'fallback'
    

    在您的代码中,这看起来像:

    def parse_project(self, response):
        yield {
            'author': response.xpath('//a[@rel="author"]/text()').extract(),
            'name': response.xpath('//strong[@itemprop="name"]/a/text()').extract(),
            'tags': [x.strip() for x in response.xpath('//a[contains(@class, "topic-tag")]/text()').extract()],
            'about': response.xpath('//*[@itemprop="about"]/text()').extract_first().strip(),
            'lang_name': response.xpath('//span[@class = "lang"]/text()').extract(),
            'lang_perc' : response.xpath('//span[@class = "percent"]/text()').extract(),
            'stars': response.xpath('//a[contains(@aria-label, "starred")]/text()').extract_first().strip(),
            'forks': response.xpath('//a[contains(@aria-label, "forked")]/text()').extract_first().strip(),
            'commits': response.xpath('//a[contains(., "commits")]/span/text()').extract_first().strip(),
            'contributors': response.xpath('//a[contains(., "contributor")]/span/text()').extract_first().strip() if response.xpath('//a[contains(., "contributor")]/span/text()').extract_first() is not None else None,
            'last_commits': None
        }
    

    【讨论】:

    • 请您再确认一下好吗?我可能走运了。当我检查没有“关于”部分的this page 时,我仍然收到建议方法的错误:>>> response.xpath('//*[@itemprop="about"]/text()').extract_first().strip() if response.xpath('//*[@itemprop="about"]/text()').extract_first().strip() is not None else None Traceback (most recent call last): ` File "", line 1, in ` AttributeError: 'NoneType' object has no attribute 'strip' 跨度>
    • 我的错,对不起。应该没有.strip()
    猜你喜欢
    • 2013-05-04
    • 2016-09-07
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多