Analisar HTML como um profissional: Dominando o Web Scraping com Python e Regex

Suciu Dan em 13 de abril de 2023

imagem do blogue

A quantidade de dados disponíveis na Internet tem vindo a aumentar nas últimas décadas. Os seres humanos consomem estes dados para uma grande variedade de objectivos, desde interesses pessoais a investigação empresarial.

No entanto, se estes dados não forem devolvidos de uma forma formatada, 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 raspagem da Web.

A raspagem da Web é o processo de recolha e processamento de dados brutos da Internet. Estes dados são analisados e utilizados para uma variedade de fins, tais como inteligência de preços, estudos de mercado, modelos de IA de treino, análise de sentimentos, auditorias de marcas e auditorias de SEO.

Um dos principais aspectos da raspagem da Web é a análise de HTML. Isso pode ser feito usando uma variedade de ferramentas, como BeautifulSoup para Python, Cheerio para NodeJS e Nokogiri para Ruby.

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

Neste artigo, vamos explorar como analisar um documento HTML usando regex e Python. Também discutiremos alguns dos desafios e soluções alternativas que acompanham a raspagem da Web.

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. É possível utilizar regex numa grande variedade de linguagens de programação, incluindo Python, C, C++, Java, Rust, OCaml e JavaScript.

Here’s what a regex rule for extracting the value from the <title> tag looks like:

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

Assustador, não é? Lembrem-se que isto é o início. Em breve, vamos entrar na toca do coelho.

Para este artigo, estou a usar Python 3.11.1. Vamos pegar nesta regra e pô-la em código. Cria um ficheiro chamado main.py e cola este excerto:

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 com o comando `python main.py`. O resultado que verá como saída é a palavra "Scraping".

Neste exemplo, estamos utilizando o módulo `re` para trabalhar com regex. A função `re.search()` procura por um padrão específico dentro de uma string. O primeiro argumento é o padrão regex, e o segundo argumento é a string na qual estamos pesquisando.

The regex pattern in this example is "<title>(.*?)</title>". It consists of several parts:

  • <title>: This is a literal string, it will match the characters "<title>" exactly.
  • (.*?): 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 anterior. Além disso, ? faz com que o * não seja ganancioso, o que significa que ele irá parar assim que encontrar a tag de fechamento.
  • </title>: This is also a literal string, it will match the characters "</title>" exactly.

A função re.search() devolve um objeto de correspondência se for encontrada uma correspondência, e o método group(1) é utilizado para extrair o texto correspondente ao primeiro grupo de captura, que é o texto entre as etiquetas de título de abertura e de fecho.

Este texto será atribuído à variável title, e o resultado será "Scraping".

Análise avançada de Regex

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

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

Queremos extrair o número de projectos. Para o conseguir, podemos utilizar este regex:

([0-9,]+) projectos

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

  • ([0-9,]+): Este é um grupo de captura, denotado pelos parênteses; os parênteses rectos [0-9,] correspondem a qualquer dígito de 0 a 9 e ao carácter `,`; o quantificador + significa corresponder a 1 ou mais do carácter anterior.
  • projectos: Trata-se de uma cadeia literal, que corresponderá exatamente a "projects".

É hora de colocar a regra em teste. 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. Executamos a regra regex no conteúdo HTML e imprimimos o primeiro grupo correspondente.

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

Extração de ligações

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

