Voltar ao blogue
Guias
Mihai MaximLast updated on Mar 31, 20268 min read

Analise HTML como um profissional: domine a extração de dados da Web com Python e expressões regulares

Analise HTML como um profissional: domine a extração de dados da Web com Python e expressões regulares

A quantidade de dados disponíveis na Internet tem vindo a aumentar nas últimas décadas. As pessoas utilizam esses dados para uma grande variedade de fins, desde interesses pessoais até à investigação empresarial.

No entanto, se esses dados não forem apresentados num formato específico, como XML ou JSON, pode ser difícil ou impossível lê-los através de aplicações de software. É aqui que entra a técnica de web scraping.

O web scraping é o processo de recolha e processamento de dados brutos da Internet. Estes dados são analisados e utilizados para diversos fins, tais como inteligência de preços, pesquisa de mercado, treino de modelos de IA, análise de sentimentos, auditorias de marca e auditorias de SEO.

Um dos aspetos-chave do web scraping é a análise de HTML. Isto pode ser feito utilizando uma variedade de ferramentas, tais como o BeautifulSoup para Python, o Cheerio para NodeJS e o Nokogiri para Ruby.

As expressões regulares (regex) são uma sequência de caracteres que definem um padrão de pesquisa.

Neste artigo, exploraremos como analisar um documento HTML utilizando regex e Python. Discutiremos também alguns dos desafios e soluções alternativas associados ao web scraping.

No final do artigo, terá uma compreensão abrangente do tema e das diferentes ferramentas e técnicas disponíveis.

Análise básica de regex

A maioria das linguagens de programação de uso geral suporta regex. Pode utilizar regex numa ampla variedade de linguagens de programação, incluindo Python, C, C++, Java, Rust, OCaml e JavaScript.

Eis como se apresenta uma regra de expressão regular para extrair o valor da tag <title>:

<title>(.*?)</title>

Assustador, não é? Tenha em mente que isto é apenas o começo. Em breve, vamos mergulhar mais fundo no assunto.

Para este artigo, estou a usar o Python 3.11.1. Vamos pegar nesta regra e transformá-la em código. Crie um ficheiro chamado main.py e cole este trecho:

import re

html = "<html><head><title>Scraping</title></head></html>"

title_search = re.search("<title>(.*?)</title>", html)

title = title_search.group(1)

print(title)

Pode executar este código através do comando `python main.py`. O resultado que verá como saída é a palavra “Scraping”.

Neste exemplo, estamos a usar o módulo `re` para trabalhar com expressões regulares. A função `re.search()` procura um padrão específico dentro de uma string. O primeiro argumento é o padrão de expressão regular e o segundo argumento é a string na qual estamos a pesquisar.

O padrão de expressão regular neste exemplo é "<title>(.*?)</title>". É composto por várias partes:

  • <title>: Esta é uma cadeia de caracteres literal, que corresponderá exatamente aos caracteres “<title>”.
  • (.*?): Este é um grupo de captura, denotado por parênteses. O caractere . corresponde a qualquer caractere único (exceto uma nova linha), e o quantificador * significa corresponder a 0 ou mais do caractere precedente. Além disso, ? torna o * não-greedy, o que significa que irá parar assim que encontrar a tag de fecho.
  • </title>: Esta é também uma cadeia literal, que corresponderá exatamente aos caracteres "</title>".

A função re.search() retorna um objeto de correspondência se for encontrada uma correspondência, e o método group(1) é usado para extrair o texto correspondido pelo primeiro grupo de captura, que é o texto entre as tags de abertura e fechamento do título.

Este texto será atribuído à variável title, e a saída será "Scraping".

Análise avançada de expressões regulares

Extrair os dados de uma única tag HTML não é muito útil. Dá-lhe uma ideia do que pode fazer com expressões regulares, mas não pode usá-la numa situação real.

Vamos dar uma vista de olhos no site do PyPI, o Índice de Pacotes Python. Na página inicial, são apresentadas quatro estatísticas: o número de projetos, o número de lançamentos, o número de ficheiros e o número de utilizadores.

