Как установить исключения внутри «yield» для Scrapy? - PullRequest
0 голосов
/ 28 августа 2018

Добрый день,

Я пытаюсь очистить GitHub с помощью Scrapy. Он работает по большей части, но некоторые страницы загружают «участников» после завершения загрузки самой страницы. Когда 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(), - это та часть, которая доставляет мне неприятности и где я хочу исключения.

P.S. Я также пытался заставить его ждать страницы, используя "scrapy-splash"

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

но проблема не исчезла, поэтому я хотел бы, по крайней мере, получить все данные, которые я могу, и заполнить число участников, использующих API.

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Вместо:

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

Вы можете использовать параметр default (чтобы он не возвращал None):

yield {
    'contributors': response.xpath(selector)\
                            .extract_first(default='')\
                            .strip(),
}
0 голосов
/ 28 августа 2018

Вы можете реализовать это так:

>>> 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
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...