Podemos extrair todas as ligações com esta regra:

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

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

  • href=: trata-se de uma cadeia literal, que corresponderá exatamente aos caracteres "href=".
  • [\'"]?: os parêntesis rectos [] correspondem a qualquer carácter individual no seu interior, neste caso, os caracteres ' ou "; o quantificador ? significa corresponder a zero ou a um dos caracteres anteriores, o que significa que o valor do href pode ser delimitado por " ou ' ou nenhum.
  • ([^\'" >]+): trata-se de um grupo de captura, denotado pelos parênteses; o ^ dentro dos parênteses rectos significa negação, corresponderá a qualquer carácter que não seja um ',",>, ou um espaço; o quantificador + significa corresponder a 1 ou mais do carácter precedente, significa que o grupo irá capturar um ou mais caracteres que correspondam ao padrão.

Extração de imagens

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

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

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

  • <img: This is a literal string, it will match the characters "<img" exactly.
  • .*?: the .* match any character (except a newline) 0 or more times, and the ? quantifier means to match as few as possible of the preceding character; this is used to match any character that appears before the src attribute in the <img> tag, and it allows the pattern to match any <img> tag regardless of the number of attributes it has.
  • src=": trata-se de uma cadeia literal, que corresponderá exatamente aos caracteres "src=".
  • (.*?): this is a capturing group, denoted by the parentheses; the .*? match any character (except a newline) 0 or more times, and the ? quantifier means to match as few as possible of the preceding character; this group captures the src value of the <img> tag.
  • ": trata-se de uma cadeia literal, que corresponderá exatamente ao carácter ".

Vamos pô-lo à prova. Substitua o código do snippet 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")

O resultado deste código apresentará uma lista com todas as ligações de imagens da página Pypi.

Limitações

O Web scraping com expressões regulares pode ser uma ferramenta poderosa para extrair dados de sítios Web, no entanto, também tem as suas limitações. Um dos principais problemas com a utilização de regex para a recolha de dados da Web é o facto de poder falhar quando a estrutura do HTML muda.

Por exemplo, considere o seguinte exemplo de código em que estamos a tentar extrair o texto do h2 utilizando 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 the first <h2> tag with the second one. You may notice the second <h2> is not properly closed, and the code has </p> instead of </h2>. Let’s update the snippet with this:

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:

Primeira legenda

O texto da segunda etiqueta de cabeçalho está em falta. Isto acontece porque a regra regex não está a corresponder à etiqueta de título não fechada.

Uma solução para este problema é utilizar uma biblioteca como a BeautifulSoup, que lhe permite navegar e pesquisar a estrutura em árvore do HTML, em vez de se basear em expressões regulares. Com a BeautifulSoup, pode extrair o título de uma página Web desta 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 as etiquetas malformadas e o resultado é o seguinte:

Primeiro Subtítulo

Segundo Subtítulo

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

Outra solução é utilizar uma API de raspagem da Web, como a WebScrapingAPI, que abstrai as complexidades da raspagem da Web e permite-lhe extrair facilmente os dados de que necessita sem se preocupar com a estrutura HTML subjacente.

Com o WebScrapingAPI, pode extrair dados de qualquer sítio Web com uma simples chamada à API, que trata automaticamente as 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 sítios Web.

Neste artigo, discutimos os conceitos básicos das expressões regulares, como usá-las para analisar HTML e alguns dos desafios que você pode encontrar ao usá-las. Também vimos como bibliotecas como BeautifulSoup podem ser usadas como uma 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 morosa, mas com as ferramentas certas, pode ser fácil e eficiente. Se estiver à procura de uma solução de Web scraping que lhe poupe tempo e esforço, experimente o WebScrapingAPI.

Oferecemos uma avaliação gratuita durante 14 dias, onde pode testar o nosso serviço e ver as vantagens de utilizar uma API de raspagem da Web.

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
Casos de utilizaçãoLibertar o poder dos dados financeiros: Explorando dados tradicionais e alternativos

Mergulhe no papel transformador dos dados financeiros na tomada de decisões empresariais. Compreender os dados financeiros tradicionais e a importância emergente dos dados alternativos.

Suciu Dan
avatar do autor
Suciu Dan
8 min. de leitura
miniatura
Ciência da recolha de dados da WebWeb Scraping facilitado: a importância da análise de dados

Descubra como extrair e organizar eficientemente dados para raspagem da Web e análise de dados através de análise de dados, bibliotecas de análise de HTML e metadados schema.org.

Suciu Dan
avatar do autor
Suciu Dan
12 min ler
miniatura
Casos de utilizaçãoXPath vs. seletores CSS

Os selectores XPath são melhores do que os selectores CSS para a recolha de dados da Web? Conheça os pontos fortes e as limitações de cada método e faça a escolha certa para o seu projeto!

Mihai Maxim
avatar do autor
Mihai Maxim
8 min. de leitura