Como você garante a qualidade e a confiabilidade dos dados que você está extraindo em seu crawler?
Se o seu crawler foi desenvolvido com Scrapy, você tem a disposição a extensão Spidermon, que junto com a biblioteca Schematics permite que você inclua validações de dados de maneira simples e altamente customizável.
Definindo modelos de dados, é possível comparar os items retornados com uma estrutura pré-determinada, garantido que todos os campos contém dados no formato esperado.
Nosso exemplo
Para explicar o uso do Spidermon para realizar a validação dos dados, criamos um projeto de exemplo simples, que extrai citações do site http://quotes.toscrape.com/.
Começamos instalando as bibliotecas necessárias:
$ python3 -m venv .venv
$ source .venv/bin/activate
(.venv) $ pip install scrapy spidermon schematics
Em seguida criamos um novo projeto Scrapy:
$ scrapy startproject quotes_crawler
$ cd myproject & scrapy genspider quotes quotes.com
Definimos um item que será retornado pelo nosso spider:
# quotes_crawler/spiders/items.py
import scrapy
class QuoteItem(scrapy.Item):
quote = scrapy.Field()
author = scrapy.Field()
author_url = scrapy.Field()
tags = scrapy.Field()
E finalmente criamos o nosso spider:
# quotes_crawler/spiders/quotes.py
import scrapy
from myproject.items import QuoteItem
class QuotesSpider(scrapy.Spider):
name = "quotes"
allowed_domains = ["quotes.toscrape.com"]
start_urls = ["http://quotes.toscrape.com/"]
def parse(self, response):
for quote in response.css(".quote"):
item = QuoteItem(
quote=quote.css(".text::text").get(),
author=quote.css(".author::text").get(),
author_url=response.urljoin(
quote.css(".author a::attr(href)").get()),
tags=quote.css(".tag *::text").getall(),
)
yield item
yield scrapy.Request(
response.urljoin(response.css(
".next a::attr(href)").get())
)
Com isso já é possível executar o nosso crawler e obter os dados desejados:
$ scrapy crawl quotes -o quotes.csv
Definindo nosso modelo de validação
Schematics é uma biblioteca de validação de dados baseada em modelos (muito parecidos com modelos do Django). Esses modelos incluem alguns tipos de dados comuns e validadores, mas também é possível extendê-los e definir regras de validação customizadas.
Baseado no nosso exemplo anterior, vamos criar um modelo para o nosso item contendo algumas regras básicas de validação:
# quotes_crawler/spiders/validators.py
from schematics.models import Model
from schematics.types import URLType, StringType, ListType
class QuoteItem(Model):
# String de preenchimento obrigatório
quote = StringType(required=True)
# String de preenchimento obrigatório
author = StringType(required=True)
# Uma string que represente uma URL de preenchimento obrigatório
author_url = URLType(required=True)
# Lista de Strings de preenchimento não obrigatório
tags = ListType(StringType)
Precisamos agora habilitar o Spidermon e configurá-lo para que os campos retornados pelo nosso spider sejam validados contra esse modelo:
# quotes_crawler/settings.py
SPIDERMON_ENABLED = True
EXTENSIONS = {
"spidermon.contrib.scrapy.extensions.Spidermon": 500,
}
ITEM_PIPELINES = {
"spidermon.contrib.scrapy.pipelines.ItemValidationPipeline": 800
}
SPIDERMON_VALIDATION_MODELS = (
"quotes_crawler.validators.QuoteItem",
)
# Inclui um campo '_validation' nos items que contenham erros
# com detalhes do problema encontrado
SPIDERMON_VALIDATION_ADD_ERRORS_TO_ITEMS = True
Conforme os dados forem extraidos, eles serão validados de acordo com as regras
definidas no modelo e, caso algum erro seja encontrado, um novo campo
_validation
será incluído no item com detalhes do erro.
Caso um item receba uma URL inválida no campo author_url
por exemplo, o
resultado será:
{
'_validation': defaultdict(
<class 'list'>, {'author_url': ['Invalid URL']}),
'author': 'C.S. Lewis',
'author_url': 'invalid_url',
'quote': 'Some day you will be old enough to start reading fairy tales '
'again.',
'tags': ['age', 'fairytales', 'growing-up']
}