Coletando dados de todo o site usando a classe pai Spider: parâmetros de solicitação, cinco componentes principais e middleware

Coletando dados de todo o site

Para coletar dados de todo o site, é necessário:

  • Capturar dados de todas as páginas
  • Enviar solicitações manualmante:
  • yield scrapy.Request(url, callback)
  • Resumo do uso de yield:
  • Enviar itens para o pipeline usando yield item
  • Enviar solicitações manuais usando yield scrapy.Request(url, callback)
  • Enviar solicitações POST manualmente:
  • yield scrapy.FormRequest(url, formdata, callback) onde formdata é um dicionário com os parâmetros da solicitação
import scrapy
from exemplo.items import ExemploItem

class SiteSpider(scrapy.Spider):
    name = 'site'
    start_urls = ['https://www.exemplo.com/']
    url_template = 'https://www.exemplo.com/pagina=%d'

    def parse(self, response):
        itens = response.xpath('//div[@class="itens"]/li')
        for item in itens:
            titulo = item.xpath('.//h2/text()').get()
            autor = item.xpath('.//span[@class="autor"]/text()').get()
            visualizacoes = item.xpath('.//span[@class="views"]/text()').get()

            novo_item = ExemploItem()
            novo_item['titulo'] = titulo
            novo_item['autor'] = autor
            novo_item['visualizacoes'] = visualizacoes

            yield novo_item

        page_number = 2
        while page_number <= 10:
            new_url = self.url_template % page_number
            yield scrapy.Request(url=new_url, callback=self.parse_pagina)
            page_number += 1

    def parse_pagina(self, response):
        print(response.text)

Cinco componentes principais do Scrapy

  1. Motor (Engine)
  • Gerencia o fluxo de dados e inicia as transações
  1. Scheduler
  • Aceita as solicitações do motor, as armazena em uma fila e define a ordem de processamento
  1. Downloader
  • Realiza a Download de conteúdo da web
  1. Spiders
  • Extraem os dados relevantes das páginas
  1. Pipeline
  • Processa os itens coletados, validnado, limpando e armazenando os dados

Trabalhando com parâmetros de solicitação

  • Objetivo: Permitir coletas mais profundas
  • Uso: Quando os dados necessários não estão na mesma página
  • Mecanismo:
  • Enviar parâmetros usando yield scrapy.Request(url, callback, meta)
  • Receber parâmetros no callback usando response.meta
import scrapy
from filmes.items import FilmeItem

class FilmeSpider(scrapy.Spider):
    name = 'filmes'
    start_urls = ['https://www.cinemas.com/filmes']
    url_template = 'https://www.cinemas.com/filmes/pagina-%d'
    pagina_atual = 1

    def parse(self, response):
        print(f'Coletando dados da página {self.pagina_atual}')
        filmes = response.xpath('//div[@class="filme-lista"]/div')
        for filme in filmes:
            item = FilmeItem()
            item['titulo'] = filme.xpath('.//h3/a/text()').get()
            detail_url = filme.xpath('.//a/@href').get()
            yield scrapy.Request(detail_url, callback=self.parse_detalhe, meta={'item': item})

        if self.pagina_atual < 5:
            self.pagina_atual += 1
            new_url = self.url_template % self.pagina_atual
            yield scrapy.Request(new_url, callback=self.parse)

    def parse_detalhe(self, response):
        item = response.meta['item']
        descricao = response.xpath('//div[@class="descricao"]/text()').get()
        item['descricao'] = descricao
        yield item

Melhorando a eficiência do Scrapy

  • Configurações no arquivo settings.py:
  • Aumentar o número de requisições simultâneas: CONCURRENT_REQUESTS = 100
  • Reduzir o nível de logs: LOG_LEVEL = 'INFO'
  • Desativar cookies: COOKIES_ENABLED = False
  • Desativar retentaitvas: RETRY_ENABLED = False
  • Definir timeout de download: DOWNLOAD_TIMEOUT = 10

Pool de User-Agents

user_agents_pool = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:36.0) Gecko/20140701 Firefox/36.0',
    'Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12.388 Version/12.18',
    # Adicione mais User-Agents conforme necessário
]

Middleware no Scrapy

O middleware do Scrapy permite:

  • Modificar headers de requisição
  • Alterar URLs
  • Definir proxies
import random
from scrapy import signals

class MeuMiddleware:
    def process_request(self, request, spider):
        request.headers['User-Agent'] = random.choice(user_agents_pool)
        print(f'User-Agent usado: {request.headers["User-Agent"]}')

        proxy = 'http://example.com:8080'
        request.meta['proxy'] = proxy
        print(f'Proxy definido: {proxy}')
        return None

    def process_response(self, request, response, spider):
        return response

    def process_exception(self, request, exception, spider):
        print(f'Exceção ocorrida em: {request.url}')
        return request

Exemplo prático: Coletando notícias do site de notícias

Análise:

  • Cada seção carrega suas notícias dinamicamente

Configurações no settings.py:

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'

ROBOTSTXT_OBEY = False
LOG_LEVEL = 'ERROR'

DOWNLOADER_MIDDLEWARES = {
    'noticias.middleware.NoticiaMiddleware': 543,
}

ITEM_PIPELINES = {
    'noticias.pipeline.NoticiaPipeline': 300,
}

Pipeline para armazenar em banco de dados:

import pymysql

class NoticiaPipeline:
    def open_spider(self, spider):
        self.conexao = pymysql.connect(
            host='localhost',
            port=3306,
            user='root',
            password='123456',
            db='scrapy_noticias',
            charset='utf8'
        )
        self.cursor = self.conexao.cursor()

    def process_item(self, item, spider):
        sql = """
        INSERT INTO noticias (titulo, conteudo)
        VALUES (%s, %s)
        """
        try:
            self.cursor.execute(sql, (item['titulo'], item['conteudo']))
            self.conexao.commit()
        except Exception as e:
            print(f'Erro ao inserir dados: {e}')
            self.conexao.rollback()
        return item

    def close_spider(self, spider):
        self.cursor.close()
        self.conexao.close()

Tags: Scrapy web scraping Python middleware user-agents

Publicado em 9-29 13:57