🎯 Um navegador em nuvem personalizável e anti-detecção alimentado por Chromium desenvolvido internamente, projetado para rastreadores web e agentes de IA. 👉Experimente agora
De volta ao blog

Raspagem da Web com Polars: Da Página ao Vivo para um DataFrame Rápido

James Thompson
James Thompson

Scraping and Proxy Management Expert

22-Jul-2026

TL;DR:

  • Polars é uma biblioteca de DataFrame rápida e suportada por Arrow, e combina com o Scrapeless para transformar uma página ao vivo em um quadro tipado e consultável.
  • Polars não possui cliente HTTP nem parser HTML, portanto, as etapas de busca e extração vêm do Scrapeless e um parser; Polars assume o controle assim que os registros existem.
  • Construa um quadro a partir de uma lista de dicionários com pl.DataFrame(records), e o esquema é tipado a partir da primeira linha quando você coercivamente define os valores durante a extração.
  • A API de expressões substitui a indexação encadeada estilo pandas: pl.col("price_gbp").mean() dentro de group_by(...).agg(...) é lido e executado de forma limpa.
  • O caminho preguiçoso, df.lazy()...collect(), permite que Polars planeje e otimize toda a consulta antes de acessar os dados, que é onde ele se destaca em conjuntos maiores.
  • Comece no plano gratuito do Scrapeless e aponte a etapa de busca para o seu próprio catálogo.

Polars continua sendo usado em trabalhos de dados porque é rápido e sua API é agradável, mas quase todos os tutoriais lhe entregam um arquivo Parquet que já existe. A raspagem é a situação oposta. Os dados são ao vivo, são HTML, e não têm tipo até que você os torne tipados. Este guia leva um catálogo público de livros de uma URL a um DataFrame Polars que você pode agrupar e agregar, e é honesto sobre a única coisa que o Polars não fará por você: obter a página.

A busca vem da API de Raspagem Universal Scrapeless, que retorna HTML renderizado para uma URL pública. Um parser transforma esse HTML em registros. Polars faz o resto, e faz rápido.

O que o Polars Adiciona a um Fluxo de Trabalho de Raspagem

Polars é uma biblioteca de DataFrame construída no formato de memória columnar Apache Arrow, que é o que torna suas colunas tipadas e agregações agrupadas rápidas. Para dados raspados, o retorno é concreto: uma vez que seus registros estão em um quadro, limpá-los e resumí-los é feito com algumas expressões em vez de um loop escrito à mão, e as colunas mantêm seus tipos. Polars baseia-se no formato columnar Apache Arrow para seu layout em memória, então uma coluna de preços é uma coluna numérica real, não uma lista de strings que você reanalisou em cada operação.

Instalação

Polars lida com o quadro; um parser lida com o HTML. Instale ambos.

bash Copy
pip install polars lxml

Defina sua chave de API Scrapeless uma vez no shell. Use a chave real em tempo de execução e mantenha o espaço reservado fora do seu código-fonte.

bash Copy
export SCRAPELESS_API_KEY="sk_your_key_here"

Buscar, Extrair e Construir um Quadro

A primeira etapa busca a página, captura um registro por produto e constrói o DataFrame. Como Polars não pode buscar ou analisar HTML, esta etapa é onde o Scrapeless e o parser fazem seu trabalho; Polars assume os registros finalizados.

python Copy
import json
import os
import urllib.request

import polars as pl
from lxml import html as lxhtml

API_URL = "https://api.scrapeless.com/api/v2/unlocker/request"
RATINGS = {"One": 1, "Two": 2, "Three": 3, "Four": 4, "Five": 5}


def fetch_html(url: str) -> str:
    payload = json.dumps(
        {"actor": "unlocker.webunlocker", "input": {"url": url, "js_render": False, "headless": False}}
    ).encode()
    request = urllib.request.Request(
        API_URL,
        data=payload,
        headers={"x-api-token": os.environ["SCRAPELESS_API_KEY"], "Content-Type": "application/json"},
        method="POST",
    )
    with urllib.request.urlopen(request, timeout=90) as response:
        return json.loads(response.read())["data"]


dom = lxhtml.fromstring(fetch_html("https://books.toscrape.com/"))
records = []
for card in dom.cssselect("article.product_pod"):
    records.append(
        {
            "title": card.cssselect("h3 a")[0].get("title"),
            "price_gbp": float(card.cssselect("p.price_color")[0].text_content().strip().lstrip("£")),
            "rating": RATINGS[card.cssselect("p.star-rating")[0].get("class").split()[-1]],
            "in_stock": "In stock" in card.cssselect("p.instock.availability")[0].text_content(),
        }
    )

df = pl.DataFrame(records)
print(f"registros extraídos: {df.height}")
print("esquema:", dict(df.schema))

A extração usa o padrão CSS Selectors através do cssselect do lxml, e coage cada valor enquanto o lê: o preço se torna um float, a palavra da avaliação se torna um inteiro, e a disponibilidade se torna um booleano. Essa coação é o hábito importante. Construa os registros com tipos reais do Python e Polars infere um esquema real a partir deles.

