Introdução ao Web Scraping com BeautifulSoup e Requests

Atualizado em: 13/07/2026
Tempo de leitura: 5 minutos
logo do BeautifulSoup em um fundo branco

Web scraping com BeautifulSoup e Requests permite coletar informações de páginas HTML e transformá-las em dados estruturados. Neste guia, você vai aprender a fazer requisições com segurança, localizar elementos, extrair textos e links, percorrer páginas e salvar o resultado em CSV.

O que são Requests e BeautifulSoup?

BibliotecaResponsabilidade
RequestsFaz a requisição HTTP e recebe a resposta do servidor
BeautifulSoupInterpreta o HTML e ajuda a localizar elementos e atributos

Em outras palavras, o Requests baixa o conteúdo e o BeautifulSoup organiza esse conteúdo para consulta. Para conhecer mais opções de requisição, consulte o guia da biblioteca Requests em Python.

Como instalar BeautifulSoup e Requests

Crie um ambiente virtual para o projeto e instale os pacotes:

python -m venv .venv

# Windows
.venv\Scripts\activate

# Linux ou macOS
source .venv/bin/activate

pip install requests beautifulsoup4

O pacote instalado se chama beautifulsoup4, mas a importação é feita pelo módulo bs4.

Primeiro exemplo de web scraping

O exemplo abaixo acessa uma página simples, verifica se a resposta foi bem-sucedida e extrai o título:

import requests
from bs4 import BeautifulSoup

url = "https://example.com/"

resposta = requests.get(url, timeout=10)
resposta.raise_for_status()

soup = BeautifulSoup(resposta.text, "html.parser")
titulo = soup.find("h1")

if titulo:
    print(titulo.get_text(strip=True))

O parâmetro timeout impede que o programa espere indefinidamente. Já raise_for_status() gera uma exceção quando o servidor responde com um erro HTTP.

Fazendo requisições de forma mais robusta

Uma função reutilizável ajuda a padronizar timeout, identificação do projeto e tratamento de erros:

import requests

CABECALHOS = {
    "User-Agent": (
        "ColetorEducacional/1.0 "
        "(contato: [email protected])"
    )
}


def baixar_html(url):
    try:
        resposta = requests.get(
            url,
            headers=CABECALHOS,
            timeout=15,
        )
        resposta.raise_for_status()
        return resposta.text
    except requests.Timeout:
        print(f"Tempo esgotado ao acessar {url}")
    except requests.HTTPError as erro:
        print(f"Erro HTTP em {url}: {erro}")
    except requests.RequestException as erro:
        print(f"Falha na requisição para {url}: {erro}")

    return None

Identifique o seu projeto de forma honesta quando isso fizer sentido. Não tente disfarçar o coletor como outro software nem contornar mecanismos de proteção do site.

Como localizar elementos no HTML

Considere este HTML de exemplo:

<section id="catalogo">
    <article class="produto" data-id="101">
        <h2 class="nome">Teclado</h2>
        <span class="preco">R$ 120,00</span>
        <a href="/produtos/101">Detalhes</a>
    </article>

    <article class="produto" data-id="102">
        <h2 class="nome">Mouse</h2>
        <span class="preco">R$ 80,00</span>
        <a href="/produtos/102">Detalhes</a>
    </article>
</section>

find()

Retorna o primeiro elemento correspondente:

primeiro_produto = soup.find("article", class_="produto")

find_all()

Retorna todos os elementos correspondentes:

produtos = soup.find_all("article", class_="produto")

for produto in produtos:
    print(produto.get_text(" ", strip=True))

select() e select_one()

Esses métodos aceitam seletores CSS, o que facilita consultas por classe, ID e hierarquia:

catalogo = soup.select_one("#catalogo")
produtos = soup.select("#catalogo article.produto")
nomes = soup.select(".produto .nome")
from urllib.parse import urljoin

url_base = "https://site-permitido.example/"

for produto in soup.select("article.produto"):
    nome = produto.select_one(".nome")
    preco = produto.select_one(".preco")
    link = produto.select_one("a[href]")

    dados = {
        "id": produto.get("data-id"),
        "nome": nome.get_text(strip=True) if nome else None,
        "preco": preco.get_text(strip=True) if preco else None,
        "url": urljoin(url_base, link["href"]) if link else None,
    }

    print(dados)

