Raspagem da Web com o Scrapy: A maneira fácil

Mihai Maxim em Jan 30 2023

imagem do blogue

Raspagem da Web com o Scrapy

Scrapy é uma poderosa biblioteca Python para extrair dados de sites. É rápida, eficiente e fácil de usar - confie em mim, já passei por isso. Quer seja um cientista de dados, um programador ou alguém que adora brincar com dados, o Scrapy tem algo para lhe oferecer. E o melhor de tudo é que é gratuito e de código aberto.

Os projectos Scrapy vêm com uma estrutura de ficheiros que o ajuda a organizar o seu código e dados. Facilita a criação e manutenção de raspadores da Web, pelo que vale a pena considerar se estiver a planear fazer uma raspagem séria da Web. Web scraping com Scrapy É como ter um assistente útil (embora virtual) ao seu lado enquanto embarca na sua viagem de extração de dados.

O que vamos construir

Quando se está a aprender uma nova habilidade, uma coisa é ler sobre ela e outra coisa é realmente fazê-la. É por isso que decidimos construir um scraper juntos, à medida que avançamos neste guia. É a melhor maneira de obter uma compreensão prática de como funciona o web scraping com o Scrapy.

Então, o que é que vamos construir, exatamente? Vamos construir um raspador que recolhe as definições de palavras do sítio Web do Urban Dictionary. É um alvo divertido para a recolha de dados e ajudará a tornar o processo de aprendizagem mais agradável. O nosso scraper será simples - devolverá as definições de várias palavras encontradas no sítio Web do Urban Dictionary. Utilizaremos o suporte integrado do Scrapy para selecionar e extrair dados de documentos HTML para extrair as definições de que necessitamos.

Então, vamos começar! Na próxima secção, iremos rever os pré-requisitos necessários para seguir este tutorial. Até lá!

Pré-requisitos

Antes de mergulharmos na construção do nosso scraper, há algumas coisas que você precisará configurar. Nesta secção, iremos abordar como instalar o Scrapy e configurar um ambiente virtual para o nosso projeto. A documentação do Scrapy sugere a instalação do Scrapy em um ambiente virtual dedicado. Ao fazer isso, você evitará quaisquer conflitos com os pacotes do seu sistema.

Estou a executar o Scrapy no Ubuntu 22.04.1 WSL (Windows Subsystem for Linux), por isso vou configurar um ambiente virtual para a minha máquina.

Aconselho-o a ler o capítulo "Compreender a estrutura das pastas" para compreender totalmente as ferramentas com que estamos a trabalhar. Além disso, dê uma olhadela ao capítulo "Scrapy Shell", que tornará a sua experiência de desenvolvimento muito mais fácil.

Configurar um ambiente virtual Python

Para configurar um ambiente virtual para Python no Ubuntu, você pode usar o comando mkvirtualenv. Primeiro, certifique-se de que tem o virtualenv e o virtualenvwrapper instalados:

$ sudo apt-get install virtualenv virtualenvwrapper

Adicione estas linhas no final do seu ficheiro .bashrc:

export WORKON_HOME=$HOME/.virtualenvs

export PROJECT_HOME=$HOME/Deve

export VIRTUALENVWRAPPER_PYTHON='/usr/bin/python3'

source /usr/local/bin/virtualenvwrapper.sh

Utilizei o Vim para editar o ficheiro, mas pode escolher o editor que quiser:

vim ~/.bashrc

// Use ctr + i para entrar no modo de inserção, use a seta para baixo para ir até o final do arquivo.

// Cole as linhas no final do arquivo.

// Pressione escape para sair do modo de inserção, digite wq e pressione enter para salvar as alterações e sair do Vim.

Em seguida, crie um novo ambiente virtual com mkvirtualenv:

$ mkvirtualenv scrapy_env

Agora deve ver um (scrapy_env) anexado no início da sua linha de terminal.

Para sair do ambiente virtual, digite $ deactivate

Para voltar ao ambiente virtual scrappy_env, digite $ workon scrapy_env

Instalando o Scrapy

Pode instalar o Scrapy com o gestor de pacotes pip:

$ pip install scrapy

Isto irá instalar a versão mais recente do Scrapy.

É possível criar um novo projeto com o comando scrapy startproject:

$ scrapy startproject myproject

Isto irá inicializar um novo projeto Scrapy chamado "myproject". Ele deve conter a estrutura padrão do projeto.

Compreender a estrutura de pastas

Esta é a estrutura de projeto predefinida:

myproject

├── myproject

