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

screenzy-1601054558203
Pré-visualização de uma sala de aula no Codedamn.

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 e status usando a função print  

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:

  1. 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.
  2. 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 em page_body
  • Armazenar o conteúdo da head (sem usar o .text) do URL em page_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 lista all_h1_tags.
  • Criar uma variável seventh_p_text e armazenar o texto do 7º elemento  p  (í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 ser a.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 ser div.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 chamada top_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:

  1. Primeiro, você selecionará todos os elementos em div.thumbnail, obtendo uma lista de produtos individuais
  2. Depois, você realiza uma iteração neles.
  3. Você pode usar select outra vez para obter o título, já que ele permite iterar sobre ele mesmo.
  4. Note que, agora que você já está rodando um laço para div.thumbnail, o seletor h4 > 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.
  5. Agora, você já pode usar strip para remover quaisquer espaços extras contidos no texto e adicionar o texto à sua lista utilizando append.

Simples, não é mesmo?

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:

  1. Nome do produto
  2. Preço
  3. Descrição
  4. Avaliações
  5. 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!