Python e LangChain: Web scraping com IA

Cansado de programar?

Conheça a melhor e mais completa formação de Python e Django e sinta-se um programador verdadeiramente competente. Além de Python e Django, você também vai aprender Banco de Dados, SQL, HTML, CSS, Javascript, Bootstrap e muito mais!

Quero aprender Python e Django de Verdade! Quero aprender!
Suporte

Tire suas dúvidas diretamente com o professor

Projetos práticos

Projetos práticos voltados para o mercado de trabalho

Prática profissional

Formação moderna com foco na prática profissional

Download do Artigo

Artigo atualizado em Setembro 2026: o carregamento das páginas agora usa o Playwright e o BeautifulSoup diretamente, porque o pacote langchain-community (de onde vinham AsyncChromiumLoader, BeautifulSoupTransformer e PlaywrightURLLoader) foi descontinuado. O modelo gpt-4o-mini virou gpt-6-luna, a extração passou a devolver todos os artigos de cada trecho (antes vinha só um), faltavam o playwright install chromium e o tiktoken na instalação, e os casos avançados, que chamavam funções inexistentes, agora usam de fato o modelo. Testado com langchain-openai 1.6 e Playwright 1.63.

Salve salve Pythonista :wave:

No mundo digital de hoje, o Web Scraping é uma técnica essencial para extrair informações de sites.

Com a evolução da inteligência artificial, surge a possibilidade de incorporar agentes inteligentes através de Frameworks LLM, como o Langchain, e automação de navegadores, como o Playwright, para enriquecer esse processo.

Neste artigo, exploraremos como combinar essas ferramentas para realizar web scraping de maneira eficiente e inteligente.

Vamos entender o que são o Langchain e o Playwright, como configurá-los e implementá-los em um projeto de web scraping.

Além disso, utilizaremos outras bibliotecas úteis e o ChatGPT para analisar os dados extraídos.

Vamos lá!

Vá Direto ao Assunto…

O que é Langchain?

O Langchain é uma biblioteca que simplifica a criação de pipelines de processamento de linguagem natural sofisticados.

Ela permite que desenvolvedores combinem diferentes modelos e técnicas de forma modular.

Utilizando o Langchain, podemos facilmente misturar e combinar modelos de IA para obter uma análise aprimorada do texto extraído durante o web scraping.

Se quiser saber mais sobre o LangChain, clique aqui para ler um artigo completo com mais detalhes sobre essa formidável ferramenta.

O que é Playwright?

Playwright é uma biblioteca para automação de navegadores, semelhante ao Selenium, mas com desempenho melhorado e suporte a multiplataforma.

Ele permite controlar navegadores para extrair dados dinâmicos de sites de forma eficiente, essencial quando lidamos com páginas que carregam dados via JavaScript.

Neste projeto, usamos o Playwright para carregar as páginas (inclusive as que dependem de JavaScript) e obter o HTML final para análise.

Bibliotecas Necessárias

Para implementar nosso projeto de Web Scraping com IA, precisamos instalar as seguintes bibliotecas:

1
2
3
4
5
6
7
8
9
pip install playwright \
  beautifulsoup4 \
  python-decouple \
  tiktoken \
  langchain-text-splitters \
  langchain-openai

# Baixa o navegador que o Playwright vai controlar
playwright install chromium

Explicação das Bibliotecas

  • playwright: Automação de navegador para carregamento de páginas dinâmicas. O comando playwright install chromium baixa o navegador; sem ele, o código falha ao abrir a página.
  • beautifulsoup4: Extração de dados do HTML.
  • python-decouple: Carregar variáveis de ambiente de arquivos .env.
  • tiktoken: Contagem de tokens, usada pelo divisor de texto.
  • langchain-text-splitters: Divisão do texto em pedaços (parte do ecossistema LangChain).
  • langchain-openai: Integração do LangChain com a API da OpenAI (instala junto o langchain-core).

Versões anteriores deste artigo usavam o pacote langchain-community. Ele foi descontinuado em maio de 2026 e não recebe mais manutenção, por isso ficou de fora.