text Copy
registros extraídos: 20
esquema: {'title': String, 'price_gbp': Float64, 'rating': Int64, 'in_stock': Boolean}

Vinte cartões de produto na primeira página se tornam um quadro com um esquema digitado: String, Float64, Int64 e Boolean. Nenhuma coluna é deixada como texto que depois precisa ser reanalisada.

Transformar Com Expressões

Polars substitui o indexamento encadeado por uma API de expressões, e essa é a parte que vale a pena aprender corretamente. Uma expressão como pl.col("price_gbp").mean() descreve um cálculo que o Polars executa de forma eficiente, e as expressões se compõem dentro de filter, group_by e agg.

python Copy
resumo = (
    df.lazy()
    .filter(pl.col("in_stock"))
    .group_by("rating")
    .agg(pl.len().alias("books"), pl.col("price_gbp").mean().round(2).alias("avg_price"))
    .sort("rating")
    .collect()
)
print(resumo)

df.lazy() transforma o quadro ansioso em um plano de consulta, a cadeia descreve o trabalho, e .collect() o executa. Neste pequeno conjunto, a diferença é invisível, mas o caminho preguiçoso permite que o Polars analise toda a consulta e pule o trabalho antes de ler um único valor, razão pela qual ele consegue escalar. Os grupos agregados de livros em estoque são classificados pela classificação de estrelas e relatam a contagem e o preço médio por grupo.

text Copy
shape: (5, 3)
┌────────┬───────┬───────────┐
│ rating ┆ books ┆ avg_price │
│ ---    ┆ ---   ┆ ---       │
│ i64    ┆ u32   ┆ f64       │
╞════════╪═══════╪═══════════╡
│ 1      ┆ 6     ┆ 40.02     │
│ 2      ┆ 3     ┆ 36.83     │
│ 3      ┆ 3     ┆ 42.32     │
│ 4      ┆ 4     ┆ 31.1      │
│ 5      ┆ 4     ┆ 39.75     │
└────────┴───────┴───────────┘

O Script Completo

Junte os estágios, adicione mais uma expressão para encontrar o livro mais barato com cinco estrelas e armazene o quadro como Parquet.

python Copy
import json
import os
import urllib.request

import polars as pl
from lxml import html as lxhtml

API_URL = "https://api.scrapeless.com/api/v2/unlocker/request"
RATINGS = {"Um": 1, "Dois": 2, "Três": 3, "Quatro": 4, "Cinco": 5}


def fetch_html(url: str) -> str:
    payload = json.dumps(
        {"actor": "unlocker.webunlocker", "input": {"url": url, "js_render": False, "headless": False}}
    ).encode()
    request = urllib.request.Request(
        API_URL,
        data=payload,
        headers={"x-api-token": os.environ["SCRAPELESS_API_KEY"], "Content-Type": "application/json"},
        method="POST",
    )
    with urllib.request.urlopen(request, timeout=90) as response:
        return json.loads(response.read())["data"]


dom = lxhtml.fromstring(fetch_html("https://books.toscrape.com/"))
records = []
for card in dom.cssselect("article.product_pod"):
    records.append(
        {
            "title": card.cssselect("h3 a")[0].get("title"),
            "price_gbp": float(card.cssselect("p.price_color")[0].text_content().strip().lstrip("£")),
            "rating": RATINGS[card.cssselect("p.star-rating")[0].get("class").split()[-1]],
            "in_stock": "Em estoque" in card.cssselect("p.instock.availability")[0].text_content(),
        }
    )

df = pl.DataFrame(records)
print(f"registros extraídos: {df.height} | colunas: {df.columns}")

resumo = (
    df.lazy()
    .filter(pl.col("in_stock"))
    .group_by("rating")
    .agg(pl.len().alias("books"), pl.col("price_gbp").mean().round(2).alias("avg_price"))
    .sort("rating")
    .collect()
)
print(resumo)

cheapest = df.filter(pl.col("rating") == 5).sort("price_gbp").select("title", "price_gbp").head(1)
print("livro 5 estrelas mais barato:", cheapest.to_dicts())

df.write_parquet("books.parquet")
print(f"tamanho em bytes do parquet: {os.path.getsize('books.parquet')}")

A execução relata cada etapa, terminando com um arquivo Parquet que mantém o esquema para o próximo leitor.

text Copy
registros extraídos: 20 | colunas: ['title', 'price_gbp', 'rating', 'in_stock']
shape: (5, 3)
┌────────┬───────┬───────────┐
│ rating ┆ books ┆ avg_price │
│ ---    ┆ ---   ┆ ---       │
│ i64    ┆ u32   ┆ f64       │
╞════════╪═══════╪═══════════╡
│ 1      ┆ 6     ┆ 40.02     │
│ 2      ┆ 3     ┆ 36.83     │
│ 3      ┆ 3     ┆ 42.32     │
│ 4      ┆ 4     ┆ 31.1      │
│ 5      ┆ 4     ┆ 39.75     │
└────────┴───────┴───────────┘
livro 5 estrelas mais barato: [{'title': 'Set Me Free', 'price_gbp': 17.46}]
tamanho em bytes do parquet: 2233