│ ├── __init__.py

│ ├── items.py

│ ├── middlewares.py

│ ├── pipelines.py

│ ├── settings.py

│ └── spiders

│ └── __init__.py

└── scrapy.cfg

items.py

items.py é um modelo para os dados extraídos. Este modelo será utilizado para armazenar os dados que extrai do sítio Web.

Exemplo:

import scrapy

class Product(scrapy.Item):

name = scrapy.Field()

price = scrapy.Field()

description = scrapy.Field()

Aqui definimos um Item chamado Produto. Este pode ser utilizado por uma Spider (ver /spiders) para armazenar informações sobre o nome, o preço e a descrição de um produto.

/aranhas

/spiders é uma pasta que contém as classes Spider. No Scrapy, as Spiders são classes que definem como um site deve ser raspado.

Exemplo:

import scrapy

from myproject.items import Product

class MySpider(scrapy.Spider):

name = 'myspider'

start_urls = ['<example_website_url>']



def parse(self, response):

# Extract the data for each product

for product_div in response.css('div.product'):

product = Product()

product['name'] = product_div.css('h3.name::text').get()

product['price'] = product_div.css('span.price::text').get()

product['description'] = product_div.css('p.description::text').get()

yield product

O "spider" percorre as start_urls, extrai o nome, o preço e a descrição de todos os produtos encontrados nas páginas (utilizando selectores css) e armazena os dados no Product Item (ver items.py). De seguida, "produz" estes itens, o que faz com que o Scrapy os passe para o componente seguinte no pipeline (ver pipelines.py).

Yield é uma palavra-chave em Python que permite que uma função devolva um valor sem terminar a função. Em vez disso, produz o valor e suspende a execução da função até que o próximo valor seja solicitado.

Por exemplo:

def count_up_to(max):

count = 1

while count <= max:

yield count

count += 1

for number in count_up_to(5):

print(number)

// returns 1 2 3 4 5 (each on a new line)

pipelines.py

Os pipelines são responsáveis pelo processamento dos itens (ver items.py e /spiders) que são extraídos pelos spiders. Pode utilizá-los para limpar o HTML, validar os dados e exportá-los para um formato personalizado ou guardá-los numa base de dados.

Exemplo:

import pymongo

class MongoPipeline(object):

def __init__(self):

self.conn = pymongo.MongoClient('localhost', 27017)

self.db = self.conn['mydatabase']

self.product_collection = self.db['products']

self.other_collection = self.db['other']



def process_item(self, item, spider):

if spider.name == 'product_spider':

//insere o item na colecção_de_produtos

elif spider.name == 'other_spider':

//inserir item na coleção other_collection

return item

Criámos um Pipeline chamado MongoPipeline. Ele se conecta a duas coleções do MongoDB (product_collection e other_collection). O pipeline recebe itens (veja items.py) de spiders (veja /spiders) e os processa na função process_item. Neste exemplo, a função process_item adiciona os itens às suas coleções designadas.

settings.py

O settings.py armazena uma variedade de configurações que controlam o comportamento do projeto Scrapy, como os pipelines, middlewares e extensões que devem ser usados, bem como configurações relacionadas a como o projeto deve lidar com solicitações e respostas.

Por exemplo, pode utilizá-lo para definir a ordem de execução dos pipelines (ver pipelines.py):

ITEM_PIPELINES = {

'myproject.pipelines.MongoPipeline': 300,

'myproject.pipelines.JsonPipeline': 302,

}

// MongoPipeline will execute before JsonPipeline, because it has a lower order number(300)

Ou definir um contentor de exportação:

FEEDS = {

'items': {'uri': 'file:///tmp/items.json', 'format': 'json'},

}

// this will save the scraped data to a items.json

scrappy.cfg

scrapy.cfg é o ficheiro de configuração para as definições principais do projeto.

[definições] 

predefinição = [nome do projeto].definições

[implantação]

#url = http://localhost:6800/

projeto = [nome do projeto]

middlewares.py

Existem dois tipos de middlewares no Scrapy: middlewares downloader e middlewares spider.

Os middlewares de download são componentes que podem ser utilizados para modificar solicitações e respostas, tratar erros e implementar lógica de download personalizada. Eles estão situados entre o spider e o downloader do Scrapy.

Os middlewares Spider são componentes que podem ser utilizados para implementar uma lógica de processamento personalizada. Eles estão situados entre o motor e a aranha.

A concha de sucata