Verifique se o elemento existe antes de chamar get_text() ou acessar um atributo. Essa validação evita erros quando o HTML muda ou algum item não contém todos os campos.

Projeto completo: coletar dados e salvar em CSV

O código abaixo reúne a estrutura principal de um coletor. Substitua a URL e os seletores pelos de uma página que autorize a coleta.

import csv
from urllib.parse import urljoin

import requests
from bs4 import BeautifulSoup

URL_BASE = "https://site-permitido.example/"
URL_CATALOGO = urljoin(URL_BASE, "catalogo")
CABECALHOS = {
    "User-Agent": (
        "ColetorEducacional/1.0 "
        "(contato: [email protected])"
    )
}


def baixar_html(url):
    resposta = requests.get(
        url,
        headers=CABECALHOS,
        timeout=15,
    )
    resposta.raise_for_status()
    return resposta.text


def extrair_produtos(html):
    soup = BeautifulSoup(html, "html.parser")
    produtos = []

    for card in soup.select("article.produto"):
        nome = card.select_one(".nome")
        preco = card.select_one(".preco")
        link = card.select_one("a[href]")

        if not nome:
            continue

        produtos.append(
            {
                "nome": nome.get_text(strip=True),
                "preco": (
                    preco.get_text(strip=True)
                    if preco
                    else ""
                ),
                "url": (
                    urljoin(URL_BASE, link["href"])
                    if link
                    else ""
                ),
            }
        )

    return produtos


def salvar_csv(produtos, caminho="produtos.csv"):
    campos = ["nome", "preco", "url"]

    with open(caminho, "w", newline="", encoding="utf-8") as arquivo:
        escritor = csv.DictWriter(arquivo, fieldnames=campos)
        escritor.writeheader()
        escritor.writerows(produtos)


def main():
    try:
        html = baixar_html(URL_CATALOGO)
        produtos = extrair_produtos(html)
        salvar_csv(produtos)
        print(f"{len(produtos)} produtos salvos.")
    except requests.RequestException as erro:
        print(f"Não foi possível baixar a página: {erro}")
    except OSError as erro:
        print(f"Não foi possível salvar o CSV: {erro}")


if __name__ == "__main__":
    main()

A separação em funções facilita testar a extração com um arquivo HTML local, sem fazer uma nova requisição a cada execução.

Como trabalhar com paginação

Quando o catálogo está dividido em várias páginas, percorra somente a quantidade necessária, inclua uma pausa razoável e pare quando não houver resultados:

import time


def coletar_paginas(limite=5):
    todos_os_produtos = []

    for pagina in range(1, limite + 1):
        url = f"https://site-permitido.example/catalogo?page={pagina}"
        html = baixar_html(url)
        produtos = extrair_produtos(html)

        if not produtos:
            break

        todos_os_produtos.extend(produtos)
        time.sleep(1)

    return todos_os_produtos

Não faça requisições em alta frequência. Respeite limites informados pelo site e use cache quando precisar repetir a análise do mesmo conteúdo.

Sites que carregam conteúdo com JavaScript

Requests recebe o HTML enviado pelo servidor, mas não executa JavaScript. Se os dados aparecem somente depois que a página carrega, procure primeiro uma API oficial ou um recurso de exportação. Quando a automação de navegador for realmente necessária, use-a apenas com autorização e respeite as regras do serviço.

Boas práticas legais e éticas

  • Leia os termos de uso e as políticas do site antes de coletar dados.
  • Consulte o arquivo robots.txt como indicação das áreas destinadas ou não a robôs, sem tratá-lo como única fonte de permissão.
  • Prefira APIs oficiais quando estiverem disponíveis.
  • Não contorne login, captcha, bloqueios ou controles de acesso.
  • Evite coletar dados pessoais ou conteúdo protegido sem base adequada.
  • Reduza a frequência das requisições e armazene resultados quando possível.
  • Identifique seu projeto e forneça um contato quando apropriado.
  • Interrompa a coleta se o servidor responder com bloqueio ou limitação.

