How to scrape ebay with python cover 1 2

Este guia mostra como fazer scraping do eBay com Python de ponta a ponta: um scraper funcional para resultados de busca, anúncios individuais, variantes de produto e avaliações, além da configuração anti-bot e de proxies que o mantém funcionando. Você precisa de Python 3, algumas bibliotecas e cerca de 30 minutos para a versão básica. Ao final terá funções reutilizáveis de web scraping do eBay que exportam JSON e CSV limpos.

Sou Andrii Byzov, CMO fracionário AI-Native que gerencia pipelines de dados de e-commerce. O eBay é um alvo valioso, mas bem defendido, então este passo a passo sobre como fazer scraping do eBay combina o código com as partes que a maioria dos guias omite: paginação, dados ocultos de variantes e como evitar bloqueios. A versão curta de fazer scraping do eBay com segurança: envie cabeçalhos de navegador reais, rotacione proxies residenciais e respeite os limites de taxa. Para saber quais IPs usar, veja nosso guia de melhores proxies para scraping do eBay.


Fatos-chave

  • O eBay tem dois tipos de página —resultados de busca e anúncios de produto— com estruturas HTML diferentes, então você escreve dois scrapers.
  • As variantes (tamanho, cor, armazenamento) ficam ocultas em JSON inline, não no HTML visível: você as extrai com uma expressão regular e json.loads().
  • Cabeçalhos de navegador reais vêm primeiro: sem um User-Agent adequado, o eBay costuma devolver 403 ou páginas vazias mesmo em requisições simples.
  • Os IPs de data center são sinalizados rápido no eBay; os proxies residenciais rotativos sustentam o volume e devolvem preços corretos por região.
  • Os anúncios diferem por país —eBay.com, eBay.co.uk e eBay.de mostram preços e fretes diferentes— então a segmentação geográfica importa para um scraping de dados do eBay preciso.

Passo 1 — Configure seu ambiente

Crie um ambiente isolado e instale as bibliotecas que seu setup de web scraping do eBay precisa. Cada uma tem sua função: requests busca as páginas, beautifulsoup4 + lxml fazem o parse do HTML e httpx gerencia requisições assíncronas quando você escala.



# Create an isolated project folder and virtual environment
mkdir ebay-scraper && cd ebay-scraper
python3 -m venv env
source env/bin/activate        # Windows: env\Scripts\activate

# requests  -> send HTTP requests
# beautifulsoup4 -> parse the returned HTML
# lxml -> fast HTML parser backend for BeautifulSoup
# httpx -> async requests for scaling later
pip install requests beautifulsoup4 lxml httpx










Passo 2 — Entenda a estrutura de páginas do eBay

Antes de escrever código, entenda que o eBay tem dois tipos de página fundamentalmente diferentes, e que saber como fazer scraping do eBay de forma confiável começa por conhecer quais seletores pertencem a cada um. Cada tipo de página precisa de seletores diferentes. Abra qualquer página, pressione F12 (ou clique com o botão direito → Inspecionar) e passe o cursor sobre um elemento para ver sua classe. O mapa abaixo é o que você usará nos Passos 3 e 4.

Página de resultados de busca

Cada resultado fica em um contêiner li.s-item, com o título, o preço e o link aninhados dentro. O parâmetro de URL _pgn controla a paginação: você vai precisar dele no Passo 3.

Página de anúncio de produto

Um anúncio individual expõe o preço em .x-price-primary, o título em h1 span e as especificações do item em linhas .ux-labels-values. A descrição longa fica em um iframe#desc_ifr separado: uma subpágina que você scrapearia com sua própria requisição.

Dado Seletor nos resultados Seletor no anúncio
Contêiner li.s-item
Título .s-item__title h1 span
Preço .s-item__price .x-price-primary
Link / imagem a.s-item__link / .s-item__image img
Especificações .ux-labels-values
Descrição iframe#desc_ifr

Passo 3 — Scrapeie os resultados de busca do eBay

O primeiro scraper recebe uma consulta de busca e devolve uma lista de itens com título, preço, URL e imagem: o ponto de entrada da maioria dos projetos de web scraping do eBay. Sem o cabeçalho User-Agent correto, o eBay devolve um 403 ou uma página vazia mesmo nesta requisição simples, então os cabeçalhos entram desde o início. Você pode adaptar o mesmo padrão para scrapear anúncios do eBay a partir de qualquer termo de busca.



import requests
from bs4 import BeautifulSoup
from urllib.parse import quote_plus

HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                         "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
           "Accept-Language": "en-US,en;q=0.9"}

def scrape_search(query, proxies=None):
    """Return a list of eBay search results for a query."""
    url = f"https://www.ebay.com/sch/i.html?_nkw={quote_plus(query)}"
    html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
    soup = BeautifulSoup(html.text, "lxml")
    items = []
    for card in soup.select("li.s-item"):
        title = card.select_one(".s-item__title")
        price = card.select_one(".s-item__price")
        link  = card.select_one("a.s-item__link")
        image = card.select_one(".s-item__image-wrapper img")
        if not (title and link):
            continue
        items.append({
            "title": title.get_text(strip=True),
            "price": price.get_text(strip=True) if price else None,
            "url":   link["href"],
            "image": image.get("src") if image else None,
        })
    return items

print(scrape_search("smartphone")[:3])






























Lidando com a paginação

Uma única página de resultados não basta. Este laço percorre o parâmetro _pgn (página 2, 3… N) e para quando a lista de resultados está vazia ou você atinge um limite de páginas: a parte que a maioria dos tutoriais de eBay scraper em Python omite.



from urllib.parse import quote_plus

def scrape_all_pages(query, max_pages=10, proxies=None):
    """Page through results via the _pgn parameter until empty or max_pages."""
    all_items = []
    for page in range(1, max_pages + 1):
        url = (f"https://www.ebay.com/sch/i.html?_nkw={quote_plus(query)}"
               f"&_pgn={page}")
        html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
        soup = BeautifulSoup(html.text, "lxml")
        cards = soup.select("li.s-item")
        if not cards:                 # no more results -> stop
            break
        for card in cards:
            title = card.select_one(".s-item__title")
            link  = card.select_one("a.s-item__link")
            if title and link:
                all_items.append({"title": title.get_text(strip=True),
                                  "url": link["href"]})
    return all_items




















Passo 4 — Scrapeie as páginas de anúncio de produto

Quando você scrapeia anúncios do eBay um a um, parse_product(url) recebe a URL de um anúncio e devolve os campos estruturados: título, preço, condição, vendedor, frete e a tabela de especificações onde cada linha é um par chave/valor. É o núcleo do scraping de dados do eBay no nível do produto.



def parse_product(url, proxies=None):
    """Scrape a single eBay listing page."""
    html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
    soup = BeautifulSoup(html.text, "lxml")

    def text(sel):
        el = soup.select_one(sel)
        return el.get_text(strip=True) if el else None

    # item specifics live in a label/value table
    specifics = {}
    for row in soup.select(".ux-labels-values"):
        label = row.select_one(".ux-labels-values__labels")
        value = row.select_one(".ux-labels-values__values")
        if label and value:
            specifics[label.get_text(strip=True)] = value.get_text(strip=True)

    return {
        "title":     text("h1 span"),
        "price":     text(".x-price-primary"),
        "condition": text(".x-item-condition-text .ux-textspans"),
        "seller":    text(".x-sellercard-atf__info__about-seller"),
        "shipping":  text(".ux-labels-values--shipping .ux-textspans"),
        "item_specifics": specifics,
    }

























Extraindo variantes de produto (dados MSKU)

O eBay guarda as opções de variante —cor, tamanho, armazenamento— não no HTML visível, mas dentro de um objeto JSON inline (MSKU) em uma tag <script>. Você localiza esse JSON e faz o parse com json.loads(). Sua chave e formato exatos mudam com o tempo, então trate o código abaixo como ponto de partida e ajuste ao que vir no DevTools: ele devolve as opções de variante (nome/valor), a parte que a maioria dos concorrentes omite.



import re, json

def parse_variants(url, proxies=None):
    """eBay keeps multi-SKU variant options (size, colour, storage) in an inline
    JSON blob rather than visible HTML. The exact key and shape change over time,
    so treat the pattern below as a starting point and adjust it to the page you
    inspect in DevTools. This returns the option name/value pairs, not full
    price-per-combination data."""
    html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30).text
    # find the inline state object, then load it with a balanced-brace slice
    start = html.find('"MSKU"')
    if start == -1:
        return []
    brace = html.find("{", start)
    depth, end = 0, brace
    for i in range(brace, len(html)):
        depth += (html[i] == "{") - (html[i] == "}")
        if depth == 0:
            end = i + 1
            break
    try:
        data = json.loads(html[brace:end])
    except json.JSONDecodeError:
        return []
    return [{"name": v.get("displayName"), "value": v.get("valueName")}
            for v in data.get("menuItemMap", {}).values()]


























Passo 5 — Scrapeie as avaliações de produto do eBay

Ao scrapear avaliações do eBay, observe que são avaliações de produto/catálogo em uma URL separada, não em cada página de anúncio, e que nem todo anúncio as tem. Você deriva a URL de avaliações do ID de produto/catálogo do anúncio e então extrai nota, texto, data e autor. Trate o endpoint abaixo como ilustrativo e confirme o caminho atual no DevTools.



def scrape_reviews(item_id, proxies=None):
    """Reviews live on a separate URL keyed by the item ID."""
    url = f"https://www.ebay.com/urw/{item_id}/product-reviews"
    html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
    soup = BeautifulSoup(html.text, "lxml")
    reviews = []
    for r in soup.select(".ebay-review-section"):
        rating = r.select_one(".star-rating")
        body   = r.select_one(".review-item-content")
        date   = r.select_one(".review-item-date")
        author = r.select_one(".review-item-author")
        reviews.append({
            "rating": rating.get("aria-label") if rating else None,
            "text":   body.get_text(strip=True) if body else None,
            "date":   date.get_text(strip=True) if date else None,
            "author": author.get_text(strip=True) if author else None,
        })
    return reviews


















Passo 6 — Exporte os dados para JSON e CSV

Salve seus resultados nos dois formatos ao mesmo tempo: JSON preserva a estrutura aninhada (útil para variantes e especificações), CSV é plano e abre direto no Excel ou Google Sheets.



import json, csv

results = scrape_search("smartphone")

# Option A - JSON (keeps nested structure)
with open("ebay.json", "w", encoding="utf-8") as f:
    json.dump(results, f, indent=2, ensure_ascii=False)

# Option B - CSV (flat, opens in Excel/Sheets)
if results:
    with open("ebay.csv", "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=results[0].keys())
        writer.writeheader()
        writer.writerows(results)














Passo 7 — Contorne as medidas anti-bot do eBay

O eBay defende os anúncios com um stack em camadas: pontuação de reputação de IP, limites de taxa (HTTP 429), bloqueios suaves (uma resposta 200 com resultado vazio) e CAPTCHAs. Você não vencerá tudo com um truque, mas os cabeçalhos e IPs certos resolvem os casos comuns para o web scraping do eBay em uma escala razoável.

Configure cabeçalhos adequados

Envie um conjunto completo e realista de cabeçalhos, não apenas um User-Agent. Cada cabeçalho reduz seu risco de bloqueio: a ausência de Accept-Language ou Referer é um sinal típico de bot. Para trabalhos maiores, rotacione o User-Agent a partir de uma lista.



HEADERS = {
    # identify as a real desktop browser - eBay returns 403/empty without this
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
    "Accept-Language": "en-US,en;q=0.9",      # match the locale you target
    "Accept-Encoding": "gzip, deflate, br",   # accept compressed responses
    "Referer": "https://www.ebay.com/",       # look like in-site navigation
    "Connection": "keep-alive",
}

# rotate the User-Agent across a list for larger jobs
import random
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Version/17.0 Safari/605.1.15",
]
HEADERS["User-Agent"] = random.choice(USER_AGENTS)

















Use proxies residenciais rotativos

Os cabeçalhos não bastam em volume: o eBay pontua a reputação de IP, e os proxies de data center são sinalizados muito mais rápido que os residenciais. Use IPs residenciais rotativos para scraping de busca em grande volume (um IP novo por requisição) e sessões sticky para fluxos de anúncio ou leilão onde importa uma sessão estável. Os proxies residenciais da DataImpulse custam US$ 1/GB, são pague-conforme-o-uso e se conectam direto na chamada ao requests.



# Route requests through DataImpulse rotating residential proxies
proxies = {
    "http":  "http://LOGIN:[email protected]:823",
    "https": "http://LOGIN:[email protected]:823",
}
html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)






Segmentação geográfica: scrapear dados do eBay por região

Os anúncios do eBay diferem por país: eBay.com, eBay.co.uk e eBay.de devolvem preços, disponibilidade e fretes diferentes para o mesmo produto. Para ver os dados que um comprador de um país específico vê, roteie por um proxy localizado lá. A DataImpulse tem IPs residenciais em 195 países, incluindo segmentação no nível de estado nos EUA, para que seu scraping de dados do eBay reflita o mercado certo. A mesma abordagem impulsiona a comparação de preços entre regiões.


Passo 8 — Escale seu scraper do eBay

Três níveis transformam o script básico em uma forma pronta para produção de fazer scraping do eBay com Python em escala, por ordem de complexidade crescente: um atraso aleatório entre requisições para não ultrapassar os limites de taxa, lógica de retry com backoff exponencial para absorver respostas 429/403, e coleta assíncrona com httpx + asyncio para volume em paralelo.



import time, random, asyncio, httpx

# 1) Basic pacing - a random delay between requests
def polite_get(url, **kw):
    time.sleep(random.uniform(1, 3))
    return requests.get(url, headers=HEADERS, timeout=30, **kw)

# 2) Retry with exponential backoff on 429/403
def get_with_retry(url, retries=4, **kw):
    for attempt in range(retries):
        r = requests.get(url, headers=HEADERS, timeout=30, **kw)
        if r.status_code not in (429, 403):
            return r
        time.sleep(2 ** attempt + random.random())   # 1s, 2s, 4s, 8s ...
    return r

# 3) Async collection for high volume (httpx >=0.28 uses proxy=, not proxies=)
async def scrape_many(urls, proxy=None):
    async with httpx.AsyncClient(headers=HEADERS, proxy=proxy, timeout=30) as client:
        tasks = [client.get(u) for u in urls]
        return await asyncio.gather(*tasks)





















Perguntas frequentes

É legal fazer scraping do eBay?

Depende. Scrapear dados publicamente disponíveis pode ser lícito em alguns contextos, mas o Acordo de Usuário do eBay restringe o acesso automatizado —bots, scrapers, ferramentas de mineração de dados— sem permissão prévia, então o scraping pode violar seus termos e gerar risco legal. Usar proxies em si é legal. Respeite os limites de taxa, não scrapeie atrás de um login, evite dados pessoais e busque aconselhamento jurídico para uso comercial. Isto é informação geral, não aconselhamento jurídico: veja nosso guia sobre se o web scraping é legal.

Preciso de proxies para scrapear o eBay?

Para algumas requisições, não. Para qualquer volume real, sim: o eBay pontua a reputação de IP e limita a taxa com rigor, então um único IP é bloqueado rápido. Os proxies residenciais rotativos distribuem as requisições por muitos IPs e permitem segmentar países específicos para preços corretos por região.

Como scrapeio as variantes de produto do eBay?

Variantes como tamanho e cor não estão no HTML visível: o eBay as guarda em um objeto JSON inline (MSKU) dentro de uma tag script. Localize esse objeto com re.search() e faça o parse com json.loads(), como no Passo 4.

Por que meu scraper do eBay devolve resultados vazios?

Quase sempre são os cabeçalhos. Sem um User-Agent de navegador real (e idealmente Accept-Language e Referer), o eBay frequentemente devolve um 403 ou um 200 com corpo vazio. Adicione o conjunto completo de cabeçalhos do Passo 7; se persistir, você provavelmente está limitado por taxa ou sinalizado por IP, então reduza o ritmo e roteie por um proxy residencial.

Como lido com a paginação do eBay em Python?

Incremente o parâmetro de URL _pgn (&_pgn=2, 3…) em um laço e pare quando o contêiner de resultados (li.s-item) estiver vazio ou você atingir um limite de páginas, como na função de paginação do Passo 3.


Conclusão

É assim que se faz scraping do eBay com Python de ponta a ponta: scrapers de resultados e de anúncios, paginação, extração de variantes ocultas, avaliações, exportação JSON/CSV e os cabeçalhos mais os proxies residenciais rotativos que mantêm seu setup de eBay scraper em Python funcionando. Comece pequeno com o scraper de busca e adicione depois paginação, cabeçalhos anti-bot e escalonamento conforme seu volume cresce. Para os IPs certos, veja melhores proxies para scraping do eBay.

Última atualização: 24 de junho de 2026.



Share article: