Разделение одного паука на разных пауков в скрапе - PullRequest
0 голосов
/ 20 января 2020

Я бы хотел разделить разбор на разных пауков.

В настоящее время у меня есть:

class CategoriesSpider(scrapy.Spider):
    name = 'categories'
    allowed_domains = ['example.org']
    start_urls = ['https://example.org/categories']

    def parse(self, response):
        for link in response.xpath("//div[@class='something']/@href"):
          yield scrapy.Request(response.urljoin(link.root), callback=self.parse_actual_item_i_want)

    def parse_actual_item_i_want(self, response):
          yield self.find_the_item(response)

А теперь разбить его на:

class OneThingSpider(scrapy.Spider):
    name = 'one_thing'
    allowed_domains = ['example.org']
    start_urls = ['https://example.org/']

    def __init__(self, url: str):
        if url == None or url == "":
            raise ValueError("Invalid url given")

        # Exact URL and it's format is not known
        self.start_urls = [url]

    def parse(self, response):
          yield self.find_the_item(response)

Итак что если обновляется только одна вещь, я могу использовать только OneThingSpider

Так где и как я называю OneThingSpider внутри CategoriesSpider или конвейером?

Я пробовал вот это:

Внутри CategoriesSpider попытки # 1:

    def parse(self, response):
        for link in response.xpath("//div[@class='something']/@href"):
          yield self.crawler.crawl("one_thing", response.urljoin(link.root))

В попытке конвейера # 1:

В CategoriesSpider:

    def parse(self, response):
        for link in response.xpath("//div[@class='something']/@href"):
          yield CategoryUrl({"url": response.urljoin(link.root)})

В конвейере:

class MyPipeline(object):
    def process_item(self, item, spider):
        if isinstance(item, CategoryUrl):
            spider.crawler.crawl("one_thing", item["url"])
            return

        # this part works
        if isinstance(item, ItemIWant): 
            with open(...)

В конвейере попытка # 2:

То же изменение в CategoriesSpider, что и при попытке # 1. Здесь мы просто пытаемся получить sh URL-адреса OneThingSpider после закрытия CategoriesSpider.

В конвейере:

class MyPipeline(object):
    urls = []
    def process_item(self, item, spider):
        if isinstance(item, CategoryUrl):
            self.urls.append(item["url"])
            spider.crawler.crawl("one_thing", item["url"])
            return

        # this part works
        if isinstance(item, ItemIWant): 
            with open(...)

    def close_spider(self, spider):
        if spider.name == "categories":
            for url in self.urls:
                spider.crawler.crawl("one_thing", url)

Ошибка, которую я получаю, заключается в том, что гусеничный уже ползет . Итак, как правильно разделить паука на более мелких пауков?

Цель состоит в том, что я могу бегать:

scrapy crawl categories

, а также

scrapy crawl one_thing -a url="https://example.org/something/xyz.html"

1 Ответ

0 голосов
/ 20 января 2020

Обычно вы использовали бы наследование классов для повторного использования кода паука в нескольких пауках:

class BaseSpider(Spider):
    start_urls = NotImplemented
    start_body = ""

    def start_requests(self):
        for url in self.start_urls:
            yield Request(url, method='POST', body=self.start_body)

    def parse(self, response):
        raise NotImplementedError


# then children spiders
class CakeSpider(BaseSpider):
    name = 'cakes'
    start_urls = ['http://example1.com']
    start_body = '{"category": "cakes"}'

    def parse(self, response):
        # custom parser for first spider here

class VegetableSpider(BaseSpider):
    name = 'vegetables'
    start_urls = ['http://example2.com']
    start_body = '{"category": "vegetables"}'

    def parse(self, response):
        # custom parser for second spider here

В результате вы запустили бы scrapy crawl cakes, чтобы начать сканирование категории тортов, и scrapy crawl vegetables, чтобы сканировать категорию овощей. .

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