write_parquet armazena as colunas tipadas no formato de arquivo Apache Parquet, para que o próximo processo leia price_gbp de volta como um float sem re-coerção. O guia do usuário do Polars documenta toda a expressão e a API preguiçosa quando você ultrapassa este exemplo.

O Que o Polars Não Fará

Polars é um motor de dataframe, e esse é o todo limite: ele não tem cliente HTTP e nem analisador HTML. Não fará uma solicitação de URL, não renderizará JavaScript e não transformará tags <article> em linhas. Isso é intencional, e é por isso que este fluxo de trabalho usa duas ferramentas na frente. Scrapeless recupera a página, e um parser lê a marcação em registros. Se você precisa de um tratamento mais profundo do passo de parsing, o guia sobre usando BeautifulSoup para web scraping aborda a extração de HTML em Python, e os mesmos registros alimentam diretamente o pl.DataFrame.

Quando um alvo renderiza seu conteúdo com JavaScript, a primeira busca retorna um shell vazio e o loop de extração não encontra cartões. Defina js_render como True na requisição para que o Scrapeless retorne a página após a execução de seus scripts, e deixe como False quando a marcação já for renderizada pelo servidor, como este catálogo.

Antes de ampliar o rastreamento além da primeira página, leia o robots.txt do alvo e os termos. O Protocolo de Exclusão de Robôs afirma quais caminhos um site pede para que clientes automatizados evitem, e permanecer dentro dele mantém o fluxo de trabalho sustentável. Mantenha o volume limitado e os dados públicos, como este exemplo faz.

Pronto para tentar em seus próprios dados? Crie uma conta gratuita no Scrapeless e altere a URL e os seletores na etapa de busca.

Conclusão

Polars transforma registros extraídos em um quadro tipado e consultável com muito pouco código, desde que algo mais obtenha a página primeiro. Scrapeless busca o HTML, um parser constrói os registros com tipos reais, e Polars agrupa, agrega e armazena através de suas APIs de expressão e preguiçosa. Comece a partir do script completo, troque a URL e os seletores pelo seu próprio alvo e procure o caminho preguiçoso à medida que seus dados crescem.

Comece com o plano gratuito do Scrapeless para buscar suas próprias páginas, e confira os preços do Scrapeless quando planejar um trabalho recorrente.

Perguntas Frequentes

P: O Polars faz scraping de páginas web por conta própria?

Não. Polars é uma biblioteca de DataFrame sem cliente HTTP e sem analisador HTML, então não pode solicitar uma URL ou ler a marcação. Combine-o com uma camada de busca, como o Scrapeless, e um parser como lxml ou BeautifulSoup; o Polars assume o controle uma vez que os registros existem.

P: Por que escolher Polars em vez de pandas para dados extraídos?

Polars é construído no formato columnar Apache Arrow e oferece um motor de consulta preguiçoso, então agregações agrupadas e filtros em grandes quadros são rápidos, e a API de expressão é consistente. Um trade-off é relevante para scraping: pandas tem read_html para tabelas, enquanto o Polars espera que você construa o quadro a partir de registros, o que se adapta melhor a páginas estilo cartão do que apenas às tabelas.

P: Qual é a diferença entre ávido e preguiçoso no Polars?

Um DataFrame ávido executa cada operação imediatamente, enquanto df.lazy() constrói um plano de consulta que só é executado quando você chama .collect(). O caminho preguiçoso permite que o Polars otimize toda a consulta e pule trabalhos desnecessários, razão pela qual ele escala melhor em grandes conjuntos de dados, mesmo que o resultado seja idêntico em pequenos.

P: Por que meus números extraídos aparecem como strings no Polars?

Valores extraídos chegam como texto, e se você os passar para pl.DataFrame sem alterações, o tipo da coluna será String. Force cada valor durante a extração, como o exemplo que converte o preço para float e a palavra da classificação para um inteiro, assim o esquema é tipado a partir da primeira linha e nenhuma coluna precisa ser reanalisada depois.

P: Como construir um DataFrame Polars a partir de uma lista de registros extraídos?

Coleta cada registro como um dicionário com chaves consistentes e passe a lista para pl.DataFrame(records). O Polars infere o esquema a partir dos valores, então valores tipados nos dicionários produzem um quadro tipado, pronto para a API de expressão.

Na Scorretless, acessamos apenas dados disponíveis ao público, enquanto cumprem estritamente as leis, regulamentos e políticas de privacidade do site aplicáveis. O conteúdo deste blog é apenas para fins de demonstração e não envolve atividades ilegais ou infratoras. Não temos garantias e negamos toda a responsabilidade pelo uso de informações deste blog ou links de terceiros. Antes de se envolver em qualquer atividade de raspagem, consulte seu consultor jurídico e revise os termos de serviço do site de destino ou obtenha as permissões necessárias.

Artigos mais populares

Catálogo