Artigo original: Web Scraping Python Tutorial – How to Scrape Data From A Website
O Python é uma linguagem linda de se programar. Com um ecossistema de pacotes maravilhoso, nela, há bem menos ruído que em outras linguagens, além de ser muito fácil de usar.
O Python pode ser usado para várias coisas – desde a análise de dados até a programação em back-end. Dentre todas as opções, uma das maneiras mais empolgantes de se usar o Python é o scraping (em português, algo como "raspagem" ou extração) de dados na web.
Neste artigo, abordaremos como utilizar a linguagem Python para fazer scraping na web. Também trabalharemos com uma aula prática e interativa, guiando você à medida que avançamos neste artigo.
Observação: faremos scraping em um site da web hospedado por mim. Assim, poderemos aprender a fazê-lo em segurança. Muitas empresas não permitem o scraping de dados em seus sites. Então, essa será uma boa maneira de aprender. Certifique-se de checar isso antes de começar um scraping de dados na web.
Introdução à aula de scraping de dados na web
Se você quiser programar em paralelo no decorrer deste artigo, pode usar esta aula no codedamn, que consiste em diversos laboratórios que ajudam você a fazer o scraping de dados. Será um exercício prático e interativo no codedamn, muito similar à maneira que você aprende no freeCodeCamp.
Nesta aula, você utilizará essa página para testar o scraping de dados:
https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/ (em inglês)
A aula é composta por sete laboratórios. Você resolverá o que há em cada um ao longo deste artigo. Usaremos o Python 3.8 e o BeautifulSoup 4 para o scraping de dados.
Parte 1: carregando páginas da web com 'request'
Este é o link deste laboratório.
O módulo requests
permite que você envie solicitações de HTTP usando o Python.
A solicitação de HTTP retorna um objeto response
com todos os dados de resposta (conteúdo, código, status e assim por diante). Aqui vai um exemplo ao pegar HTML de uma página:
import requests
res = requests.get('https://codedamn.com')
print(res.text)
print(res.status_code)
Requerimentos necessários:
- Pegar o conteúdo do URL a seguir usando o módulo
requests
: https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/ - Armazenar a resposta recebida (como demonstrado logo abaixo) em uma variável chamada
txt
- Armazenar o código do status (como demonstrado abaixo) em uma variável chamada
status
- Imprimir
txt
estatus
usando a funçãoprint
Uma vez que você esteja entendendo o que está acontecendo no código abaixo, será bastante simples para você completar este laboratório. Aqui está a solução para ele:
import requests
# Faça uma solicitação para https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/
# Armazene o resultado na variável 'res'
res = requests.get(
'https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/')
txt = res.text
status = res.status_code
# Imprima o resultado
print(txt, status)
Vamos prosseguir para a parte 2 agora. Nela, você poderá programar mais, aproveitando o código que já fez até o momento.
Parte 2: extraindo o título com BeautifulSoup
Este é o link para o laboratório.
Em toda esta lição, você usará uma biblioteca chamada BeautifulSoup
no Python para fazer o scraping de dados na web. Algumas funcionalidades que fazem o BeautifulSoup ser uma solução poderosa são:
- Fornecer muitos métodos simples e expressões "Pythônicas" para a navegação, pesquisa e modificação da árvore do DOM. Não é necessário programar muito para escrever uma aplicação.
- O BeautifulSoup fica no topo dos analisadores (do inglês, parsers) mais populares de Python, como lxml e html5lib, permitindo que você teste diferentes estratégias de análise ou que faça uma troca entre velocidade e flexibilidade.
Basicamente, o BeautifulSoup pode analisar qualquer coisa que tenha na página da web fornecida.
Aqui está um exemplo simples do BeautifulSoup:
from bs4 import BeautifulSoup
page = requests.get("https://codedamn.com")
soup = BeautifulSoup(page.content, 'html.parser')
title = soup.title.text # Obtém o texto que está entre as tags <title>(...)</title>
Requerimentos necessários:
- Utilizar o pacote
requests
para pegar o título do URL: https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/ - Utilizar o BeautifulSoup para armazenar o título dessa página dentro de uma variável chamada
page_title
Vendo o exemplo abaixo, você pode notar que, uma vez inserido o page.content
dentro do BeautifulSoup, você poderá começar a trabalhar com a análise da árvore do DOM de uma maneira bem típica do Python. A solução para o laboratório seria:
import requests
from bs4 import BeautifulSoup
# Fazer uma solicitação para https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/
page = requests.get(
"https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/")
soup = BeautifulSoup(page.content, 'html.parser')
# Extrair o título da página
page_title = soup.title.text
# Imprimir o resultado
print(page_title)
Esse foi um laboratório simples, onde tivemos que mudar o URL e imprimir o título da página. O código acima passaria nesse laboratório.
Parte 3: extraindo body e head
Aqui está o link para este laboratório.
No último laboratório, você viu como extrair o title
da página. Da mesma maneira, seria fácil extrair seções mais específicas.
Você também viu que deve usar .text
nelas para obter a string, mas você também pode imprimi-las sem utilizar o .text
. Isso dará a você a marcação completa. Tente rodar o exemplo abaixo:
import requests
from bs4 import BeautifulSoup
# Fazer uma solicitação
page = requests.get(
"https://codedamn.com")
soup = BeautifulSoup(page.content, 'html.parser')
# Extrair o título da página
page_title = soup.title.text
# Extrair o body da página
page_body = soup.body
# Extrair a head da página
page_head = soup.head
# Imprimir o resultado
print(page_body, page_head)
Vamos ver como você pode extrair as seções body
e head
de suas páginas.
Requerimentos necessários:
- Repetir o experimento com o URL:
https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/
- Armazenar o título da página (sem usar o .text) do URL em
page_title
- Armazenar o conteúdo do
body
(sem usar o .text) do URL empage_body
- Armazenar o conteúdo da
head
(sem usar o .text) do URL empage_head
Quando você tentar imprimir page_body
ou page_head
, verá que eles estarão impressos como strings
. Na verdade, porém, quando você colocar print(type page_body)
, verá que não é exatamente uma string. Mesmo assim, isso funcionará bem.
A solução desse exemplo seria simples, baseada no código abaixo:
import requests
from bs4 import BeautifulSoup
# Fazer uma solicitação
page = requests.get(
"https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/")
soup = BeautifulSoup(page.content, 'html.parser')
# Extrair o título da página
page_title = soup.title
# Extrair o body da página
page_body = soup.body
# Extrair a head da página
page_head = soup.head
# Imprimir o resultado
print(page_title, page_head)
Parte 4: selecionando com o BeautifulSoup
Aqui está o link para este laboratório.
Agora que você já explorou algumas partes do BeautifulSoup, veremos como você pode selecionar elementos do DOM com métodos do BeautifulSoup.
Uma vez que você tenha a variável soup
(como nos laboratórios anteriores), você pode trabalhar com .select
nela, um seletor de CSS dentro do BeautifulSoup. Ou seja, você pode ter acesso à arvore do DOM do mesmo modo como você selecionaria elementos com CSS. Vejamos um exemplo:
import requests
from bs4 import BeautifulSoup
# Fazer uma solicitação
page = requests.get(
"https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/")
soup = BeautifulSoup(page.content, 'html.parser')
# Extrair o texto do primeiro <h1>(...)</h1>
first_h1 = soup.select('h1')[0].text
O .select
retorna uma lista em Python de todos os elementos. Essa é a razão pela qual você selecionou apenas o primeiro elemento aqui com o índice [0]
.
Requerimentos necessários:
- Criar uma variável
all_h1_tags
. Colocá-la em uma lista vazia. - Usar
.select
para selecionar todas as tags<h1>
e armazenar seus textos dentro da listaall_h1_tags
. - Criar uma variável
seventh_p_text
e armazenar o texto do 7º elementop
(índice 6) dentro dela.
A solução do laboratório é:
import requests
from bs4 import BeautifulSoup
# Fazer uma solicitação
page = requests.get(
"https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/")
soup = BeautifulSoup(page.content, 'html.parser')
# Criar all_h1_tags como uma lista vazia
all_h1_tags = []
# Definir all_h1_tags como todas as tags h1 de soup
for element in soup.select('h1'):
all_h1_tags.append(element.text)
# Criar seventh_p_text e defini-lo como o texto do 7º elemento p da página
seventh_p_text = soup.select('p')[6].text
print(all_h1_tags, seventh_p_text)
Vamos continuar.
Parte 5: fazendo o scraping dos itens que estão no topo
Aqui está o link deste laboratório.
Agora, extrairemos os itens do topo retirados por scraping do URL https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/
Se você abrir essa página da web em uma nova guia, verá alguns itens no topo dela. Nesse laboratório, sua tarefa é pegar (ou fazer o scraping de) seus nomes e armazená-los em uma lista chamada top_items
. Você também extrairá as suas avaliações.
Para concluir esse desafio, preste atenção nos seguintes pontos:
- Use o
.select
para obter os títulos. (Dica: um seletor para os títulos dos produtos poderia sera.title
) - Use
.select
para obter o rótulo de contagem de comentários para esses títulos de produtos. - Use
.select
para extrair o contador de avaliações dos títulos desses produtos. (Dica: um seletor para as avaliações poderia serdiv.ratings
) Observação: esse é um rótulo completo (ou seja, 2 avaliações), não só um número. - Crie um dicionário nesse formato:
info = {
"title": 'Asus AsusPro Adv... '.strip(),
"review": '2 reviews\n\n\n'.strip()
}
- Note que você está usando o método
strip
para remover quaisquer linhas extras ou espaços em branco que possam aparecer no resultado. Isso é algo importante para avançar nesse laboratório. - Use
.append
para adicionar esse dicionário em uma lista chamadatop_items
. - Imprima essa lista no final usando
print
.
Há algumas tarefas a serem completadas nesse desafio. Vamos, primeiramente, dar uma olhada na solução para entendermos o que está acontecendo aqui:
import requests
from bs4 import BeautifulSoup
# Fazer uma solicitação
page = requests.get(
"https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/")
soup = BeautifulSoup(page.content, 'html.parser')
# Criar top_items como uma lista vazia
top_items = []
# Extrair e armazenar em top_items de acordo com as instruções
products = soup.select('div.thumbnail')
for elem in products:
title = elem.select('h4 > a.title')[0].text
review_label = elem.select('div.ratings')[0].text
info = {
"title": title.strip(),
"review": review_label.strip()
}
top_items.append(info)
print(top_items)
Note que essa é apenas uma das soluções. Fique à vontade para tentar de outras maneiras. Nessa solução:
- Primeiro, você selecionará todos os elementos em
div.thumbnail
, obtendo uma lista de produtos individuais - Depois, você realiza uma iteração neles.
- Você pode usar
select
outra vez para obter o título, já que ele permite iterar sobre ele mesmo. - Note que, agora que você já está rodando um laço para
div.thumbnail
, o seletorh4 > a.title
daria somente um resultado dentro de uma lista. O que você deve fazer é selecionar o elemento de número 0 dessa lista e, então, extrair o seu texto. - Agora, você já pode usar
strip
para remover quaisquer espaços extras contidos no texto e adicionar o texto à sua lista utilizandoappend
.
Simples, não é mesmo?
Parte 6: extraindo links
Aqui está o link deste laboratório
Até agora, você viu como é possível extrair o texto, ou innerText
, dos elementos. Veremos em seguida como é possível extrair os atributos por meio da extração dos links da página.
Aqui está um exemplo de como extrair toda a informação de imagem da página:
import requests
from bs4 import BeautifulSoup
# Fazer uma solicitação
page = requests.get(
"https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/")
soup = BeautifulSoup(page.content, 'html.parser')
# Criar top_items como uma lista vazia
image_data = []
# Extrair e armazenar em top_items de acordo com as instruções
images = soup.select('img')
for image in images:
src = image.get('src')
alt = image.get('alt')
image_data.append({"src": src, "alt": alt})
print(image_data)
Nesse laboratório, sua tarefa é extrair o atributo href
dos links e seus respectivos textos text
. Certifique-se das seguintes coisas:
- Você terá que criar uma lista chamada
all_links
- Nessa lista, armazene toda a informação do link. Isso deverá ficar no seguinte formato:
info = {
"href": "<link here>",
"text": "<link text here>"
}
- Certifique-se que o seu
text
esteja sem nenhum espaço em branco. - Certifique-se de checar se o seu
.text
éNone
antes de usar o.strip()
nele. - Armazene todos esses dicionários em
all_links
- Use
print
para imprimir essa lista no final.
Você extrairá os valores dos atributos da mesma maneira que você extrai os valores de um dicionário, usando a função get
. Veremos agora a solução para esse laboratório:
import requests
from bs4 import BeautifulSoup
# Fazer uma solicitação
page = requests.get(
"https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/")
soup = BeautifulSoup(page.content, 'html.parser')
# Criar top_items como uma lista vazia
all_links = []
# Extrair e armazenar em top_items de acordo com as instruções
links = soup.select('a')
for ahref in links:
text = ahref.text
text = text.strip() if text is not None else ''
href = ahref.get('href')
href = href.strip() if href is not None else ''
all_links.append({"href": href, "text": text})
print(all_links)
Aqui, você extrairá o atributo href
do mesmo modo que você fez no caso da imagem. A única coisa que você fará de diferente é conferir se ele é None
, tal qual fizemos anteriormente. Queremos defini-lo como uma string vazia. Caso contrário, tiraremos o espaço em branco.
Parte 7: gerando CSV a partir de dados
Aqui está o link deste laboratório
Por fim, vamos entender como gerar CSV a partir de um conjunto de dados. Você criará um CSV com os seguintes tópicos:
- Nome do produto
- Preço
- Descrição
- Avaliações
- Imagem do produto
Esses produtos estão localizados em div.thumbnail
. O padrão do CSV está logo abaixo:
import requests
from bs4 import BeautifulSoup
import csv
# Fazer uma solicitação
page = requests.get(
"https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/")
soup = BeautifulSoup(page.content, 'html.parser')
all_products = []
products = soup.select('div.thumbnail')
for product in products:
# TODO: Trabalho
print("Trabalho com o produto aqui")
keys = all_products[0].keys()
with open('products.csv', 'w', newline='') as output_file:
dict_writer = csv.DictWriter(output_file, keys)
dict_writer.writeheader()
dict_writer.writerows(all_products)
Você deverá extrair os dados do site da web e gerar o CSV para três produtos.
Requerimentos necessários:
- O nome do produto é a versão com o espaço em branco cortado do nome do item (exemplo - Asus AsusPro Adv.)
- Preço é o espaço em branco cortado mas com o rótulo do preço inteiro (exemplo - $1101.83)
- A descrição é a versão com o espaço em branco cortado da descrição do produto (exemplo - Asus AsusPro Advanced BU401LA-FA271G Dark Grey, 14", Core i5-4210U, 4GB, 128GB SSD, Win7 Pro)
- Avaliações são as versões com o espaço em branco cortado do produto (exemplo - 7 avaliações)
- Imagem do produto é o URL (atributo src) da imagem do produto (exemplo - /webscraper-python-codedamn-classroom-website/cart2.png)
- O nome do arquivo CSV deve ser products.csv e deve ser armazenado na mesma pasta que o seu arquivo script.py.
Aqui está a solução para esse laboratório:
import requests
from bs4 import BeautifulSoup
import csv
# Fazer uma solicitação
page = requests.get(
"https://codedamn-classrooms.github.io/webscraper-python-codedamn-classroom-website/")
soup = BeautifulSoup(page.content, 'html.parser')
# Criar top_items como uma lista vazia
all_products = []
# Extrair e armazenar em top_items de acordo com as instruções
products = soup.select('div.thumbnail')
for product in products:
name = product.select('h4 > a')[0].text.strip()
description = product.select('p.description')[0].text.strip()
price = product.select('h4.price')[0].text.strip()
reviews = product.select('div.ratings')[0].text.strip()
image = product.select('img')[0].get('src')
all_products.append({
"name": name,
"description": description,
"price": price,
"reviews": reviews,
"image": image
})
keys = all_products[0].keys()
with open('products.csv', 'w', newline='') as output_file:
dict_writer = csv.DictWriter(output_file, keys)
dict_writer.writeheader()
dict_writer.writerows(all_products)
O bloco for
é o mais interessante aqui. Você extrai todos os elementos e atributos de tudo o que já foi aprendido até agora em todos os laboratórios.
Quando você rodar esse código, terá um bom arquivo CSV. Isso é praticamente todo o básico de scraping de dados com o BeautifulSoup!
Conclusão
Eu espero que essa aula interativa do codedamn tenha ajudado você a entender o básico de scraping de dados com o Python.
Se você gostou desta aula e deste artigo, o autor pede que compartilhe com ele sya opinião no Twitter e no Instagram do autor. Ele adoraria ter o seu feedback!