Antes de embarcarmos na excitante jornada de implementação do nosso scraper do Urban Dictionary, devemos primeiro familiarizar-nos com o Scrapy Shell. Esta consola interactiva permite-nos testar a nossa lógica de scraping e ver os resultados em tempo real. É como uma caixa de areia virtual onde podemos brincar e afinar a nossa abordagem antes de soltar a nossa Aranha na web. Confie em mim, isso vai poupar muito tempo e dor de cabeça a longo prazo. Então vamos nos divertir e conhecer o Scrapy Shell.

Abrir a concha

Para abrir o Scrapy Shell, primeiro terá de navegar para o diretório do seu projeto Scrapy no seu terminal. Depois, basta executar o seguinte comando:

shell scrapy

Isto irá abrir o Scrapy Shell e ser-lhe-á apresentado um prompt onde pode introduzir e executar comandos Scrapy. Também pode passar um URL como argumento para o comando da shell para recolher diretamente uma página web, desta forma:

scrapy shell <url>

Por exemplo:

shell scrapy https://www.urbandictionary.com/define.php?term=YOLO

Devolverá (no objeto de resposta) o html da página Web que contém as definições da palavra YOLO (no Urban Dictionary).

Em alternativa, depois de entrar na shell, pode utilizar o comando fetch para ir buscar uma página Web.

fetch('https://www.urbandictionary.com/define.php?term=YOLO')

Também pode iniciar a shell com o parâmetro nolog para que não mostre os registos:

shell do scrapy --nolog

Trabalhar com o shell

Neste exemplo, fui buscar o URL "https://www.urbandictionary.com/define.php?term=YOLO" e guardei o html no ficheiro test_output.html.

(scrapy_env) mihai@DESKTOP-0RN92KH:~/myproject$ scrapy shell --nolog

[s] Available Scrapy objects:

[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)

[s] crawler <scrapy.crawler.Crawler object at 0x7f1eef80f6a0>

[s] item {}

[s] settings <scrapy.settings.Settings object at 0x7f1eef80f4c0>

[s] Useful shortcuts:

[s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)

[s] fetch(req) Fetch a scrapy.Request and update local objects

[s] shelp() Shell help (print this help)

[s] view(response) View response in a browser

>>> response // response is empty

>>> fetch('https://www.urbandictionary.com/define.php?term=YOLO')

>>> response

<200 https://www.urbandictionary.com/define.php?term=Yolo>

>>> with open('test_output.html', 'w') as f:

... f.write(response.text)

...

118260

Agora, vamos inspecionar o ficheiro test_output.html e identificar os selectores de que precisamos para extrair os dados para o nosso scraper do Urban Dictionary.

imagem do blogue

Podemos observar isso:

  • Cada contentor de definição de palavras tem a classe "definition".
  • O significado da palavra encontra-se no interior da div com a classe "significado".
  • Os exemplos da palavra encontram-se no interior da div com a classe "example".
  • As informações sobre o autor e a data da publicação encontram-se na div com a classe "contributor".

Agora vamos testar alguns selectores no Scrapy Shell:

Para obter referências a todos os contentores de definição, podemos utilizar selectores CSS ou XPath:

Pode saber mais sobre os selectores XPath aqui: https://www.webscrapingapi.com/the-ultimate-xpath-cheat-sheet

definições = response.css('div.definition')
definições = response.xpath('//div[contains(@class, "definition")]')

Devemos extrair o significado, o exemplo e a informação de publicação de cada contentor de definição. Vamos testar alguns selectores com o primeiro contentor:

>>> first_def = definitions[0]

>>> meaning = first_def.css('div.meaning').xpath(".//text()").extract()

>>> meaning

['Yolo ', 'means', ', '', 'You Only Live Once', ''.']

>>> meaning = "".join(meaning)

>>> significado

'Yolo significa, 'Só se vive uma vez'.'

>>> exemplo = first_def.css('div.example').xpath(".//text()").extract()

>>> exemplo = "".join(example)

>>> exemplo

'"Põe o cinto de segurança." Jessica disse.\r "HAH, YOLO!" Responde a Anna.\r(Depois, têm um acidente de carro. Resumindo... Usa o cinto de segurança.)'

>>> post_data = first_def.css('div.contributor').xpath(".//text()").extract()

>>> post_data

['by ', 'Soy ugly', ' April 24, 2019']

Ao utilizar o shell Scrapy, conseguimos encontrar rapidamente um seletor geral que se adequa às nossas necessidades.

definition.css('div.<meaning|example|contributor>').xpath(".//text()").extract() 

// returns an array with all the text found inside the <meaning|example|contributor>

ex: ['Yolo ', 'means', ', '', 'You Only Live Once', ''.']

Para saber mais sobre os selectores Scrapy, consulte a documentação. https://docs.scrapy.org/en/latest/topics/selectors.html

Implementar o scraper do Urban Dictionary

Bom trabalho! Agora que já apanhou o jeito de usar o Scrapy Shell e compreende o funcionamento interno de um projeto Scrapy, está na altura de mergulhar na implementação do nosso scraper Urban Dictionary. Por esta altura, já se deve sentir confiante e pronto para assumir a tarefa de extrair todas aquelas definições de palavras hilariantes (e por vezes questionáveis) da web. Então, sem mais delongas, vamos começar a construir nosso coletor de dados!

Definição de um item

Primeiro, vamos implementar um Item: (veja items.py)

class UrbanDictionaryItem(scrapy.Item):

meaning = scrapy.Field()

author = scrapy.Field()

date = scrapy.Field()

example = scrapy.Field()

Esta estrutura conterá os dados extraídos da Spider.

Definição de uma aranha

É assim que vamos definir a nossa Aranha (ver /spiders):

importar scrapy

from ..items import UrbanDictionaryItem

classe UrbanDictionarySpider(scrapy.Spider):

nome = "urban_dictionary" (dicionário urbano)

start_urls = ['https://www.urbandictionary.com/define.php?term=Yolo']

def parse(self, response):

definições = response.css('div.definition')

para definição em definições:

item = UrbanDictionaryItem()

item['meaning'] = definition.css('div.meaning').xpath(".//text()").extract()

item['example'] = definition.css('div.example').xpath(".//text()").extract()

author = definition.css('div.contributor').xpath(".//text()").extract()

item['data'] = autor[2]

item['autor'] = autor[1]

item de rendimento

Para executar o spider urban_dictionary, use o seguinte comando:

scrapy crawl urban_dictionary

// os resultados devem aparecer na consola (muito provavelmente no topo dos registos)

Criar um pipeline

Nesta altura, os dados não estão higienizados.

{'author': 'Soy ugly',

'date': ' April 24, 2019',

'example': ['“Put your ',

'seatbelt',

' on.” Jessica said.\n',

'“HAH, YOLO!” Replies Anna.\n',

'(They then proceed to have a ',

'car crash',

'. ',

'Long story short',

'...Wear a seatbelt.)'],

'meaning': ['Yolo ', 'means', ', ‘', 'You Only Live Once', '’.']}

Queremos modificar os campos "example" e "meaning" para conter strings, não arrays. Para o fazer, vamos escrever um Pipeline (ver pipelines.py) que transformará os arrays em strings concatenando as palavras.

class SanitizePipeline:

def process_item(self, item, spider):

# Sanitize o campo 'meaning'

item['meaning'] = "".join(item['meaning'])

# Sanitize o campo 'example'

item['example'] = "".join(item['example'])



# Sanitize the 'date' field

item['date'] = item['date'].strip()

return item

//ex: ['Yolo ', 'means', ', '', 'You Only Live Once', ''.'] turns to

'Yolo significa, 'You Only Live Once'.'

Ativar o Pipeline

Depois de definirmos o Pipeline, precisamos de o ativar. Se não o fizermos, então os nossos objectos UrbanDictionaryItem não serão higienizados. Para fazer isso, adicione-o ao seu arquivo settings.py (veja settings.py):

 ITEM_PIPELINES = {

'myproject.pipelines.SanitizePipeline': 1,

}

Enquanto isso, pode também especificar um ficheiro de saída para os dados extraídos serem colocados.

 FEEDS = {

'items': {'uri': 'file:///tmp/items.json', 'format': 'json'},

}

// this will put the scraped data in an items.json file.

Opcional: Implementação de um Middleware Proxy

A recolha de dados da Web pode ser um pouco complicada. Um dos principais problemas com que nos deparamos frequentemente é o facto de muitos sítios Web necessitarem de renderização de javascript para apresentarem totalmente o seu conteúdo. Isto pode causar enormes problemas para nós, enquanto web scrapers, uma vez que as nossas ferramentas muitas vezes não têm a capacidade de executar javascript como um navegador web normal faz. Isto pode levar a que sejam extraídos dados incompletos ou, pior ainda, que o nosso IP seja banido do sítio Web por fazer demasiados pedidos num curto período de tempo.

A nossa solução para este problema é o WebScrapingApi. Com o nosso serviço, pode simplesmente fazer pedidos à API e ela tratará de todo o trabalho pesado por si. Executará JavaScript, rodará proxies e até tratará de CAPTCHAs, assegurando que pode fazer scraping até dos sites mais teimosos com facilidade.

Um middleware proxy encaminhará cada pedido de busca feito pelo Scrapy para o servidor proxy. O servidor proxy então fará a requisição para nós e então retornará o resultado.

Primeiro, vamos definir uma classe ProxyMiddleware dentro do arquivo middlewares.py.

import base64

class ProxyMiddleware:

def process_request(self, request, spider):

# Set the proxy for the request

request.meta['proxy'] = "http://proxy.webscrapingapi.com:80"

request.meta['verify'] = False

# Set the proxy authentication for the request

proxy_user_pass = "webscrapingapi.proxy_type=residential.render_js=1:<API_KEY>"

encoded_user_pass = base64.b64encode(proxy_user_pass.encode()).decode()

request.headers['Proxy-Authorization'] = f'Basic {encoded_user_pass}'

Neste exemplo, utilizámos o servidor proxy WebScrapingApi.

webscrapingapi.proxy_type=residential.render_js=1 is the proxy authentication username, <API_KEY> the password.

Pode obter uma API_KEY gratuita criando uma nova conta em https://www.webscrapingapi.com/

Depois de definirmos o ProxyMiddleware, tudo o que precisamos de fazer é activá-lo como DOWNLOAD_MIDDLEWARE no ficheiro settings.py.

DOWNLOADER_MIDDLEWARES = {

'myproject.middlewares.ProxyMiddleware': 1,

}

E é isso. Como pode ver, a recolha de dados da Web com o Scrapy pode simplificar muito do nosso trabalho.

Concluir

Conseguimos! Construímos um scraper que pode extrair definições do Urban Dictionary e aprendemos muito sobre o Scrapy ao longo do caminho. Desde a criação de itens personalizados até à utilização de middlewares e pipelines, provámos o quão poderoso e versátil pode ser o web scraping com o Scrapy. E a melhor parte? Ainda há muito mais para descobrir.

Parabéns por ter chegado ao fim desta viagem comigo. Agora, deve sentir-se confiante na sua capacidade de enfrentar qualquer projeto de Web scraping que surja no seu caminho. Lembre-se de que a raspagem da Web não precisa de ser assustadora ou esmagadora. Com as ferramentas e os conhecimentos certos, pode ser uma experiência divertida e gratificante. Se alguma vez precisar de ajuda, não hesite em contactar-nos em https://www.webscrapingapi.com/. Sabemos tudo sobre web scraping e teremos todo o gosto em ajudá-lo de todas as formas possíveis.

Notícias e actualizações

Mantenha-se atualizado com os mais recentes guias e notícias sobre raspagem da Web, subscrevendo a nossa newsletter.

We care about the protection of your data. Read our <l>Privacy Policy</l>.Privacy Policy.

Artigos relacionados

miniatura
GuiasComo extrair dados de produtos da Amazon: Um guia abrangente de melhores práticas e ferramentas

Explore as complexidades da extração de dados de produtos da Amazon com nosso guia detalhado. De práticas recomendadas e ferramentas como a API Amazon Scraper a considerações legais, saiba como enfrentar desafios, contornar CAPTCHAs e extrair insights valiosos com eficiência.

Suciu Dan
avatar do autor
Suciu Dan
15 min. de leitura
miniatura
Ciência da recolha de dados da WebScrapy vs. Selenium: Um guia abrangente para escolher a melhor ferramenta de raspagem da Web

Explore a comparação aprofundada entre o Scrapy e o Selenium para raspagem da Web. Desde a aquisição de dados em grande escala até o tratamento de conteúdo dinâmico, descubra os prós, os contras e os recursos exclusivos de cada um. Saiba como escolher a melhor estrutura com base nas necessidades e na escala do seu projeto.

WebscrapingAPI
avatar do autor
WebscrapingAPI
14 min ler
miniatura
GuiasTutorial do Scrapy Splash: Dominando a arte de raspar sites renderizados em JavaScript com Scrapy e Splash

Aprenda a extrair sites dinâmicos renderizados em JavaScript usando o Scrapy e o Splash. Desde a instalação até à escrita de um spider, à manipulação da paginação e à gestão das respostas do Splash, este guia abrangente oferece instruções passo a passo tanto para principiantes como para especialistas.

Ștefan Răcila
avatar do autor
Ștefan Răcila
6 min. de leitura