PythonDS: Data Science no Python e mais...

Python, Micropython, C, Arduino, ESP-8266, Raspberry Pi e outras aventuras tecno-nerds

Logo Python

Web Scraping com Python

Web scraping é uma técnica para varrer a web em busca de informações de seu interesse. Esse artigo aborda o uso de Python e das bibliotecas Requests e BeautifulSoup para criar robôs que executem esta missão.

1. Capturando conteúdo web: O primeiro passo que se deve realizar é a captura de conteúdo de uma página web, para isso criaremos uma variável com a url da página, em seguida usaremos a biblioteca Requests para obter o conteúdo HTML original. Este último passo é realizado criando uma variável e atribuindo a ela o conteúdo retornado pela chamada ao método get da biblioteca requests.

>>> url = 'https://www.crummy.com/software/BeautifulSoup/'
>>> import requests
>>> page = requests.get(url)

Para conferir o resultado, pode-se verificar o tipo da variável, confirmando que se trata de um objeto do tipo 'requests.models.Response' ou chamando a variável page diretamente no Shell que retornará a resposta Response [200] caso a captura tenha sido bem sucedida.

>>> type(page)
<class 'requesets.models.Response'>
>>> page
<Response [200]>

2. Convertendo conteúdo HTML: O conteúdo da variável page, é acessado pelo atributo content (page.content), mas o retorno da função get é o material bruto da página, ou seja, o texto e todos os elementos HTML da página acessada. Isto ocorre, porque requests e suas funções não são exclusivas para web scraping, mas para acesso a conteúdo web de diversas formas, inclusive para processamento do conteúdo completo. Mas, como material em HTML no geral não tem utilidade para usuários finais que desejam ler o texto puro, precisamos de uma ferramenta adicional para tornar as coisas bonitas, para isso entra em cena a poderosa biblioteca Beautiful Soup, que faz a conversão, também conhecida como parser, do conteúdo, gerando um objeto <class 'bs4.BeautifulSoup'>, que organiza o conteúdo de maneira que facilmente se pode acessar tanto o conteúdo HTML quanto o conteúdo textual legível.
Nas linhas a seguir é importada a biblioteca e criada uma variável que recebe o retorno da função BeautifulSoup:

>>> from bs4 import BeautifulSoup
>>> page = BeautifulSoup(page.content, 'html.parser')

3. Capturando texto limpo: Com os dados já estruturados no objeto BeautifulSoup criado no passo anterior é possível acessá-los, exbí-los na tela, armazená-los em variáveis e salvá-los em arquivos ou bancos de dados, conforme as necessidades de cada projeto.
Estas ações, quando o conteúdo original proveio de uma página HTML, são feitas a partir das referências às tags (elementos) HTML. Por exemplo para buscar conteúdo de parágrafos usamos como referência a tag 'p', enquanto para capturar um título usamos 'h1'. A seguir são apresentados dois exemplos simples de tratamento do conteúdo de títulos e parágrafos, respectivamente:

>>> h1 = bs.find_all('h1')
>>> h1
[<h1>Beautiful Soup</h1>]

Veja que a captura, guardada na variável h1, ainda apresenta uma visualização estranha, similar ao retorno de uma lista tradicional de Python, mas se consultar o tipo com type(h1) perceberá que trata-se de um objeto bs4 <class 'bs4.element.ResultSet'>. Este tipo de objeto, guarda os resultados da busca por determinado elemento, e pode ser iterado para recuperar o conteúdo textual.
As linhas a seguir cumprem este objetivo, iterando o objeto h1 e capturando o texto de cada ocorrência com o método .get_text():

>>> titulos = [h1[k].get_text() for k in range(0, len(h1))]
>>> titulos
['BeautifulSoup']
>>> print(titulos[0])
BeautifulSoup

Retornando ao objeto bs que ainda está com o conteúdo completo da varredura, vamos usar novamente o método .find_all() para capturar os parágrafos representados pelo elemento 'p' e em seguida chamamos a função len() para para a variável criada, onde podemos verificar que foram capturados 25 parágrafos na página consultada.

>>> p = bs.find_all('p')
>>> len(p)
25

Se tentar exibido o conteúdo de um item do objeto p, por exemplo usando print(p[0]) será exibido o primeiro item, mas ainda com os elementos HTML. Para capturar os parágrafos limpos podemos usar a mesma lógica anterior, criando um lista a partir da iteração do conteúdo de p.

>>> paragrafos = [p[k].get_text() for k in range(0, len(p))]
>>> len(paragrafos)
25

4. Armazenando o conteúdo:Agora sim o conteúdo limpo dos parágrafos estará disponível e pode ser exibido na tela ou armazenado. Um único detalhe que pode ser tratado se for necessário é que ao capturar o texto os caracteres de quebra de linha ficam armazenados juntamente, o que pode ser visto na comparação da exibição na tela pela chamada direta de um dos itens da lista ou pela sua exibição com o comando print(), mas como esse não é um erro ou um elemento HTML esquecido, mas uma característica do texto original, sua remoção (por exemplo através do uso da função sub da biblioteca re é opcional e não está no escopo deste estudo).

>>> paragrafos[0]
"You didn't write that awful page. You're just trying to get some\ndata out of it.
Beautiful Soup is here to help. Since 2004, it's been\nsaving programmers hours or
days of work on quick-turnaround\nscreen scraping projects."
>>> print(paragrafos[0])
You didn't write that awful page. You're just trying to get some
data out of it. Beautiful Soup is here to help. Since 2004, it's been
saving programmers hours or days of work on quick-turnaround
screen scraping projects.

Com o conteúdo completo dos parágrafos na variável criada, o tratamento e armazenamento pode ser feito da maneira desejada pelo projeto específico. Para dar um exemplo de como podemos fazer isso, o código abaixo junta os parágrafos em um texto fluído e salva em um arquivo de texto.

>>> texto = '\n'.join(paragrafos[k] for k in range(0, len(paragrafos)))
>>> with open('scrap.txt', 'w') as arquivo:
print(f'Captura do site: {url}', file=arquivo)
print('=' * 100, file=arquivo)
print('Título:', file=arquivo, end='')
print(titulos[0], file=arquivo)
print('=' * 100, file=arquivo)
print('Conteúdo:', file=arquivo)
print(texto, file=arquivo)

Considerações finais: Este material apresenta apenas uma forma simplificada e direta de uso das bibliotecas estudadas para captura de dados de páginas web. Há diversas outras ações complementares que podem ser realizadas para expansão do conteúdo a ser pesquisado, conversão (parser) de outros formatos de conteúdo online como XML, Java Script, imagens, PDF, etc., além da possibilidade de uso destas técnicas de maneira incorporada a um programa com varredura programada, tratamento de erros, parametrização de tags e outros elementos a serem pesquisadas com base em estudo do conteúdo dos sites a serem consultados e dos objetivos do projeto específico.
Os links da documentação das bibliotecas e o material de referência indicado ao final ajudam a expansão do uso, cobrindo estes e outros aspectos que tornam o web scraping uma poderosa ferramenta em diversos contextos.

Referências

Bibliotecas Python utilizadas:

Biblioteca Documentação PyPi Página Oficial
BeautifulSoup pypi.org/project/beautifulsoup4 www.crummy.com/software/BeautifulSoup
Requests pypi.org/project/requests 2.python-requests.org

Livros e artigos sugeridos: