[PYTHON] Schreiben Sie Spinnen-Tests in Scrapy

Als ich versuchte, einen Unit-Test für Scrapy zu schreiben, war das etwas Besonderes und ich hatte nicht viele Informationen, also habe ich es zusammengefasst. Aufgrund der Eigenschaften des Crawlers, dass es sicher ist, den HTML-Code jederzeit zu ändern, ist es meiner Meinung nach besser, ihn hauptsächlich zu verwenden, um die Crawlzeit zum Zeitpunkt der Implementierung zu verkürzen, als die Gültigkeitsprüfung. (* Dies ist hauptsächlich ein Artikel über Spider-Unit-Tests) (* Tests wie Pipeline liegen außerhalb des Bereichs, da sie normalerweise mit unittest usw. geschrieben werden können.)

TL;DR;

Verwenden Sie Spinnenverträge

    def parse(self, response):
    """ This function parses a sample response. Some contracts are mingled
    with this docstring.

    @url http://www.amazon.com/s?field-keywords=selfish+gene
    @returns items 1 16
    @returns requests 0 0
    @scrapes Title Author Year Price
    """

Grundlegende Nutzung von Spinnenverträgen

Ich denke, es ist schnell, den folgenden Beispielcode zu sehen. (Python3.6.2, Scrapy 1.4.0)

myblog.py


    def parse_list(self, response):
        """Listenbildschirm-Analyseprozess

        @url http://www.rhoboro.com/index2.html
        @returns item 0 0
        @returns requests 0 10
        """
        for detail in response.xpath('//div[@class="post-preview"]/a/@href').extract():
            yield Request(url=response.urljoin(detail), callback=self.parse_detail)

Machen Sie benutzerdefinierte Verträge

Unterklasse erstellen

Verträge können durch Erstellen eigener Unterklassen verlängert werden. Registrieren Sie die erstellten Verträge in settings.py.

contracts.py


# -*- coding: utf-8 -*-

from scrapy.contracts import Contract
from scrapy.exceptions import ContractFail


class ItemValidateContract(Contract):
    """Überprüfen Sie, ob der Artikel den Erwartungen entspricht

Weil sich das Akquisitionsergebnis jederzeit ändern kann
Ich denke, es ist am besten, nur dort zu testen, wo Sie unveränderliche Werte erwarten.
Sollte ich mehr als fehlende Elemente mit Pipeline überprüfen?
    """
    name = 'item_validate' #Dieser Name ist der Name in der Dokumentzeichenfolge

    def post_process(self, output):
        item = output[0]
        if 'title' not in item:
            raise ContractFail('title is invalid.')


class CookiesContract(Contract):
    """Auf Anfrage(kratzig)Vertrag zum Hinzufügen von Cookies

    @cookies key1 value1 key2 value2
    """
    name = 'cookies'

    def adjust_request_args(self, kwargs):
        # self.Konvertieren Sie Argumente in das Wörterbuchformat und setzen Sie Cookies ein
        kwargs['cookies'] = {t[0]: t[1]
                             for t in zip(self.args[::2], self.args[1::2])}
        return kwargs

Benutzercode

Der Code auf der Seite, die dies verwendet, sieht folgendermaßen aus.

settings.py


...
SPIDER_CONTRACTS = {
    'item_crawl.contracts.CookiesContract': 10,
    'item_crawl.contracts.ItemValidateContract': 20,
}
...

myblog.py


    def parse_detail(self, response):
        """Detailbildschirm-Analyseprozess

        @url http://www.rhoboro.com/2017/08/05/start-onomichi.html
        @returns item 1
        @scrapes title body tags
        @item_validate
        @cookies index 2
        """
        item = BlogItem()
        item['title'] = response.xpath('//div[@class="post-heading"]//h1/text()').extract_first()
        item['body'] = response.xpath('//article').xpath('string()').extract_first()
        item['tags'] = response.xpath('//div[@class="tags"]//a/text()').extract()
        item['index'] = response.request.cookies['index']
        yield item