Implementação do Web Scraping com IA

Vamos implementar o processo de web scraping com as etapas detalhadas a seguir.

Configuração Inicial

Primeiro, vamos configurar nossa chave de API e o modelo de linguagem natural que usaremos:

Crie um arquivo .env na raiz do projeto com a chave da API da OpenAI:

1
OPENAI_API_KEY=sua_chave_aqui

E carregue a chave no código:

1
2
3
4
5
from decouple import config
import os

# Carrega a chave da API da OpenAI do arquivo .env usando decouple
os.environ['OPENAI_API_KEY'] = config('OPENAI_API_KEY')

Definição do Modelo

Definimos o modelo para estruturar os dados do artigo, utilizando o Pydantic.

Estruturamos o modelo do artigo com campos como título, descrição, data, autor e link. Como cada trecho de texto enviado ao modelo pode conter vários artigos, criamos também uma classe ArticleList para receber todos eles de uma vez:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pydantic import Field, BaseModel

class Article(BaseModel):
    """
    Representa um artigo com informações estruturadas.
    """
    headline: str = Field(description="O título do artigo")
    description: str | None = Field(default=None, description="Uma breve descrição do artigo, se existir no texto")
    date: str = Field(description="A data em que o artigo foi publicado")
    author: str = Field(description="O autor do artigo")
    link: str = Field(description="O link para o artigo")


class ArticleList(BaseModel):
    articles: list[Article] = Field(description="Todos os artigos encontrados no texto")

A description é opcional (str | None) porque nem todo card da listagem do blog tem um resumo. Se o campo fosse obrigatório, o modelo seria forçado a inventar uma descrição.

Carregamento de Dados

Usamos o Playwright para abrir cada URL num Chromium sem interface gráfica (headless), esperar a página terminar de carregar (incluindo o JavaScript) e pegar o HTML final:

1
2
3
4
5
6
7
8
9
10
11
12
13
from playwright.sync_api import sync_playwright

def carregar_html(url):
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        page.goto(url, wait_until="networkidle")
        html = page.content()
        browser.close()
    return html

# Lista de URLs que serão carregadas
urls = ["https://pythonacademy.com.br/blog/"]

Extração com BeautifulSoup

Com o BeautifulSoup, extraímos apenas as tags desejadas (aqui, article). Para descobrir quais tags usar, inspecione o HTML da página e identifique as que contêm o conteúdo desejado.

Guardamos o texto de cada tag, junto com o primeiro link dela, num Document do LangChain (um objeto com o texto em page_content e informações extras em metadata):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from bs4 import BeautifulSoup
from langchain_core.documents import Document

def artigo_para_texto(artigo):
    texto = artigo.get_text(" ", strip=True)
    link = artigo.find("a", href=True)
    return f"{texto} (link: {link['href']})" if link else texto

tags_to_extract = ["article"]

docs_transformed = []
for url in urls:
    soup = BeautifulSoup(carregar_html(url), "html.parser")
    trechos = [artigo_para_texto(tag) for tag in soup.find_all(tags_to_extract)]
    docs_transformed.append(
        Document(page_content="\n\n".join(trechos), metadata={"source": url})
    )

Tokenização de Texto

Usamos o RecursiveCharacterTextSplitter para tokenizar o texto entregue para análise:

1
2
3
4
5
6
7
8
from langchain_text_splitters import RecursiveCharacterTextSplitter

# Divide o conteúdo extraído em pedaços usando tokenização
splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
  chunk_size=2000,
  chunk_overlap=0
)
splits = splitter.split_documents(documents=docs_transformed)

Análise de Conteúdo

Finalmente, invocamos o modelo estruturado de linguagem natural para estruturar os dados:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from langchain_openai import ChatOpenAI

# Cria uma instância do modelo ChatOpenAI configurado com o gpt-6-luna
llm = ChatOpenAI(model="gpt-6-luna")

# Configura o modelo para retornar respostas no formato da classe ArticleList
structured_llm = llm.with_structured_output(ArticleList)

# Extrai e estrutura os artigos de cada pedaço
extracted_content = []
for split in splits:
    resultado = structured_llm.invoke(split.page_content)
    extracted_content.extend(resultado.articles)

# Converte o conteúdo estruturado em uma lista de dicionários
extracted_content_dict = [article.model_dump() for article in extracted_content]

# Exibe o resultado
print(extracted_content_dict)

O with_structured_output usa o recurso de structured output da API da OpenAI: o modelo é obrigado a responder no formato do schema Pydantic, e o LangChain já devolve objetos ArticleList validados.

Resultado da Extração de Dados

O código acima extrai e estrutura dados das páginas especificadas retornando uma lista de artigos. O início da saída fica algo como (o conteúdo depende da página no momento do scraping e a resposta do modelo pode variar):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
  {'headline': 'Como criar um agente de IA em Python (do loop manual ao framework)',
  'description': None,
  'date': '03/06/2026',
  'author': 'Vinícius Ramos',
  'link': 'https://pythonacademy.com.br/blog/como-criar-um-agente-de-ia-em-python'},

  {'headline': 'Por que criei o Ebookr.ai: A dor de criar ebooks profissionais com Word e Google Docs',
  'description': None,
  'date': '11/02/2026',
  'author': 'Vinícius Ramos',
  'link': 'https://pythonacademy.com.br/blog/por-que-criei-o-ebookr-ai'},
  ...
]

Este resultado revela como o uso de IA pode facilitar e estruturar processos de extração de dados.

Antes de continuar… Está curtindo esse conteúdo? :thumbsup:

Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?

Sua assinatura não pôde ser validada.
Você fez sua assinatura com sucesso.

Assine as PyDicas e receba 30 dias do melhor conteúdo Python na sua Caixa de Entrada: direto e sem enrolação!

Código Completo do Web Scraping com IA

Aqui está o código completo para referência:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import os

from bs4 import BeautifulSoup
from decouple import config
from langchain_core.documents import Document
from langchain_openai import ChatOpenAI
from langchain_text_splitters import RecursiveCharacterTextSplitter
from playwright.sync_api import sync_playwright
from pydantic import Field, BaseModel

os.environ['OPENAI_API_KEY'] = config('OPENAI_API_KEY')

llm = ChatOpenAI(model="gpt-6-luna")

class Article(BaseModel):
    headline: str = Field(description="O título do artigo")
    description: str | None = Field(default=None, description="Uma breve descrição do artigo, se existir no texto")
    date: str = Field(description="A data em que o artigo foi publicado")
    author: str = Field(description="O autor do artigo")
    link: str = Field(description="O link para o artigo")

class ArticleList(BaseModel):
    articles: list[Article] = Field(description="Todos os artigos encontrados no texto")

structured_llm = llm.with_structured_output(ArticleList)

def carregar_html(url):
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        page.goto(url, wait_until="networkidle")
        html = page.content()
        browser.close()
    return html

def artigo_para_texto(artigo):
    texto = artigo.get_text(" ", strip=True)
    link = artigo.find("a", href=True)
    return f"{texto} (link: {link['href']})" if link else texto

urls = ["https://pythonacademy.com.br/blog/"]
tags_to_extract = ["article"]

docs_transformed = []
for url in urls:
    soup = BeautifulSoup(carregar_html(url), "html.parser")
    trechos = [artigo_para_texto(tag) for tag in soup.find_all(tags_to_extract)]
    docs_transformed.append(
        Document(page_content="\n\n".join(trechos), metadata={"source": url})
    )

splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
  chunk_size=2000,
  chunk_overlap=0
)

splits = splitter.split_documents(documents=docs_transformed)

extracted_content = []
for split in splits:
    extracted_content.extend(structured_llm.invoke(split.page_content).articles)

extracted_content_dict = [article.model_dump() for article in extracted_content]

print(extracted_content_dict)

