Voltar ao blogue
Guias
Mihai Maxim31 de janeiro de 20237 min de leitura

Parsel: Como extrair texto de HTML em Python

Parsel: Como extrair texto de HTML em Python

Introdução

O web scraping é o processo automatizado de recolha de dados de sites através da utilização de um script ou programa. É utilizado para extrair informações como texto, imagens e outros tipos de dados que podem ser úteis para diversos fins, tais como investigação, análise de dados ou análise de mercado.

Hoje em dia, existem inúmeras soluções para a extração de dados da Web com Python. O Selenium e o Scrapy são algumas das bibliotecas mais utilizadas e populares. Embora estas ferramentas sejam excelentes para tarefas complexas de extração de dados, podem revelar-se um pouco complicadas para uma utilização ocasional.

Apresentamos o Parsel, uma pequena biblioteca de scraping. Esta biblioteca leve e fácil de aprender é perfeita para projetos de pequena dimensão e é ideal para quem está a dar os primeiros passos no scraping na Web. É capaz de analisar HTML e extrair dados utilizando seletores CSS e XPath, tornando-a uma excelente ferramenta para qualquer entusiasta de dados que procure uma forma rápida e fácil de recolher informações da Web.

Apertem os cintos e preparem-se para aprender a usar esta biblioteca enquanto me acompanham nesta aventura de recolha automatizada de dados. Vamos começar a extrair dados!

Introdução ao Parsel

Pode instalar a biblioteca Parsel com:

pip install parsel

Vamos agora passar diretamente a um projeto de exemplo e extrair todos os dados relativos aos países deste site simples: https://www.scrapethissite.com/pages/simple/.

Para obter o código HTML do site, terá de efetuar um pedido HTTP GET.

Vamos efetuar pedidos HTTP com a biblioteca «requests» do Python, por isso certifique-se de que a instala com:

pip install requests

Agora pode obter o código HTML e guardá-lo num ficheiro:

import parsel 

import requests

response = requests.get("https://www.scrapethissite.com/pages/simple/")

with open("out.html", "w", encoding="utf-8") as f:

   f.write(response.text)

E analise a estrutura:

Editor de código que mostra a marcação HTML dos cartões de países com campos relativos à capital, população e área

Os nossos dados são armazenados em estruturas semelhantes a esta:

<div class="col-md-4 country">

   <h3 class="country-name">

       <i class="flag-icon flag-icon-af"></i>

       Afghanistan

   </h3>

   <div class="country-info">

       <strong>Capital:</strong> <span class="country-capital">Kabul</span><br>

       <strong>Population:</strong> <span class="country-population">29121286</span><br>

       <strong>Area (km<sup>2</sup>):</strong> <span class="country-area">647500.0</span><br>

   </div>

</div><!--.col-->

Para escrever seletores, terá de passar o código HTML bruto ao Parsel:

import parsel

import requests

response = requests.get("https://www.scrapethissite.com/pages/simple/")

raw_html = response.text

parsel_dom = parsel.Selector(text = raw_html)

Agora estamos prontos para escrever alguns seletores.

Extrair texto utilizando seletores CSS

Pode imprimir a capital do primeiro país com:

parsel_dom = parsel.Selector(text=raw_html)

first_capital = parsel_dom.css(".country-capital::text").get()

print(first_capital)

// Resultado

Andorra-a-Velha
parsel_dom.css(".country-capital::text").get() selecionará o texto interno do primeiro elemento que tenha a classe "country-capital".

Pode imprimir todos os nomes dos países com:

countries_names = filter(lambda line: line.strip() != "", parsel_dom.css(".country-name::text").getall())

for country_name in countries_names:

   print(country_name.strip())

// Resultado

Andorra

Emirados Árabes Unidos

Afeganistão

Antígua e Barbuda

Anguilla

. . .
parsel_dom.css(".country-name::text").getall() irá selecionar os textos internos de todos os elementos que tenham a classe "country-name". 

Notice that we had to clean-up the output a bit. We did that because all the elements that have the “.country-name” class also have an <i> tag nested inside of them. Also, the country name is surrounded by many trailing spaces.

<h3 class="country-name">

 <i class="flag-icon flag-icon-ae"></i> //this is picked up as an empty string

  United Arab Emirates // this is picked up as “  United Arab Emirates  “

</h3>

Agora vamos escrever um script para extrair todos os dados com seletores CSS:

import parsel

import requests

response = requests.get("https://www.scrapethissite.com/pages/simple/")

raw_html = response.text

parsel_dom = parsel.Selector(text=raw_html)

countries = parsel_dom.css(".country")

countries_data = []

for country in countries:

  country_name = country.css(".country-name::text").getall()[1].strip()

  country_capital = country.css(".country-capital::text").get()

  country_population = country.css(".country-population::text").get()

  country_area = country.css(".country-area::text").get()

  countries_data.append({

     "name": country_name,

     "capital": country_capital,

     "population": country_population,

     "area": country_area

  })

for country_data in countries_data:

  print(country_data)

// Outputs

{'name': 'Andorra', 'capital': 'Andorra la Vella', 'population': '84000', 'area': '468.0'}

{'name': 'United Arab Emirates', 'capital': 'Abu Dhabi', 'population': '4975593', 'area': '82880.0'}

{'name': 'Afghanistan', 'capital': 'Kabul', 'population': '29121286', 'area': '647500.0'}

... 

Extrair texto utilizando seletores XPath

O XPath é uma linguagem de consulta para selecionar nós de um documento XML. É a sigla de XML Path Language e utiliza uma notação de caminho semelhante à dos URLs para navegar pelos elementos e atributos de um documento XML. As expressões XPath podem ser utilizadas para selecionar um único elemento, um conjunto de elementos ou um atributo específico de um elemento. O XPath é utilizado principalmente em XSLT, mas também pode ser utilizado para navegar pelo Modelo de Objetos de Documento (DOM) de qualquer documento em linguagem semelhante a XML, como HTML ou SVG.

O XPath pode parecer intimidante à primeira vista, mas, na verdade, é bastante fácil começar a utilizá-lo assim que se compreendem os conceitos básicos e a sintaxe. Um recurso que pode ser útil é o nosso guia de seletores XPath, disponível em https://www.webscrapingapi.com/the-ultimate-xpath-cheat-sheet.

Agora vamos experimentar alguns seletores:

Veja como pode imprimir a primeira letra maiúscula:

parsel_dom = parsel.Selector(text=raw_html)

first_capital = parsel_dom.xpath('//*[@class="country-capital"]/text()').get()

print(first_capital)

// Resultado

Andorra-a-Velha

E todos os nomes dos países:

countries_names = filter(lambda line: line.strip() != "", 

parsel_dom.xpath('//*[@class="country-name"]//text()').getall())

for country_name in countries_names:

  print(country_name.strip())

// Saída

Andorra-a-Velha

Abu Dhabi

Cabul

St. John's

The Valley

Tirana

...

Vamos reescrever o script utilizando seletores XPath:

import parsel

import requests

response = requests.get("https://www.scrapethissite.com/pages/simple/")

raw_html = response.text

parsel_dom = parsel.Selector(text=raw_html)

countries = parsel_dom.xpath('//div[contains(@class,"country")][not(contains(@class,"country-"))]')

countries_data = []

for country in countries:

 country_name = country.xpath(".//h3/text()").getall()[1].strip()

 country_capital = country.xpath(".//span/text()").getall()[0]

 country_population = country.xpath(".//span/text()").getall()[1]

 country_area = country.xpath(".//span/text()").getall()[2]

 countries_data.append({

    "name": country_name,

    "capital": country_capital,

    "population": country_population,

    "area": country_area

 })

for country_data in countries_data:

 print(country_data)

// Output

{'name': 'Andorra', 'capital': 'Andorra la Vella', 'population': '84000', 'area': '468.0'}

{'name': 'United Arab Emirates', 'capital': 'Abu Dhabi', 'population': '4975593', 'area': '82880.0'}

{'name': 'Afghanistan', 'capital': 'Kabul', 'population': '29121286', 'area': '647500.0'}

...

Remover elementos

Remover elementos é simples. Basta aplicar a função `drop` a um seletor:

selector.css(".my_class").drop()

Vamos demonstrar esta funcionalidade escrevendo um script que remova o campo «população» de cada país:

import parsel

import requests

response = requests.get("https://www.scrapethissite.com/pages/simple/")

raw_html = response.text

