Невозможно остановить мой скрипт, когда некоторые URL очищены - PullRequest
4 голосов
/ 22 апреля 2019

Я создал скрипт в scrapy для анализа названий различных сайтов, перечисленных в start_urls.Сценарий делает свою работу без нареканий.

Теперь я хочу, чтобы мой сценарий остановился после того, как два URL-адреса были проанализированы независимо от того, сколько там URL-адресов.

Я пробовал до сих пор:

import scrapy
from scrapy.crawler import CrawlerProcess

class TitleSpider(scrapy.Spider):
    name = "title_bot"
    start_urls = ["https://www.google.com/","https://www.yahoo.com/","https://www.bing.com/"]

    def parse(self, response):
        yield {'title':response.css('title::text').get()}

if __name__ == "__main__":
    c = CrawlerProcess({
        'USER_AGENT': 'Mozilla/5.0', 
    })
    c.crawl(TitleSpider)
    c.start()

Как сделать так, чтобы мой сценарий был остановлен, когда два из перечисленных URL-адресов очищены?

Ответы [ 4 ]

1 голос
/ 27 апреля 2019

В настоящее время я вижу единственный способ немедленно остановить этот скрипт - использование os._exit функции принудительного выхода:

import os
import scrapy
from scrapy.crawler import CrawlerProcess

class TitleSpider(scrapy.Spider):
    name = "title_bot"
    start_urls = ["https://www.google.com/","https://www.yahoo.com/","https://www.bing.com/"]
    item_counter =0

    def parse(self, response):
        yield {'title':response.css('title::text').get()}
        self.item_counter+=1
        print(self.item_counter)
        if self.item_counter >=2:
            self.crawler.stats.close_spider(self,"2 items")
            os._exit(0)

if __name__ == "__main__":
    c = CrawlerProcess({'USER_AGENT': 'Mozilla/5.0' })
    c.crawl(TitleSpider)
    c.start()

Еще кое-что, что я пробовал.
Но я не получил требуемого результата (немедленно остановите сценарий с 2 ​​очищенными элементами с 3 URL в start_urls):

  1. Перевод CrawlerProcess экземпляра в настройки паука и вызов CrawlerProcess.stop, (reactor.stop) и т. Д. И другие методы из parse метод.
  2. Использование CloseSpider расширение документы источник ) со следующим CrawlerProcess определением:

    c = CrawlerProcess({
        'USER_AGENT': 'Mozilla/5.0',
        'EXTENSIONS' : {
    
    'scrapy.extensions.closespider.CloseSpider': 500,
                        },
    "CLOSESPIDER_ITEMCOUNT":2 })
    
  3. Уменьшение значения CONCURRENT_REQUESTS до 1raise CloseSpider условие в parse методе).
    Когда приложение соскребает 2 элемента и оно достигает строки кода с raise ClosesSpider - третий запрос уже началось в другой теме.
    В случае использования обычного способа остановки spider, приложение будет активно, пока не обработает ранее отправленную запросы и обрабатывают их ответы и только после этого - это закрывается.

Поскольку у вашего приложения относительно небольшое количество URL в start_urls, приложение начинает обрабатывать все URL задолго до того, как оно достигнет raise CloseSpider.

1 голос
/ 25 апреля 2019

Как предложил Gallaecio, вы можете добавить счетчик, но разница здесь в том, что вы экспортируете элемент после оператора if.Таким образом, почти всегда будет экспортировать 2 элемента.

import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.exceptions import CloseSpider


class TitleSpider(scrapy.Spider):
    name = "title_bot"
    start_urls = ["https://www.google.com/", "https://www.yahoo.com/", "https://www.bing.com/"]
    item_limit = 2

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.counter = 0

    def parse(self, response):
        self.counter += 1
        if self.counter > self.item_limit:
            raise CloseSpider

        yield {'title': response.css('title::text').get()}

Почему почти всегда? , спросите вы.Это связано с расой в методе parse.

Представьте, что self.counter в настоящее время равно 1, что означает, что ожидается экспорт еще одного элемента.Но теперь Scrapy получает два ответа одновременно и вызывает метод parse для них обоих.Если два потока, выполняющие метод parse, будут увеличивать счетчик одновременно, они оба будут иметь self.counter, равный 3, и, таким образом, оба вызовут исключение CloseSpider.

В этом случае (что маловероятно, но все же может произойти), паук экспортирует только один элемент.

0 голосов
/ 25 апреля 2019

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

for cnt, url in enumerate(start_urls):
    if cnt > 1:
        break
    else:
        parse(url)
0 голосов
/ 22 апреля 2019

Строя поверх https://stackoverflow.com/a/38331733/939364,, вы можете определить счетчик в конструкторе вашего паука и использовать parse, чтобы увеличить его и поднять CloseSpider, когда он достигнет 2:

import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.exceptions import CloseSpider  # 1. Import CloseSpider

class TitleSpider(scrapy.Spider):
    name = "title_bot"
    start_urls = ["https://www.google.com/","https://www.yahoo.com/","https://www.bing.com/"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.counter = 0  # 2. Define a self.counter property

    def parse(self, response):
        yield {'title':response.css('title::text').get()}
        self.counter += 1  # 3. Increase the count on each parsed URL
        if self.counter >= 2:
            raise CloseSpider  # 4. Raise CloseSpider after 2 URLs are parsed

if __name__ == "__main__":
    c = CrawlerProcess({
        'USER_AGENT': 'Mozilla/5.0', 
    })
    c.crawl(TitleSpider)
    c.start()

Я не уверен на 100%, что это предотвратит синтаксический анализ третьего URL-адреса, поскольку я думаю, что CloseSpider останавливает новые запросы от начала, но ожидает завершения запущенных запросов.

Если вы хотите предотвратить удаление более 2 элементов, вы можете отредактировать parse, чтобы не выдавать элементы, когда self.counter > 2.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...