:zap: Falando em LangChain e IA: Estou usando exatamente essas tecnologias para construir o Ebookr.ai - uma plataforma que gera ebooks profissionais sobre qualquer tema automaticamente. O mesmo poder do LangChain que você está aprendendo aqui, aplicado para criar conteúdo de alta qualidade. Confira!

Conclusão

Neste artigo, mergulhamos na combinação poderosa do Langchain e do Playwright para realizar web scraping avançado com IA.

Estudamos como configurar e implementar estas ferramentas, além de outras bibliotecas essenciais, para extrair dados de sites de forma eficiente.

Com a capacidade de estruturar informações de maneira precisa, esse método transforma a maneira como abordamos a extração de dados na web.

Experimente estas técnicas no seu próximo projeto e veja os benefícios dessa abordagem inovadora.

LangChain + Playwright vs Outras Abordagens

Critério LangChain+Playwright BeautifulSoup Scrapy Selenium
JavaScript ✅ Executa ❌ Não ❌ Não ✅ Executa
Extração IA ✅ Built-in ❌ Manual ❌ Manual ❌ Manual
Estruturação ✅ Pydantic ❌ Manual ❌ Manual ❌ Manual
Performance ⚠️ Média ✅ Rápida ✅ Muito rápida ❌ Lenta
Custo ❌ APIs ($$) ✅ Grátis ✅ Grátis ✅ Grátis
Precisão ✅ Alta (IA) ⚠️ Média ⚠️ Média ⚠️ Média
HTML dinâmico ✅ Simples ❌ Não ❌ Não ✅ Simples
Uso ideal SPAs + IA Estático Escala SPAs básico

Saber quando vale a pena usar uma solução mais pesada como essa é tão importante quanto saber implementá-la - e essa clareza vem da prática em projetos variados. É isso que a Jornada Python treina, do zero ao avançado:

Quando Usar LangChain + Playwright

✅ Sites JavaScript pesados (SPAs) Playwright renderiza JavaScript completo

✅ Precisa extração inteligente IA entende contexto e estrutura dados

✅ HTML mal estruturado/inconsistente IA adapta-se a variações na estrutura

✅ Dados não estruturados em texto Exemplo: extrair preços de parágrafos

✅ Prototipar rapidamente Menos código que parsers tradicionais

Quando NÃO Usar

❌ Site tem API oficial API é sempre melhor e mais confiável

❌ Orçamento limitado Custos de API OpenAI podem ser altos

❌ Precisa de escala massiva Scrapy é muito mais rápido/barato

❌ HTML bem estruturado e estático BeautifulSoup é suficiente e mais barato

❌ Performance crítica Playwright + IA adiciona latency

Casos de Uso Avançados

Os exemplos desta seção reaproveitam a função carregar_texto e o llm definidos no primeiro deles.

1. Monitoramento de Preços com IA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from langchain_openai import ChatOpenAI
from playwright.sync_api import sync_playwright
from pydantic import BaseModel

def carregar_texto(url):
    """Abre a página no Chromium e devolve o texto visível."""
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        page.goto(url, wait_until="networkidle")
        texto = page.inner_text("body")
        browser.close()
    return texto

class Produto(BaseModel):
    nome: str
    preco_atual: float
    preco_original: float | None = None
    desconto_percentual: float | None = None
    disponivel: bool

llm = ChatOpenAI(model="gpt-6-luna")
extrator = llm.with_structured_output(Produto)

# Scraping com extração estruturada feita pelo modelo
texto = carregar_texto("https://ecommerce.com/produto")
produto = extrator.invoke(f"Extraia os dados do produto desta página:\n\n{texto}")

print(f"Preço atual: R$ {produto.preco_atual}")
if produto.desconto_percentual:
    print(f"Desconto: {produto.desconto_percentual}%")

2. Extração de Dados de Tabelas Complexas

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pydantic import BaseModel

class LinhaTabela(BaseModel):
    empresa: str
    receita: float
    lucro: float
    margem: float

class TabelaFinanceira(BaseModel):
    titulo: str
    linhas: list[LinhaTabela]
    total_empresas: int

