[PYTHON] Redémarrez avec Scrapy

Scrapy, un framework Python pour l'exploration de sites Web, a la capacité de redémarrer, c'est-à-dire d'interrompre pendant l'exécution, puis de reprendre à partir de la suite précédente. Ceci est utile lorsque vous visitez un grand nombre de pages et effectuez un scraping chronophage.

Voici la documentation officielle. Jobs: pausing and resuming crawls

Aperçu de la fonction

J'ai préparé l'araignée suivante pour essayer la fonction. http://quotes.toscrape.com 6 Téléchargez simplement la page et enregistrez le contenu.

toscrape-restart.py


import scrapy
import json
import time


class QuotesSpider(scrapy.Spider):
    name = "toscrape-restart"

    custom_settings = {
        #Ne pas demander en parallèle
        "CONCURRENT_REQUESTS": 1,
        #Définissez des intervalles sur les demandes pour les rendre plus faciles à interrompre
        "DOWNLOAD_DELAY": 10,
        # http://quotes.toscrape.robots sur com.N'obtenez pas de txt car il n'existe pas
        "ROBOTSTXT_OBEY": False,
    }

    def start_requests(self):
        #Maintenir l'état entre les lots (voir ci-dessous)
        self.logger.info(self.state.get("state_key1"))
        self.state["state_key1"] = {"key": "value"}
        self.state["state_key2"] = 0

        urls = [
            "http://quotes.toscrape.com/page/1/",
            "http://quotes.toscrape.com/page/2/",
            "http://quotes.toscrape.com/page/3/",
            "http://quotes.toscrape.com/page/4/",
            "http://quotes.toscrape.com/page/5/",
            "http://quotes.toscrape.com/page/6/",
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        self.logger.info(
            "first quote author: " + response.css("small.author::text").get()
        )

L'araignée ci-dessus peut être démarrée avec la commande suivante.

scrapy crawl toscrape-restart

Ce sera une exécution normale. Pour le rendre redémarrable, définissez JOBDIR comme suit.

scrapy crawl toscrape-restart -s JOBDIR=crawls/restart-1

Cela créera un répertoire crawls / restart-1 qui stocke les informations pour les redémarrages et vous permettra de redémarrer. (S'il n'y a pas de répertoire, Scrapy le créera, vous n'avez donc pas besoin de le préparer à l'avance) Démarrez-le avec la commande ci-dessus et interrompez-le avec Ctrl-C pendant l'exécution. Par exemple, si vous l'arrêtez immédiatement après avoir obtenu la première page, la sortie sera la suivante.

$ scrapy crawl toscrape-restart -s JOBDIR=crawls/restart-1

(Omis)

2020-03-24 14:43:04 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/1/> (referer: None)
2020-03-24 14:43:04 [toscrape-restart] INFO: first quote author: Albert Einstein
^C2020-03-24 14:43:06 [scrapy.crawler] INFO: Received SIGINT, shutting down gracefully. Send again to force 
2020-03-24 14:43:06 [scrapy.core.engine] INFO: Closing spider (shutdown)
2020-03-24 14:43:18 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/2/> (referer: None)
2020-03-24 14:43:18 [toscrape-restart] INFO: first quote author: Marilyn Monroe
2020-03-24 14:43:19 [scrapy.statscollectors] INFO: Dumping Scrapy stats:

(Omis)

Il a été interrompu lorsque j'ai reçu la deuxième page. Après avoir interrompu de cette manière, vous pouvez reprendre en exécutant la même commande que la première.

$ scrapy crawl toscrape-restart -s JOBDIR=crawls/restart-1

(Omis)

2020-03-24 14:46:07 [scrapy.dupefilters] DEBUG: Filtered duplicate request: <GET http://quotes.toscrape.com/page/1/> - no more duplicates will be shown (see DUPEFILTER_DEBUG to show all duplicates)
2020-03-24 14:46:10 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/3/> (referer: None)
2020-03-24 14:46:10 [toscrape-restart] INFO: first quote author: Pablo Neruda
2020-03-24 14:46:21 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/4/> (referer: None)
2020-03-24 14:46:21 [toscrape-restart] INFO: first quote author: Dr. Seuss
2020-03-24 14:46:35 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/5/> (referer: None)
2020-03-24 14:46:35 [toscrape-restart] INFO: first quote author: George R.R. Martin
2020-03-24 14:46:47 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/6/> (referer: None)
2020-03-24 14:46:47 [toscrape-restart] INFO: first quote author: Jane Austen
2020-03-24 14:46:47 [scrapy.core.engine] INFO: Closing spider (finished)
2020-03-24 14:46:47 [scrapy.statscollectors] INFO: Dumping Scrapy stats:

(Omis)

Les 1ère et 2ème pages étaient affichées comme "Requête en double filtrée" et n'ont pas été récupérées. Après cela, la troisième page et les suivantes qui n'ont pas été acquises avant l'interruption l'ont été normalement.

Conserver l'état entre les lots

Le redémarrage Scrapy a la capacité de transmettre des informations entre les démarrages en utilisant state. Les informations peuvent être stockées dans l'état spider et référencées au prochain démarrage. Plus précisément, il peut être stocké dans l'utilisation suivante dans le premier toscrape-restart.py.

self.state["state_key1"] = {"key": "value"}
self.state["state_key2"] = 0

Puisque «state» est un «type dict», vous pouvez effectuer des opérations sur le dictionnaire. Dans l'exemple ci-dessus, la valeur "{" key ":" value "}" est stockée dans la clé "state_key1", et la valeur "0" est stockée dans la clé "state_key2". Quand je l'exécute, cela ressemble à ceci:

$ scrapy crawl toscrape-restart -s JOBDIR=crawls/restart-1

(Omis)

2020-03-24 15:19:54 [toscrape-restart] INFO: None
2020-03-24 15:19:55 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/1/> (referer: None)
2020-03-24 15:19:55 [toscrape-restart] INFO: first quote author: Albert Einstein
^C2020-03-24 15:19:56 [scrapy.crawler] INFO: Received SIGINT, shutting down gracefully. Send again to force 
2020-03-24 15:19:56 [scrapy.core.engine] INFO: Closing spider (shutdown)
2020-03-24 15:20:06 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/2/> (referer: None)
2020-03-24 15:20:07 [toscrape-restart] INFO: first quote author: Marilyn Monroe
2020-03-24 15:20:07 [scrapy.statscollectors] INFO: Dumping Scrapy stats:

(Omis)

Le journal INFO «Aucun» est affiché sur la première ligne. Ceci est produit par self.logger.info (self.state.get (" state_key1 ")), et rien n'est produit car rien n'est stocké dans state au premier démarrage. Dans le processus suivant, les informations ont été stockées dans "état" puis interrompues. Puis réessayez.

$ scrapy crawl toscrape-restart -s JOBDIR=crawls/restart-1

(Omis)

2020-03-24 15:29:31 [toscrape-restart] INFO: {'key': 'value'}
2020-03-24 15:29:31 [scrapy.dupefilters] DEBUG: Filtered duplicate request: <GET http://quotes.toscrape.com/page/1/> - no more duplicates will be shown (see DUPEFILTER_DEBUG to show all duplicates)
2020-03-24 15:29:31 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/3/> (referer: None)
2020-03-24 15:29:32 [toscrape-restart] INFO: first quote author: Pablo Neruda
2020-03-24 15:29:42 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/4/> (referer: None)
2020-03-24 15:29:42 [toscrape-restart] INFO: first quote author: Dr. Seuss
2020-03-24 15:29:56 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/5/> (referer: None)
2020-03-24 15:29:56 [toscrape-restart] INFO: first quote author: George R.R. Martin
2020-03-24 15:30:10 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/6/> (referer: None)
2020-03-24 15:30:10 [toscrape-restart] INFO: first quote author: Jane Austen
2020-03-24 15:30:10 [scrapy.core.engine] INFO: Closing spider (finished)
2020-03-24 15:30:10 [scrapy.statscollectors] INFO: Dumping Scrapy stats:

(Omis)

Après le redémarrage, le journal INFO de {'key': 'value'} est affiché sur la première ligne. Vous pouvez voir que les informations stockées avant l'interruption peuvent être référencées au moment de la réexécution.

D'autres choses que j'ai remarquées

Le plan est comme décrit ci-dessus, mais je noterai d'autres choses que j'ai vérifiées et remarquées.

Rôle de JOBDIR

Si vous utilisez une méthode de démarrage redémarrable, un répertoire dont le nom est passé en argument au démarrage sera créé. À l'intérieur de ce répertoire se trouvent un répertoire appelé «requests.queue» et des fichiers appelés «requests.seen» et «spider.state». Parmi ceux-ci, je n'ai pas vérifié à quoi sert requests.queue ...

spider.state est le fichier dans lequel l'état de la section précédente est stocké. Il s'agit d'un fichier pickle et vous pouvez vérifier son contenu avec la commande suivante.

python -m pickle spider.state

Avec le modèle de l'exemple de la section précédente, la sortie ressemble à ceci, et vous pouvez voir que les informations sont certainement stockées.

{'state_key1': {'key': 'value'}, 'state_key2': 0}

D'autre part, «requests.seen» contient une chaîne hachée. Je ne l'ai pas recherché très précisément non plus, mais il semble que ce soit exactement comme le nom «vu», et l'URL du site qui a obtenu les informations lors de l'exécution est enregistrée. Il semble que le site enregistré ici soit ignoré lors de la réexécution.

Réexécuter après la fin

Si vous terminez le grattage jusqu'à la fin sans interrompre pendant l'exécution, la réexécution se terminera sans rien faire car toutes les URL ont été acquises. Cela ne semble pas prendre de soin, comme l'écrasement de JOBDIR. Vous devez supprimer le JOBDIR ou modifier l'argument.

Recommended Posts

Redémarrez avec Scrapy
Grattage avec coquille tremblante
Problèmes lors de l'installation de Scrapy
Grattage festif avec Python, scrapy
Grattage Web facile avec Scrapy
Comment démarrer avec Scrapy
Créer un exe Scrapy avec Pyinstaller
Création de carte Ramen avec Scrapy et Django
Collectez les informations de latitude / longitude du magasin avec scrapy + splash ②
L'araignée introuvable apparaît lors de l'exploration avec Scrapy
Collectez les informations de latitude / longitude du magasin avec scrapy + splash ①