Queremos extrair o número de projetos. Para o fazer, podemos usar esta expressão regular:

([0-9,]+) projects

A expressão regular irá corresponder a qualquer cadeia de caracteres que comece com um ou mais dígitos, opcionalmente separados por vírgulas, e termine com a palavra «projects». É assim que funciona:

  • ([0-9,]+): Este é um grupo de captura, indicado pelos parênteses; os colchetes [0-9,] correspondem a qualquer dígito de 0 a 9 e ao caractere `,`; o quantificador + significa corresponder a 1 ou mais do caractere precedente.
  • projects: Esta é uma cadeia literal, que corresponderá exatamente a "projects".

É hora de testar a regra. Atualize o código `main.py` com este trecho:

import urllib.request

import re

response = urllib.request.urlopen("https://pypi.org/")

html = response.read().decode("utf-8")

matches = re.search("([0-9,]+) projects", html)

projects = matches.group(1)

print(projects)

Estamos a utilizar o método urlopen da biblioteca urllib para fazer um pedido GET ao site pypi.org. Lemos a resposta na variável html. Aplicamos a regra regex ao conteúdo HTML e imprimimos o primeiro grupo correspondente.

Execute o código com o comando `python main.py` e verifique o resultado: ele exibirá o número de projetos do site.

Agora que temos um scraper simples capaz de obter o documento HTML de um site, vamos brincar um pouco com o código.

Podemos extrair todos os links com esta regra:

href=[\'"]?([^\'" >]+)

Esta expressão regular é composta por várias partes:

  • href=: esta é uma cadeia de caracteres literal, que corresponderá exatamente aos caracteres "href=".
  • [\'"]?: os parênteses retos [] correspondem a qualquer caractere único dentro deles, neste caso, os caracteres ' ou "; o quantificador ? significa corresponder a zero ou um dos caracteres precedentes, o que significa que o valor href pode estar entre " ou ' ou nenhum.
  • ([^\'" >]+): este é um grupo de captura, denotado pelos parênteses; o ^ dentro dos colchetes significa negação, irá corresponder a qualquer caractere que não seja ', ", > ou um espaço; o quantificador + significa corresponder a 1 ou mais do caractere precedente, o que significa que o grupo irá capturar um ou mais caracteres que correspondam ao padrão.

Extrair imagens

Mais uma coisa e estamos quase a terminar de escrever as regras de regex: precisamos de extrair as imagens. Vamos usar esta regra:

<img.*?src="(.*?)"

Esta expressão regular consiste em várias partes:

  • <img: Esta é uma cadeia literal, que corresponderá exatamente aos caracteres "<img".
  • .*?: o .* corresponde a qualquer caractere (exceto uma nova linha) 0 ou mais vezes, e o quantificador ? significa corresponder ao menor número possível do caractere anterior; isto é usado para corresponder a qualquer caractere que apareça antes do atributo src na tag <img>, e permite que o padrão corresponda a qualquer tag <img>, independentemente do número de atributos que tenha.
  • src=": esta é uma cadeia literal, que corresponderá exatamente aos caracteres "src=".
  • (.*?): isto é um grupo de captura, denotado pelos parênteses; o .*? corresponde a qualquer caractere (exceto uma nova linha) 0 ou mais vezes, e o quantificador ? significa corresponder ao menor número possível do caractere precedente; este grupo captura o valor src da tag <img>.
  • ": esta é uma string literal, irá corresponder exatamente ao caractere ".

Vamos testar isto. Substitua o trecho de código anterior por este:

import urllib.request

import re

response = urllib.request.urlopen("https://pypi.org/")

html = response.read().decode("utf-8")

images = re.findall('<img.*?src="(.*?)"', html)

print(*images, sep = "\n")

A saída deste código irá apresentar uma lista com todos os links de imagens da página do Pypi.

Limitações

O web scraping com expressões regulares pode ser uma ferramenta poderosa para extrair dados de sites, no entanto, também tem as suas limitações. Um dos principais problemas com a utilização de regex para web scraping é que pode falhar quando a estrutura do HTML muda.

Por exemplo, considere o seguinte exemplo de código, onde estamos a tentar extrair o texto do h2 usando regex:

<html>

   <head>

       <title>Example Title</title>

   </head>

   <body>

       <h1>Page Title</h1>

       <p>This is a paragraph under the title</p>

       <h2>First Subtitle</h2>

       <p>First paragraph under the subtitle</p>

       <h2>Second Subtitle</p>

   </body>

</html>

Compare a primeira tag <h2> com a segunda. Poderá notar que a segunda tag <h2> não está devidamente fechada e que o código tem </p> em vez de </h2>. Vamos atualizar o trecho com isto:

import re

html = "<html><head><title>Example Title</title></head><body><h1>Page Title</h1><p>This is a paragraph under the title</p><h2>First Subtitle</h2><p>First paragraph under the subtitle</p><h2>Second Subtitle</p></body></html>"

headingTags = re.findall("<h2>(.*?)</h2>", html)

print(*headingTags, sep = "\n")

Vamos executar o código e verificar o resultado:

First Subtitle

Falta o texto da segunda tag de título. Isto acontece porque a regra de expressão regular não corresponde à tag de título não fechada.

Uma solução para este problema é utilizar uma biblioteca como a BeautifulSoup, que permite navegar e pesquisar na estrutura da árvore HTML, em vez de depender de expressões regulares. Com a BeautifulSoup, pode extrair o título de uma página web da seguinte forma:

from bs4 import BeautifulSoup

html = "<html><head><title>Example Title</title></head><body><h1>Page Title</h1><p>This is a paragraph under the title</p><h2>First Subtitle</h2><p>First paragraph under the subtitle</p><h2>Second Subtitle</p></body></html>"

soup = BeautifulSoup(html, 'html.parser')

for headingTag in soup.findAll('h2'):

   print(headingTag.text)

O BeautifulSoup consegue extrair tags malformadas e o resultado fica assim:

First Subtitle

Second Subtitle

Esta abordagem é mais robusta face a alterações na estrutura HTML, uma vez que não depende de padrões específicos no código HTML. Se estiver interessado em saber mais sobre o BeautifulSoup, este artigo é a leitura perfeita.

Outra solução é utilizar uma API de web scraping, como a WebScrapingAPI, que simplifica as complexidades do web scraping e permite extrair facilmente os dados de que necessita sem se preocupar com a estrutura HTML subjacente.

Com a WebScrapingAPI, pode extrair dados de qualquer site com uma simples chamada de API, e esta lida automaticamente com alterações na estrutura HTML.

Considerações finais

A análise de dados com expressões regulares pode ser uma ferramenta poderosa para extrair dados de sites.

Neste artigo, discutimos os conceitos básicos das expressões regulares, como utilizá-las para analisar HTML e alguns dos desafios que poderá encontrar ao utilizá-las. Também vimos como bibliotecas como a BeautifulSoup podem ser utilizadas como solução alternativa.

Aprendeu a extrair dados de páginas web utilizando expressões regulares e a melhorar a fiabilidade do seu código utilizando uma biblioteca mais robusta, como a BeautifulSoup.

O web scraping pode ser uma tarefa demorada, mas com as ferramentas certas, pode ser fácil e eficiente. Se procura uma solução de web scraping que lhe poupe tempo e esforço, experimente a WebScrapingAPI.

Oferecemos um período de teste gratuito de 14 dias, durante o qual poderá testar o nosso serviço e ver as vantagens de utilizar uma API de web scraping.

Sobre o autor
Mihai Maxim, Desenvolvedor Full Stack @ WebScrapingAPI
Mihai MaximDesenvolvedor Full Stack

Mihai Maxim é um programador Full Stack na WebScrapingAPI, contribuindo em todas as áreas do produto e ajudando a criar ferramentas e funcionalidades fiáveis para a plataforma.

Comece a construir

Pronto para expandir a sua recolha de dados?

Junte-se a mais de 2.000 empresas que utilizam a WebScrapingAPI para extrair dados da Web à escala empresarial, sem quaisquer custos de infraestrutura.