Führen Sie den Test aus

Führen Sie mit "Scrapy Check Spidername" aus. Offensichtlich ist es schneller als das Ausprobieren des Scrapy-Crawler-Spinnennamens, da nur die angegebene Seite gecrawlt wird.

(venv) [alpaca]~/github/scrapy/crawler/crawler % scrapy check my_blog                                                                                                [master:crawler]
.....
----------------------------------------------------------------------
Ran 5 contracts in 8.919s

OK
(venv) [alpaca]~/github/scrapy/crawler/crawler % scrapy check my_blog                                                                                                [master:crawler]
...FF
======================================================================
FAIL: [my_blog] parse_detail (@scrapes post-hook)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/rhoboro/github/scrapy/venv/lib/python3.6/site-packages/scrapy/contracts/__init__.py", line 134, in wrapper
    self.post_process(output)
  File "/Users/rhoboro/github/scrapy/venv/lib/python3.6/site-packages/scrapy/contracts/default.py", line 89, in post_process
    raise ContractFail("'%s' field is missing" % arg)
scrapy.exceptions.ContractFail: 'title' field is missing

======================================================================
FAIL: [my_blog] parse_detail (@item_validate post-hook)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/rhoboro/github/scrapy/venv/lib/python3.6/site-packages/scrapy/contracts/__init__.py", line 134, in wrapper
    self.post_process(output)
  File "/Users/rhoboro/github/scrapy/crawler/crawler/contracts.py", line 18, in post_process
    raise ContractFail('title is invalid.')
scrapy.exceptions.ContractFail: title is invalid.

----------------------------------------------------------------------
Ran 5 contracts in 8.552s

FAILED (failures=2)

Übrigens hier im Fehlerfall. (In diesem Moment habe ich vergessen, settings.py zu erwähnen.) Um ehrlich zu sein, gibt es zu wenig Informationen und es ist schwierig.

(venv) [alpaca]~/github/scrapy/crawler/crawler % scrapy check my_blog                                                                                                [master:crawler]
Unhandled error in Deferred:


----------------------------------------------------------------------
Ran 0 contracts in 0.000s

OK

Recommended Posts

Schreiben Sie Spinnen-Tests in Scrapy
Schreiben Sie einen Test in GO-Sprache + Gin
Schreiben Sie einen C-Sprach-Unit-Test in Python
Schreiben Sie Dekorateur in der Klasse
Schreiben Sie Python in MySQL
Schreiben Sie Tests in Python, um die Abdeckung zu profilieren und zu überprüfen
Schreiben Sie Pandec-Filter in Python
Schreiben Sie die Standardeingabe in den Code
Schreiben Sie die Beta-Distribution in Python
Schreiben Sie Python in Rstudio (reticulate)
Schreiben Sie Spigot in VS Code
Schreiben Sie Daten im HDF-Format
Schreiben Sie eine Dichotomie in Python
Schreiben Sie einen tabellengesteuerten Test in C.
Schreiben Sie ein JSON-Schema mit Python DSL
Wie man nüchtern mit Pandas schreibt
Schreiben Sie einen HTTP / 2-Server in Python
Installieren Sie Scrapy in einer Python Anaconda-Umgebung
Schreiben Sie die AWS Lambda-Funktion in Python
Bis Sie anfangen, mit Scrapy zu kriechen
Schreiben Sie A * (A-Stern) -Algorithmen in Python
[Maya] Schreiben Sie einen benutzerdefinierten Knoten in Open Maya 2.0
Schreiben Sie externe Schlüsseleinschränkungen in Django
Schreiben Sie Selentestcode in Python
Schreiben Sie ein Kreisdiagramm in Python
Code-Tests rund um die Uhr in Python
So trennen Sie den Pipeline-Verarbeitungscode mit Scrapy nach Spider