parsel_dom = parsel.Selector(text=raw_html)

countries = parsel_dom.css(".country")

for country in countries:

 country.css(".country-population").drop()

 country.xpath(".//strong")[1].drop()

 country.xpath(".//br")[1].drop()

countries_without_population_html = parsel_dom.get()

with open("out.html", "w", encoding="utf-8") as f:

  f.write(countries_without_population_html)
Página web que apresenta uma lista de países com os valores relativos à capital e à área, num layout com várias colunas

Exportar os dados

Quando terminar de extrair os dados, é importante pensar na forma como pretende guardá-los. Dois formatos comuns para armazenar este tipo de dados são o .json e o .csv. No entanto, deve escolher aquele que melhor se adequa às necessidades do seu projeto.

Exportar os dados para o formato .json

O JSON (JavaScript Object Notation) é um formato leve de intercâmbio de dados, fácil de ler e escrever para os utilizadores e fácil de analisar e gerar para as máquinas. É frequentemente utilizado para a troca de dados entre uma aplicação web e um servidor, ou entre diferentes partes de uma aplicação web. O JSON é semelhante a um dicionário Python, na medida em que é utilizado para armazenar dados em pares chave-valor, e pode ser utilizado para armazenar e aceder ao mesmo tipo de dados e ter a mesma estrutura.

É possível exportar uma matriz de dicionários Python para o formato .json utilizando a biblioteca json:

import json

countries_dictionaries = [

{'name': 'Andorra', 'capital': 'Andorra la Vella', 'population': '84000', 'area': '468.0'},

{'name': 'United Arab Emirates', 'capital': 'Abu Dhabi', 'population': '4975593', 'area': '82880.0'}

]

json_data = json.dumps(countries_dictionaries, indent=4)

with open("data.json", "w") as outfile:

   outfile.write(json_data)

// data.json

[

   {

       "name": "Andorra",

       "capital": "Andorra la Vella",

       "population": "84000",

       "area": "468.0"

   },

   {

       "name": "United Arab Emirates",

       "capital": "Abu Dhabi",

       "population": "4975593",

       "area": "82880.0"

   }

]

Exportar os dados para um ficheiro .csv

Um CSV é uma forma simples de armazenar dados num ficheiro de texto, em que cada linha representa uma entrada e cada valor é separado por uma vírgula. É frequentemente utilizado em programas de folhas de cálculo ou bases de dados. O Python possui um excelente suporte integrado para trabalhar com ficheiros CSV, através do seu módulo csv. Uma das funcionalidades mais poderosas do módulo CSV é a classe DictWriter, que permite gravar um dicionário Python num ficheiro CSV de forma simples. As chaves do dicionário serão utilizadas como cabeçalhos de coluna no ficheiro CSV, e os valores serão gravados como os dados correspondentes nas linhas.

Veja aqui como pode utilizar a biblioteca csv para exportar uma matriz de dicionários Python para um ficheiro .csv.

countries_dictionaries = [

{"name": "John Smith", "age": 35, "city": "New York"},

{"name": "Jane Doe", "age": 28, "city": "San Francisco"}

]

with open("data.csv", "w") as outfile:

   writer = csv.DictWriter(outfile, fieldnames=countries_dictionaries[0].keys())

   writer.writeheader()

   for row in countries_dictionaries:

       writer.writerow(row)

// data.csv

name,age,city

John Smith,35,New York

Jane Doe,28,San Francisco

Concluir

Neste artigo, explorámos a utilização da biblioteca Parsel em Python. Vimos como é fácil utilizar os seletores CSS e XPath que a Parsel disponibiliza para extrair dados de páginas web. Em geral, a Parsel oferece uma solução eficiente e versátil para a extração de dados da web. Se estiver interessado em automatizar a recolha de dados, deve definitivamente experimentá-la.

Quer saber mais sobre web scraping? Conheça o nosso produto, o WebScrapingAPI, e descubra como pode levar as suas competências em extração de dados para o próximo nível. A nossa poderosa API foi especificamente concebida para o ajudar a superar os desafios mais comuns do web scraping, como evitar bloqueios de IP ou a execução de Javascript. E o melhor de tudo? Pode experimentá-la gratuitamente!

Sobre o autor
Mihai Maxim, Desenvolvedor Full Stack na 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.