Erros comuns em web scraping

ProblemaComo evitar
AttributeError ao usar get_text()Confirme se find() ou select_one() encontrou o elemento
Caracteres incorretosVerifique a codificação da resposta e salve arquivos como UTF-8
Programa travadoDefina um timeout para cada requisição
Links incompletosUse urljoin() para combinar URLs relativas
Seletor parou de funcionarInspecione novamente o HTML e crie testes com amostras locais
Dados duplicadosUse uma chave única, como URL ou ID, antes de salvar

Perguntas frequentes

BeautifulSoup faz a requisição para o site?

Não. Ele interpreta HTML ou XML. A requisição normalmente é feita com Requests, outra biblioteca HTTP ou um conteúdo salvo localmente.

Qual a diferença entre find e select?

find() e find_all() trabalham com nome da tag e atributos. select() e select_one() usam seletores CSS. A melhor opção é a que deixa a busca mais clara e estável.

Como saber se o scraping é permitido?

Analise os termos de uso, as políticas aplicáveis, o tipo de dado e eventuais orientações do responsável pelo site. Em caso de dúvida, solicite autorização ou use uma API oficial.

BeautifulSoup executa JavaScript?

Não. Ele analisa o HTML recebido. Conteúdo gerado no navegador pode exigir uma API, um arquivo incorporado à página ou, quando autorizado, automação de navegador.

Conclusão

Requests e BeautifulSoup formam uma combinação simples e poderosa para estudar HTML e coletar dados de páginas autorizadas. Comece com uma única página, valide cada elemento, trate erros e só depois adicione paginação e exportação. Um coletor confiável precisa ser claro, moderado e respeitar as regras da fonte.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Comparando listas e diferenças entre arrays em Python
    Automação e Scripts
    Foto de perfil de Leandro Hirt da Academify

    Como comparar duas listas em Python e achar as diferenças

    Comparar dados é uma das tarefas mais comuns e fundamentais no dia a dia de qualquer programador. Seja para sincronizar

    Ler mais

    Tempo de leitura: 11 minutos
    01/05/2026
    Bot Python para monitorar queda de preço de produtos online
    Automação e Scripts
    Foto de perfil de Leandro Hirt da Academify

    Como criar um bot que avisa quando um produto baixa de preço

    Você já passou pela frustração de comprar um eletrônico e, no dia seguinte, ver que o preço caiu drasticamente? Monitorar

    Ler mais

    Tempo de leitura: 8 minutos
    23/04/2026
    Como converter código Python para C usando Cython
    Automação e Scripts
    Foto de perfil de Leandro Hirt da Academify

    Como converter Python em código C com Cython: Guia de Velocidade

    Muitos desenvolvedores escolhem o Python por sua legibilidade e vasta biblioteca, mas eventualmente se deparam com um obstáculo comum: a

    Ler mais

    Tempo de leitura: 9 minutos
    22/04/2026
    Web scraper de notícias em Python com envio para Telegram
    Automação e Scripts
    Foto de perfil de Leandro Hirt da Academify

    Como criar um Web Scraper de notícias e enviar para o Telegram

    Você já sentiu a necessidade de acompanhar notícias de um site específico sem ter que abrir o navegador a cada

    Ler mais

    Tempo de leitura: 8 minutos
    16/04/2026
    Integração do ChatGPT com código Python em projeto prático
    Automação e Scripts
    Foto de perfil de Leandro Hirt da Academify

    Como integrar o ChatGPT ao seu código Python: Guia Prático

    A inteligência artificial transformou a maneira como desenvolvemos software, e aprender como integrar o ChatGPT ao seu código Python é

    Ler mais

    Tempo de leitura: 10 minutos
    15/04/2026
    Automação em Python para organizar arquivos do computador
    Automação e Scripts
    Foto de perfil de Leandro Hirt da Academify

    Como organizar os arquivos do seu PC com Python em 5 minutos

    Você já sentiu aquela frustração de abrir a pasta de downloads e encontrar centenas de arquivos misturados? Documentos PDF perdidos

    Ler mais

    Tempo de leitura: 8 minutos
    14/04/2026