# O modelo identifica a tabela no texto e devolve a estrutura pronta
texto = carregar_texto("https://site.com/tabela-financeira")
tabela = llm.with_structured_output(TabelaFinanceira).invoke(texto)

for linha in tabela.linhas:
    print(f"{linha.empresa}: {linha.margem}% de margem")

3. Scraping com Interação (Login, Scroll)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from playwright.sync_api import sync_playwright

def scrape_com_interacao(url, username, password):
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()

        # Login
        page.goto(url)
        page.fill('input[name="username"]', username)
        page.fill('input[name="password"]', password)
        page.click('button[type="submit"]')

        # Aguardar carregamento
        page.wait_for_selector('.dashboard')

        # Scroll infinito
        previous_height = 0
        while True:
            page.evaluate('window.scrollTo(0, document.body.scrollHeight)')
            page.wait_for_timeout(2000)

            new_height = page.evaluate('document.body.scrollHeight')
            if new_height == previous_height:
                break
            previous_height = new_height

        # Extrair conteúdo
        content = page.content()
        browser.close()

        return content

Otimização de Custos

1. Cache de Conteúdo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import hashlib
import json
from pathlib import Path

def scrape_com_cache(url):
    # Hash da URL como chave de cache
    cache_key = hashlib.md5(url.encode()).hexdigest()
    cache_file = Path(f"cache/{cache_key}.json")

    # Verificar cache
    if cache_file.exists():
        with open(cache_file, encoding="utf-8") as f:
            return json.load(f)

    # Scraping real (custa API)
    texto = carregar_texto(url)
    result = extrator.invoke(texto).model_dump()  # extrator de Produto do caso 1

    # Salvar em cache
    cache_file.parent.mkdir(exist_ok=True)
    with open(cache_file, 'w', encoding="utf-8") as f:
        json.dump(result, f, ensure_ascii=False)

    return result

2. Processar em Batch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pydantic import BaseModel

class ListaDeProdutos(BaseModel):
    produtos: list[Produto]  # Produto do caso 1

# Processar múltiplas páginas juntas: uma chamada só, em vez de uma por página
# (as instruções e o schema vão uma única vez)
urls = ["url1", "url2", "url3"]
textos = [carregar_texto(url) for url in urls]

# Combinar antes de processar
combined_content = "\n\n".join(
    f"Página: {url}\n{texto}" for url, texto in zip(urls, textos)
)

# Processar tudo de uma vez
result = llm.with_structured_output(ListaDeProdutos).invoke(combined_content)

Cuidado para o texto combinado não passar do limite de contexto do modelo; se passar, divida em lotes menores.

Conclusão

Neste guia sobre Web Scraping com IA, você aprendeu:

✅ Combinação poderosa - LangChain + Playwright + IA
✅ Extração estruturada - Pydantic para dados tipados
✅ JavaScript - Playwright renderiza SPAs
✅ Comparações - vs BeautifulSoup, Scrapy, Selenium
✅ Quando usar - SPAs, HTML inconsistente, extração inteligente
✅ Otimização - Cache e batch para reduzir custos
✅ Casos avançados - Login, scroll, tabelas complexas

Principais lições:

  • IA + scraping = extração inteligente e adaptativa
  • Playwright executa JavaScript, BeautifulSoup não
  • Pydantic estrutura dados automaticamente
  • Custos de API podem ser altos - use cache
  • Para sites simples, BeautifulSoup é melhor

Próximos passos:

Quer firmar a base de Python por trás desses projetos, com web scraping e automação em uma trilha guiada do zero ao avançado? Conheça a Jornada Python, nosso curso de Python completo.

Começe agora sua Jornada na Programação!

Não deixe para amanhã o sucesso que você pode começar a construir hoje!

#newsletter Olá :wave: Curtiu o artigo? Então faça parte da nossa Newsletter! Privacidade Não se preocupe, respeitamos sua privacidade. Você pode se descadastrar a qualquer momento.