Scrapy: не могу перезапустить start_requests () правильно - PullRequest
0 голосов
/ 10 января 2019

У меня есть скребок, который запускает две страницы - одна из них является главной страницей, а другая - файлом .js, который содержит длинные и латинские координаты, которые мне нужно извлечь, потому что они понадобятся мне позже в процессе анализа. Сначала я хочу обработать файл .js, извлечь координаты, а затем проанализировать главную страницу и начать сканировать ее ссылки / анализировать ее элементы. Для этого я использую параметр priority в методе Request и говорю, что хочу, чтобы моя страница .js была обработана первой. Это работает, но только в 70% случаев (должно быть из-за асинхронных запросов Scrapy). Остальные 30% времени я в конечном итоге пытаюсь проанализировать координаты long / lat в формате .js, но, пройдя главную страницу веб-сайта, их невозможно проанализировать.

По этой причине я попытался исправить это так: в методе parse() проверьте, какой это n-й URL, если он первый, а не .js, перезапустите паука. Однако, когда я перезагружаю паука в следующий раз, он сначала корректно передает файл .js, но после его обработки паук завершает работу и завершает работу сценария без ошибок, как если бы он был завершен. Почему это происходит, в чем разница с обработкой страниц при перезапуске паука по сравнению с тем, когда я только запускаю его, и как я могу решить эту проблему?

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

class QuotesSpider(Spider):

    name = "bot"
    url_id = 0
    home_url = 'https://website.com'
    longitude = None
    latitude = None

    def __init__(self, cat=None):
        self.cat = cat.replace("-", " ")

    def start_requests(self):
        print ("Starting spider")
        self.start_urls = [
             self.home_url,
             self.home_url+'js-file-with-long-lat.js'
        ]
        for priority, url in enumerate(self.start_urls):
            print ("Processing", url)
            yield Request(url=url, priority=priority, callback=self.parse)


    def parse(self, response):
        print ("Inside parse")
        if self.url_id == 0 and response.url == self.home_url:
            self.alert("Loaded main page before long/lat page, restarting", False)
            for _ in self.start_requests():
                yield _
        else:
            print ("Everything is good, url id is", str(self.url_id))
            self.url_id +=1
            if self.longitude is None:
                for _ in self.parse_long_lat(response):
                    yield _
            else:
                print ("Calling parse cats")
                for cat in self.parse_cats(response):
                    yield cat

    def parse_long_lat(self, response):
        print ("called long lat")
        try:
            self.latitude = re.search('latitude:(\-?[0-9]{1,2}\.?[0-9]*)', 
            response.text).group(1)
            self.longitude = re.search('longitude:(\-?[0-9]{1,3}\.?[0-9]*)', 
            response.text).group(1)
            print ("Extracted coords")
            yield None
        except AttributeError as e:
            self.alert("\nCan't extract lat/long coordinates, store availability will not be parsed. ", False)
            yield None

    def parse_cats(self, response):           
        pass
        """ Parsing links code goes here """

Вывод, когда паук запускается правильно, сначала получает страницу .js, а второй начинает анализировать кошек:

Starting spider
https://website.com
https://website.com/js-file-with-long-lat.js
Inside parse
Everything is good, url id is 0
called long lat
Extracted coords
Inside parse
Everything is good, url id is 1
Calling parse cats

И сценарий продолжается и все хорошо разбирает. Выводится, когда паук запускается неправильно, сначала получает главную страницу и перезапускает start_requests ():

Starting spider
https://website.com
https://website.com/js-file-with-long-lat.js
Inside parse
Loaded main page before long/lat page, restarting
Starting spider
https://website.com
https://website.com/js-file-with-long-lat.js
Inside parse
Everything is good, url id is 0
called long lat
Extracted coords

И сценарий останавливается без ошибок, как если бы он был завершен.

P.S. Если это имеет значение, я упомянул, что URL обработки в start_requests() обрабатывается в обратном порядке, но я нахожу это естественным из-за последовательности циклов, и я ожидаю, что параметр priority выполнит свою работу (как и большинство время, и оно должно делать это в соответствии с документами Scrapy).

Ответы [ 2 ]

0 голосов
/ 12 января 2019

Итак, я, наконец, справился с этим: Я проверяю, что response.url получено в parse() и на основании этого я отправляю дальнейший разбор в соответствующий метод:

def start_requests(self):
        self.start_urls = [
            self.home_url,
            self.home_url + 'js-file-with-long-lat.js'
        ]
        for priority, url in enumerate(self.start_urls):
            yield Request(url=url, priority=priority, callback=self.parse)

def parse(self, response):
    if response.url != self.home_url:
        for _ in self.parse_long_lat(response):
            yield _
    else:
        for cat in self.parse_cats(response):
            yield cat
0 голосов
/ 10 января 2019

Почему ваш Паук не продолжает работу в случае «перезапуска»; вы вероятно столкнулись с повторяющимися запросами , которые фильтруются / отбрасываются. Поскольку страница уже посещена, Scrapy считает, что это сделано.
Таким образом, вам придется повторно отправить эти запросы с аргументом dont_filter=True:

for priority, url in enumerate(self.start_urls):
    print ("Processing", url)
    yield Request(url=url, dont_filter=True, priority=priority, callback=self.parse)
    #                      ^^^^^^^^^^^^^^^^  notice us forcing the Dupefilter to
    #                                        ignore duplicate requests to these pages

Что касается лучшего решения вместо этого хакерского подхода, рассмотрите возможность использования InitSpider (например, существуют другие методы). Это гарантирует, что ваша «начальная» работа выполнена, и на нее можно положиться.
(По какой-то причине класс никогда не был задокументирован в Scrapy docs , но это относительно простой подкласс Spider: сделайте некоторую начальную работу, прежде чем начинать фактический прогон.)

И вот пример кода для этого:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.spiders.init import InitSpider

class QuotesSpider(InitSpider):
    name = 'quotes'
    allowed_domains = ['website.com']
    start_urls = ['https://website.com']

    # Without this method override, InitSpider behaves like Spider.
    # This is used _instead of_ start_requests. (Do not override start_requests.)
    def init_request(self):
        # The last request that finishes the initialization needs
        # to have the `self.initialized()` method as callback.
        url = self.start_urls[0] + '/js-file-with-long-lat.js'
        yield scrapy.Request(url, callback=self.parse_long_lat, dont_filter=True)

    def parse_long_lat(self, response):
        """ The callback for our init request. """
        print ("called long lat")

        # do some work and maybe return stuff
        self.latitude = None
        self.longitude = None
        #yield stuff_here

        # Finally, start our run.
        return self.initialized()
        # Now we are "initialized", will process `start_urls`
        # and continue from there.

    def parse(self, response):
        print ("Inside parse")
        print ("Everything is good, do parse_cats stuff here")

, что приведет к выводу, как это:

2019-01-10 20:36:20 [scrapy.core.engine] INFO: Spider opened
2019-01-10 20:36:20 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2019-01-10 20:36:20 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://127.0.0.1/js-file-with-long-lat.js> (referer: None)
called long lat
2019-01-10 20:36:20 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://127.0.0.1> (referer: http://127.0.0.1/js-file-with-long-lat.js/)
Inside parse
Everything is good, do parse_cats stuff here
2019-01-10 20:36:21 [scrapy.core.engine] INFO: Closing spider (finished)
...