Quanto dura, in media, un tutorial su come scrapare eBay? Più o meno un trimestre. Lo dico perché in Thunderbit abbiamo visto sfilare un sacco di sviluppatori dietro snippet già morti, selettori CSS scaduti e repository GitHub “funzionanti” che a un certo punto smettono di farlo, in silenzio, due redesign di eBay più tardi.
Su eBay vivono circa 2,5 miliardi di inserzioni attive: il più grande archivio pubblico di prezzi long-tail in circolazione, secondo solo ad Amazon. Sono dati che muovono di tutto, dal pricing dei rivenditori all’analisi della concorrenza. Il problema è che recuperarli via codice è come centrare un bersaglio mobile: il frontend React di eBay rinomina di continuo le classi CSS, gli A/B test servono strutture DOM diverse a utenti diversi, e in mezzo tra te e l’HTML si piazza Akamai Bot Manager. In questa guida trovi codice Python che gira oggi, una spiegazione del perché gli scraper si rompono — così puoi costruirne di più solidi — un confronto senza sconti tra API di eBay e scraping, e un’alternativa no-code per quando Python non vale la candela del setup.
Cosa significa scrapare eBay con Python?
Scrapare eBay con Python vuol dire scrivere script che scaricano via codice le pagine di eBay, ne leggono l’HTML (oppure il JSON nascosto) e ne ricavano dati strutturati — titoli, prezzi, dati del venditore, date di vendita, dettagli delle varianti — in un formato che serve davvero a qualcosa: un CSV, un foglio di calcolo, un database.
Le pagine eBay che puoi estrarre sono di diversi tipi:
- Risultati di ricerca (per esempio tutte le inserzioni “AirPods Pro”)
- Pagine di dettaglio prodotto (specifiche complete, immagini, dati del venditore)
- Inserzioni vendute/completate (prezzi e date reali delle transazioni)
- Profili venditore e recensioni
Per questo tipo di lavoro Python resta il linguaggio più gettonato. Il suo ecosistema — Requests, BeautifulSoup, lxml, pandas — rende quasi banale scaricare pagine, leggere l’HTML e rimaneggiare i dati. Attenzione però a una distinzione importante, su cui torniamo a breve: fare scraping dell’HTML del sito non è la stessa cosa che usare l’API ufficiale di eBay.
Perché scrapare eBay? Casi d’uso reali per i team business
Se sei arrivato fin qui, un motivo preciso ce l’hai già. Vale comunque la pena ancorare il discorso a un valore di business concreto, perché sui dati di eBay il ROI è davvero notevole. Bain ha rilevato che un miglioramento dell’1% nel prezzo realizzato porta in media a un +11,1% di profitti su migliaia di aziende. McKinsey, dal canto suo, attribuisce al dynamic pricing nel retail fino al 5% di vendite in più e un 2–7% di margine recuperato.
Questi sono i casi d’uso che mi capitano sotto gli occhi più spesso:
| Caso d’uso | Dati necessari | Risultato di business |
|---|---|---|
| Monitoraggio prezzi e repricing | Prezzi delle inserzioni attive, spedizione, condizioni | Prezzi competitivi, protezione dei margini |
| Analisi dei concorrenti | Assortimento prodotti, promozioni, condizioni di spedizione | Posizionamento strategico, lacune di assortimento |
| Ricerca di mercato e individuazione trend | Velocità delle inserzioni, trend di categoria, modelli di domanda | Identificazione di nuovi prodotti, previsione della domanda |
| Pricing per rivenditori / valutazioni | Prezzi venduti, date di vendita, condizioni | Valore di mercato corretto, decisioni di acquisto |
| Analisi del sentiment | Recensioni, valutazioni, politica dei resi | Insight sulla qualità del prodotto, soddisfazione cliente |
| Lead generation | Profili venditore, informazioni sul negozio, contatti | Outreach B2B verso venditori ad alto GMV |

In fondo il succo è uno solo: eBay i dati ce li ha, ma sono chiusi a chiave dentro le pagine web.
Lo scraping è la chiave per trasformarli in vantaggio competitivo.
API ufficiale di eBay vs scraping Python: quale scegliere?
È la domanda a cui vorrei che più tutorial rispondessero giocando a carte scoperte. eBay mette a disposizione API ufficiali — su tutte la Browse API — e in tanti si chiedono se convenga affidarsi a quelle o andare di scraping diretto. La risposta dipende esclusivamente da quali dati ti servono.
| Criterio | API eBay Browse/Finding | Scraping Python |
|---|---|---|
| Inserzioni vendute/completate | Limitate — esiste la Marketplace Insights API, ma l’accesso viene spesso rifiutato | Accesso completo tramite parametri URL LH_Sold=1&LH_Complete=1 |
| Limiti di chiamata | 5.000 chiamate/giorno nel livello base | Gestione autonoma (dipende dai proxy) |
| Campi disponibili | Predefiniti (titolo, prezzo, categoria, basi del venditore) | Tutto ciò che è visibile nella pagina (recensioni, specifiche complete, varianti) |
| Complessità di setup | OAuth 2.0, registrazione app, chiavi API | pip install + codice |
| Stabilità | Endpoint stabili | Si rompe quando cambia l’HTML |
| Costo | C’è un piano gratuito, poi a pagamento per volumi | Codice gratuito, ma costi dei proxy su larga scala |
| Dati varianti/MSKU | Parziale — spesso solo SKU padre | Completo (tramite parsing del JSON nascosto) |
| Profondità della paginazione | Tetto massimo di 10.000 elementi | Teoricamente illimitata |
Una precisazione veloce: la vecchia Finding API (quella con findCompletedItems) è stata spenta del tutto a febbraio 2025. Se ti appoggi a ebaysdk-python o a qualunque libreria che interroghi il modulo Finding, oggi in produzione non hai più nulla che risponda.
Quello che consiglio io: la Browse API per query stabili, a volume moderato e con dati strutturati sulle inserzioni attive; lo scraping Python quando hai bisogno di prezzi di vendita, recensioni, dati delle varianti o di qualunque campo che l’API tenga per sé. Tanti team, alla fine, tengono il piede in entrambe le scarpe.
Strumenti e librerie necessari per scrapare eBay con Python
Prima di buttarsi sul codice, ecco la cassetta degli attrezzi. Per gran parte delle pagine eBay non serve nemmeno un browser headless: i dati sono già dentro l’HTML che il server restituisce renderizzato.
| Libreria | Scopo |
|---|---|
requests o httpx | Client HTTP per scaricare le pagine eBay |
curl_cffi | Client HTTP con fingerprint TLS da browser reale (fondamentale per aggirare Akamai) |
beautifulsoup4 | Parser HTML per estrarre tramite selettori CSS |
lxml | Backend di parsing veloce per BeautifulSoup |
jmespath | Linguaggio di query per analizzare blob JSON annidati |
pandas | Manipolazione dati ed esportazione CSV/Excel |
gspread | Integrazione con Google Sheets |
Installi tutto in una riga sola:
pip install requests httpx curl_cffi beautifulsoup4 lxml jmespath pandas gspread
Vai di Python 3.11+: pandas 3.0 vuole almeno la 3.10, e la 3.11 si porta dietro un 10–60% di velocità in più sui carichi I/O-bound.
C’è una libreria che merita un applauso a parte: curl_cffi è il singolo upgrade più utile che uno scraper eBay possa adottare nel 2026. eBay si appoggia ad Akamai Bot Manager, e l’arma principale di Akamai per smascherarti è il fingerprinting TLS. Una requests standard lascia un fingerprint JA3 che grida “Python” a un chilometro di distanza, e viene bloccata sul nascere. curl_cffi invece imita l’handshake TLS di un vero Chrome e ti porta a casa circa il 90% dei target protetti da Akamai, senza tirare in ballo un browser headless.
Prova Thunderbit su qualsiasi sito
Guida passo passo: come scrapare i risultati di ricerca eBay con Python
Eccoci al cuore della guida. Faremo scraping delle pagine dei risultati di ricerca eBay per tirare fuori le inserzioni.
- Difficoltà: Principiante–Intermedio
- Tempo richiesto: circa 30 minuti per il primo scraping funzionante
- Cosa ti serve: Python 3.11+, le librerie sopra, un terminale e un URL di ricerca eBay di destinazione
Passo 1: prepara il progetto Python
Crea la cartella del progetto e installa le dipendenze:
mkdir ebay-scraper && cd ebay-scraper
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install requests curl_cffi beautifulsoup4 lxml pandas
Crea poi un file scrape_ebay.py: sarà il tuo banco di lavoro.
Passo 2: costruisci l’URL di ricerca eBay
La struttura dell’URL di ricerca di eBay non ha segreti. Il parametro che conta è _nkw (la keyword):
import urllib.parse
keyword = "airpods pro"
base_url = "https://www.ebay.com/sch/i.html"
params = {
"_nkw": keyword,
"_ipg": "120", # elementi per pagina: 60, 120 o 240 (240 può far scattare i filtri anti-bot)
"_pgn": "1", # numero di pagina
}
url = f"{base_url}?{urllib.parse.urlencode(params)}"
print(url)
# https://www.ebay.com/sch/i.html?_nkw=airpods+pro&_ipg=120&_pgn=1
Altri parametri che tornano utili:
LH_BIN=1— solo Buy It Now_sacat=175673— categoria specifica_sop=12— ordina per miglior corrispondenza (10 = prezzo+spedizione più bassi, 13 = inserzioni appena pubblicate)LH_Complete=1&LH_Sold=1— inserzioni vendute/completate (ci dedichiamo una sezione più avanti)
Passo 3: invia una richiesta e gestisci la risposta
È qui che curl_cffi cambia le carte in tavola. Una banale requests.get() ti restituisce spesso un 403 firmato Akamai. Con curl_cffi, invece, ci spacciamo per un vero Chrome:
from curl_cffi import requests as cffi_requests
import random, time
USER_AGENTS = [
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0",
]
HEADERS = {
"User-Agent": random.choice(USER_AGENTS),
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
}
def fetch_page(url, max_retries=5):
delay = 2
for attempt in range(max_retries):
try:
r = cffi_requests.get(url, impersonate="chrome124", headers=HEADERS, timeout=30)
if r.status_code == 200:
return r.text
if r.status_code in (403, 429, 503):
retry_after = r.headers.get("Retry-After")
sleep_for = float(retry_after) if retry_after else delay + random.uniform(0, 1)
print(f" Status {r.status_code}, nuovo tentativo tra {sleep_for:.1f}s...")
time.sleep(sleep_for)
delay *= 2
continue
r.raise_for_status()
except Exception as e:
print(f" Errore nella richiesta: {e}, nuovo tentativo...")
time.sleep(delay)
delay *= 2
raise RuntimeError(f"Fallito dopo {max_retries} tentativi: {url}")
Il backoff esponenziale con jitter non è un dettaglio: intervalli di attesa sempre identici sono già di per sé un campanello che ti smaschera come bot.
Passo 4: analizza le inserzioni dalla pagina di ricerca
eBay in questo momento sta migrando a metà strada tra due layout dei risultati di ricerca. Uno scraper che voglia reggere deve sapersela cavare con entrambi:
| Campo | Layout legacy | Nuovo layout |
|---|---|---|
| Contenitore card | li.s-item | li.s-card o div.su-card-container |
| Titolo | .s-item__title | .s-card__title |
| URL | a.s-item__link[href] | a.su-link[href] |
| Prezzo | span.s-item__price | .s-card__price |
Ecco il codice di parsing che li copre tutti e due:
from bs4 import BeautifulSoup
def parse_search_results(html):
soup = BeautifulSoup(html, "lxml")
cards = soup.select("li.s-item, li.s-card, div.su-card-container")
results = []
for card in cards:
# Titolo — prova entrambi i layout
title_el = card.select_one(".s-item__title, .s-card__title")
title = title_el.get_text(strip=True) if title_el else None
# Salta la card fantasma “Shop on eBay”
if not title or "Shop on eBay" in title:
continue
# Prezzo
price_el = card.select_one("span.s-item__price, .s-card__price")
price = price_el.get_text(strip=True) if price_el else None
# URL
link_el = card.select_one("a.s-item__link[href], a.su-link[href]")
url = link_el["href"].split("?")[0] if link_el else None
# Immagine
img_el = card.select_one("img.s-item__image-img, .s-card__image img")
image = None
if img_el:
image = img_el.get("src") or img_el.get("data-src")
# Spedizione
ship_el = card.select_one("span.s-item__shipping, span.s-item__logisticsCost, .s-card__attribute-row")
shipping = ship_el.get_text(strip=True) if ship_el else None
results.append({
"title": title,
"price": price,
"url": url,
"image": image,
"shipping": shipping,
})
return results
La trappola della prima card fantasma è uno degli inciampi più classici. In molte pagine di ricerca eBay la prima li.s-item è un segnaposto nascosto, con il titolo “Shop on eBay” e nessun prezzo vero. Filtrala sempre via.
Passo 5: gestisci la paginazione per scrapare più pagine
eBay impagina con il parametro _pgn, mentre il link alla pagina successiva sta in a.pagination__next:
import urllib.parse
def scrape_ebay_search(keyword, max_pages=5):
all_results = []
for page_num in range(1, max_pages + 1):
params = {"_nkw": keyword, "_ipg": "120", "_pgn": str(page_num)}
url = f"https://www.ebay.com/sch/i.html?{urllib.parse.urlencode(params)}"
print(f"Scraping pagina {page_num}: {url}")
html = fetch_page(url)
results = parse_search_results(html)
if not results:
print(f" Nessun risultato alla pagina {page_num}, interrompo.")
break
all_results.extend(results)
print(f" Trovate {len(results)} inserzioni (totale: {len(all_results)})")
# Pausa cortese — 3-8 secondi con jitter
time.sleep(random.uniform(3, 8))
return all_results
Il jitter casuale tra 3 e 8 secondi non è un optional.
eBay e il suo strato Akamai mettono nel mirino il traffico sostenuto sopra 1 richiesta al secondo dallo stesso IP.
Passo 6: esporta i dati estratti in CSV o JSON
import pandas as pd
results = scrape_ebay_search("airpods pro", max_pages=3)
df = pd.DataFrame(results)
df.to_csv("ebay_airpods.csv", index=False)
df.to_json("ebay_airpods.json", orient="records", indent=2)
print(f"Esportate {len(df)} inserzioni in CSV e JSON.")
A questo punto dovresti avere tra le mani un foglio di calcolo pulito con le inserzioni eBay. Sulla mia macchina, scrapare 3 pagine (360 inserzioni) ha richiesto una quarantina di secondi, pause comprese.
Come scrapare le pagine di dettaglio prodotto eBay con Python
I risultati di ricerca ti danno il riassunto. È nelle pagine di dettaglio prodotto che c’è la roba buona: descrizioni complete, punteggi di feedback del venditore, specifiche dell’oggetto, caroselli di immagini, dati delle varianti.
Analizzare una singola pagina di inserzione
Le pagine degli articoli eBay vivono sotto /itm/<ITEM_ID>. La via di estrazione più stabile è il JSON-LD: eBay incorpora un blocco schema Product che sopravvive a quasi ogni cambio di CSS:
import json
def parse_item_page(html):
soup = BeautifulSoup(html, "lxml")
item = {}
# 1. JSON-LD — percorso di estrazione più stabile
for tag in soup.find_all("script", type="application/ld+json"):
try:
data = json.loads(tag.string or "")
except (json.JSONDecodeError, TypeError):
continue
if isinstance(data, dict) and data.get("@type") == "Product":
item["title"] = data.get("name")
item["brand"] = (data.get("brand") or {}).get("name")
item["images"] = data.get("image")
offers = data.get("offers") or {}
item["price"] = offers.get("price")
item["currency"] = offers.get("priceCurrency")
break
# 2. Fallback CSS per i campi non presenti nel JSON-LD
def first_text(selectors):
for sel in selectors:
el = soup.select_one(sel)
if el and el.get_text(strip=True):
return el.get_text(strip=True)
return None
item.setdefault("title", first_text([
"h1.x-item-title__mainTitle",
"h1.x-item-title__mainTitle .ux-textspans--BOLD",
]))
item["condition"] = first_text([
".x-item-condition-text .ux-textspans",
])
item["seller"] = first_text([
".x-sellercard-atf__info__about-seller a .ux-textspans",
])
item["shipping"] = first_text([
"div.ux-labels-values--shipping .ux-textspans--BOLD",
])
# 3. Specifiche dell’oggetto
specifics = {}
for dl in soup.select(".ux-layout-section-evo__item--table-view dl.ux-labels-values"):
k = dl.select_one(".ux-labels-values__labels-content .ux-textspans")
v = dl.select_one(".ux-labels-values__values-content .ux-textspans")
if k and v:
specifics[k.get_text(strip=True).rstrip(":")] = v.get_text(strip=True)
item["specifics"] = specifics
return item
Lo schema qui — prima JSON-LD, poi il fallback CSS — è proprio la chiave per scraper che non vanno in pezzi a ogni trimestre. Ci torniamo più sotto.
Scraping delle varianti prodotto eBay (dati MSKU)
Certe inserzioni eBay hanno più varianti: colori diversi, taglie diverse, tagli di memoria diversi. Nel DOM visibile vedi solo una forchetta di prezzo tipo “899 € - 1.099 €” finché l’utente non sceglie un’opzione. Il prezzo reale di ogni variante sta dentro un oggetto JavaScript nascosto, chiamato MSKU.
È uno di quei casi in cui l’API di eBay ti passa solo dati parziali (lo SKU padre), e lo scraping diventa la scelta migliore.
import re, json
def extract_variants(html):
# Il match non greedy è fondamentale — il .+ greedy ingoia l’intera pagina
m = re.search(r'"MSKU"\s*:\s*(\{.+?\})\s*,\s*"QUANTITY"', html, re.DOTALL)
if not m:
return []
try:
msku = json.loads(m.group(1))
except json.JSONDecodeError:
return []
item_labels = {str(k): v["displayLabel"] for k, v in msku.get("menuItemMap", {}).items()}
skus = []
for combo_key, variation_id in msku.get("variationCombinations", {}).items():
option_ids = combo_key.split("_")
options = [item_labels.get(oid, oid) for oid in option_ids]
var = msku.get("variationsMap", {}).get(str(variation_id), {})
bin_model = var.get("binModel", {})
price_spans = bin_model.get("price", {}).get("textSpans", [{}])
price = price_spans[0].get("text") if price_spans else None
qty = var.get("quantity")
skus.append({
"options": options,
"price": price,
"quantity_available": qty,
"variation_id": variation_id,
})
return skus
Quel (.+?) non greedy nella regex è il punto esatto in cui ogni scraper eBay rischia di cadere. Il .+ greedy ingoia tutto fino all’ultimo "QUANTITY" della pagina e ti restituisce JSON malformato. Questo bug l’ho beccato in almeno tre tutorial spacciati per “funzionanti”.
Come scrapare le inserzioni vendute e completate di eBay con Python
È questo il caso d’uso che davvero giustifica lo scraping al posto dell’API. I dati degli articoli venduti — cosa è passato di mano per davvero, a che prezzo, in quale data — sono lo standard d’oro per ricerca di mercato, pricing dei rivenditori e valutazioni. La Browse API di eBay non te li dà in modo esplicito. La Marketplace Insights API, sulla carta, sì, ma l’accesso è una “Limited Release” e viene rifiutato di frequente.
I parametri URL che servono sono LH_Complete=1 (inserzioni completate) e LH_Sold=1 (solo quelle effettivamente vendute). Ci vogliono entrambi. Usare il solo LH_Sold=1 su certe categorie ti riporta in silenzio alle inserzioni attive: è la trappola in cui inciampa quasi tutta la community.
def scrape_sold_listings(keyword, max_pages=3):
all_sold = []
for page_num in range(1, max_pages + 1):
params = {
"_nkw": keyword,
"_ipg": "120",
"_pgn": str(page_num),
"LH_Complete": "1",
"LH_Sold": "1",
}
url = f"https://www.ebay.com/sch/i.html?{urllib.parse.urlencode(params)}"
print(f"Scraping pagina venduti {page_num}...")
html = fetch_page(url)
soup = BeautifulSoup(html, "lxml")
cards = soup.select("li.s-item")
for card in cards:
title_el = card.select_one(".s-item__title")
title = title_el.get_text(strip=True) if title_el else None
if not title or "Shop on eBay" in title:
continue
# Includi solo gli articoli effettivamente venduti (prezzo verde nel wrapper POSITIVE)
sold_tag = card.select_one(
".s-item__title--tag .POSITIVE, .s-item__caption--signal.POSITIVE"
)
if sold_tag is None:
continue # Inserzione completata ma non venduta — salta
price_el = card.select_one("span.s-item__price")
price = price_el.get_text(strip=True) if price_el else None
# Estrai la data di vendita
sold_date = None
import re, datetime as dt
card_text = card.get_text()
m = re.search(r"Sold\s+([A-Z][a-z]{2}\s+\d{1,2},\s*\d{4})", card_text)
if m:
sold_date = dt.datetime.strptime(m.group(1), "%b %d, %Y").strftime("%Y-%m-%d")
link_el = card.select_one("a.s-item__link[href]")
url = link_el["href"].split("?")[0] if link_el else None
all_sold.append({
"title": title,
"sold_price": price,
"sold_date": sold_date,
"url": url,
})
if not cards:
break
time.sleep(random.uniform(3, 8))
return all_sold
La differenza chiave a livello di HTML: gli articoli venduti mostrano il prezzo in verde (dentro un wrapper .POSITIVE), mentre le inserzioni completate ma rimaste invendute lo mostrano in rosso barrato. Filtra sempre sulla classe .POSITIVE.
Perché gli scraper eBay si rompono (e come costruirne di resistenti)
Se il tuo scraper eBay ha smesso di funzionare, sappi che non sei solo. È il lamento numero uno in ogni thread sullo scraping di eBay che mi sia capitato di leggere. La domanda non è se il tuo scraper si romperà, ma quando.
Perché succede:
- eBay renderizza in React con classi generate al volo, che cambiano a ogni deploy
- Gli A/B test servono strutture DOM diverse a utenti diversi (il doppio layout
s-item/s-cardne è la prova vivente) - I redesign periodici del sito spostano il nesting dell’HTML, anche quando i dati restano identici
- Vecchi selettori come
#itemTitlee#prcIsumsono stati rimossi anni fa, ma continuano a spuntare nei tutorial
Come scrive la guida 2026 di Scrapfly: “La vera sfida nello scraping di eBay è gestire i cambiamenti dei selettori CSS. eBay aggiorna regolarmente il frontend, rompendo gli scraper che si affidano a nomi di classe specifici.”

Strategie di difesa per scraper eBay di lunga durata
Quattro strategie che reggono meglio ai rimescolamenti trimestrali di eBay:
1. Metti il JSON-LD davanti ai selettori CSS. eBay incorpora dati strutturati dello schema Product in ogni pagina articolo. Il livello dei dati si muove molto meno di quello di presentazione: i designer rifanno le classi CSS ogni trimestre, ma i nomi dei campi backend come price, name e seller sono agganciati ad API interne e quasi mai vengono rinominati.
2. Usa selettori di fallback a cascata. Non puntare mai tutto su un solo selettore CSS. Tieni sempre pronte delle alternative:
def first_text(soup, selectors):
for sel in selectors:
el = soup.select_one(sel)
if el and el.get_text(strip=True):
return el.get_text(strip=True)
return None
title = first_text(soup, [
"h1.x-item-title__mainTitle",
"h1.x-item-title__mainTitle .ux-textspans--BOLD",
"[data-testid='x-item-title'] h1",
])
3. Vai a pescare nei blob JSON nascosti. L’oggetto varianti MSKU e i dati JavaScript inline sopravvivono ai cambi CSS perché vengono generati lato server. Estrarli con regex dai tag <script> costa più fatica all’inizio, ma ti risparmia parecchia manutenzione dopo.
4. Logga i fallimenti dei selettori. Aggiungi un monitoraggio che ti dica quando un selettore smette di agganciare, non solo che il dato è vuoto:
if title is None:
print(f"WARNING: title selector failed for {url}")
5. Usa curl_cffi con l’impersonificazione del browser. Così gestisci il TLS fingerprinting di Akamai senza dover scomodare un browser headless.
L’alternativa basata su AI: zero manutenzione dei selettori
Se sei stanco di rattoppare selettori ogni due o tre mesi, c’è un approccio del tutto diverso. Strumenti come Thunderbit usano l’AI per leggere la pagina da zero ogni volta e dedurre al volo la logica di estrazione. Uno studio della McGill University ha messo alla prova scraper basati su AI e su selettori su 3.000 pagine, scoprendo che i metodi AI tenevano un’accuratezza del 98,4% anche dopo i cambi di layout, con benchmark di settore che parlano di una riduzione del 60–80% nella manutenzione degli scraper.
| Approccio | Si rompe quando eBay cambia l’HTML? | Impegno di manutenzione |
|---|---|---|
| Selettori CSS hardcoded | Sì, ogni trimestre | Alto — patch continue |
| Estrazione da JSON nascosto / JSON-LD | Raramente | Basso |
| Scraping basato su AI (Thunderbit) | No — l’AI ricalcola i selettori a ogni esecuzione | Nessuno |
Estrai dati eBay con l’AI Get Started Free
Più avanti entriamo nel dettaglio del flusso di lavoro di Thunderbit. Per ora il punto è questo: se stai costruendo uno scraper destinato a girare per mesi, conviene investire in estrazione JSON-first e selettori di fallback. Se invece non hai voglia di mantenere selettori, punto e basta, l’approccio AI merita uno sguardo.
Automatizzare scraping eBay ricorrenti per il monitoraggio prezzi
Uno scraping una tantum fa il suo lavoro. Ma monitoraggio prezzi, tracking delle scorte e analisi della concorrenza vogliono raccolte dati ricorrenti. Tutti gli articoli dei competitor citano il monitoraggio prezzi come caso d’uso, eppure quasi nessuno mostra davvero come automatizzarlo.
Opzione 1: cron job (Linux/macOS) o Utilità di pianificazione (Windows)
La strada più diretta. Incartiamo lo script Python in un cron job. Usa sempre il percorso assoluto dell’interprete Python del virtual environment, perché cron parte con un ambiente ridotto all’osso:
crontab -e
# Ogni giorno alle 08:15
15 8 * * * /Users/me/ebay/venv/bin/python /Users/me/ebay/scrape_ebay.py >> /Users/me/ebay/scrape.log 2>&1
Su Windows, si passa per PowerShell:
$A = New-ScheduledTaskAction -Execute "C:\Users\me\ebay\venv\Scripts\python.exe" -Argument "C:\Users\me\ebay\scrape_ebay.py"
$T = New-ScheduledTaskTrigger -Daily -At 8:15am
Register-ScheduledTask -TaskName "eBayScraper" -Action $A -Trigger $T
Ti serve però una macchina sempre accesa, e proxy e misure anti-bot restano sulle tue spalle.
Opzione 2: funzioni cloud (serverless)
Con AWS Lambda o Google Cloud Functions puoi far girare gli scraper senza un server dedicato. In cambio chiedono più setup: devi impacchettare le dipendenze, tenere d’occhio i timeout (Lambda si ferma a 15 minuti) e comunque gestire i proxy. In compenso, di server da mantenere non ce n’è.
Opzione 3: scheduling no-code con Thunderbit
Lo Scheduled Scraper di Thunderbit ti lascia descrivere l’intervallo in linguaggio naturale (per esempio “ogni giorno alle 8”), incollare gli URL di eBay e cliccare su Schedule. Il resto gira nel cloud, con la gestione anti-bot già integrata.
| Approccio | Sforzo di setup | Serve un server? | Gestisce l’anti-bot? |
|---|---|---|---|
| Cron + script Python | Medio | Sì (macchina sempre attiva) | Devi gestire i proxy |
| Funzione cloud (Lambda) | Alto | No (serverless) | Devi gestire i proxy |
| Thunderbit Scheduled Scraper | Basso (descrivi a parole) | No (cloud) | Integrato |
Per archiviare i dati dello scraping ricorrente, un database SQLite locale è la scelta migliore per la cronologia prezzi. Usa ON CONFLICT ... DO UPDATE (e non INSERT OR REPLACE, che manda in tilt le foreign key e azzera le colonne):
CREATE TABLE IF NOT EXISTS listings (
item_id TEXT PRIMARY KEY,
title TEXT NOT NULL,
price REAL,
last_price REAL,
first_seen_at TEXT DEFAULT (datetime('now')),
last_seen_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS price_history (
item_id TEXT NOT NULL,
observed_at TEXT NOT NULL DEFAULT (datetime('now')),
price REAL NOT NULL,
PRIMARY KEY (item_id, observed_at)
);
Prova Thunderbit Scheduled Scraper
Non vuoi programmare? Come scrapare eBay in 2 minuti con Thunderbit
Ho speso 2.000 parole di codice Python. Ora però voglio essere onesto su quando non ti serve affatto.
Se sei un utente business che fa una ricerca di mercato spot, un rivenditore che controlla i comparabili, o un team ecommerce che ha bisogno di dati oggi senza aprire uno sprint di sviluppo, Python è sovradimensionato. Setup, manutenzione dei selettori, gestione dei proxy: troppo overhead per un “mi servono solo queste 200 inserzioni in un foglio di calcolo”.
Come Thunderbit scrapare eBay (passo dopo passo)
- Installa l’estensione Chrome di Thunderbit — senza carta di credito.
- Apri in Chrome una qualsiasi pagina di risultati di ricerca o una pagina prodotto eBay.
- Clicca “AI Suggest Fields” nella sidebar di Thunderbit. L’AI legge la pagina e ti propone le colonne: Titolo, Prezzo, Condizione, Spedizione, Venditore, Valutazione.
- Clicca “Scrape.” L’estensione segue la paginazione e riempie la tabella dati. Per eBay in particolare, Thunderbit mette a disposizione template scraper istantanei già pronti, che partono con un solo clic.
- Esporta su Google Sheets, Airtable, Notion, CSV, JSON o Excel — gratis.
Tutto il giro si chiude in meno di 2 minuti.
L’ho cronometrato.
Arricchimento delle sottopagine: i dati delle pagine dettaglio senza una riga di codice in più
Una volta estratta la pagina dei risultati, Thunderbit può andare a visitare la pagina di dettaglio di ogni inserzione e aggiungere campi extra: specifiche complete, dati del venditore, descrizione, tutte le immagini. In pratica, le 20+ righe di codice Python per lo scraping delle sottopagine che abbiamo scritto prima si riducono a un clic.
Quando ha ancora senso usare Python
Python vince quando ti servono:
- Scraping su larga scala (decine di migliaia di pagine per esecuzione)
- Logiche di parsing o trasformazione dati molto su misura
- Integrazione in pipeline dati già esistenti (Airflow, dbt, Kafka)
- Controllo fine su TLS/sessione per lavori anti-bot avanzati
- Economia di scala — su milioni di righe, uno stack mantenuto in casa batte un SaaS a crediti
Per la maggior parte dei progetti one-off o di media scala, Thunderbit è più veloce e più semplice. Per pipeline di produzione su larga scala, Python ti mette in mano il controllo totale.
Consigli per evitare il blocco quando scrapare eBay con Python
eBay e il suo strato Akamai sono roba seria. Ecco cosa funziona davvero sul campo:
- Usa
curl_cfficonimpersonate="chrome124"— è il salto in avanti più netto rispetto arequestsstandard - Ruota gli User-Agent pescando da una lista di versioni browser recenti (Chrome 143, Firefox 124, Safari 26)
- Inserisci ritardi casuali di 3–8 secondi tra le richieste — gli intervalli fissi sono un fingerprint
- Usa proxy residenziali o rotanti per qualunque lavoro oltre poche decine di pagine. Gli IP da data center (AWS, GCP, DigitalOcean) Akamai li segnala in un attimo.
- Rispetta
robots.txt— molti URL di browse filtrati sono esplicitamente in Disallow; le pagine dettaglio articolo (/itm/<id>) di solito no - Gestisci i CAPTCHA con calma — intercettali e riprova con un IP diverso, oppure appoggiati a un servizio di solving
- Non martellare il server. Il precedente eBay v. Bidder's Edge stabilisce che il “trespass to chattels” scatta quando lo scraping degrada davvero i server. Restando sotto 1 richiesta al secondo per IP, da quella soglia stai a debita distanza.
Per un uso commerciale ad alto volume, valuta di tirar fuori le inserzioni attive dalla Browse API e di riservare lo scraping mirato ai soli comparabili venduti e ai dati che l’API non espone. Questo approccio ibrido è più pulito sia sul piano tecnico sia su quello legale.
È legale scrapare eBay con Python?
Non sono un avvocato, e questo articolo non è una consulenza legale. Quindi la faccio breve.
Il quadro giuridico si è spostato a favore dello scraping dei dati pubblicamente accessibili. I precedenti che contano:
- hiQ v. LinkedIn (9th Cir., 2022): scrapare dati pubblicamente accessibili non viola il CFAA
- Van Buren v. United States (SCOTUS, 2021): ha ristretto la clausola “exceeds authorized access” del CFAA
- Meta v. Bright Data (N.D. Cal., 2024): lo scraping da logout non viola i termini della piattaforma, perché lo scraper non è un “utente”
Detto questo, l’aggiornamento dell’User Agreement di eBay di febbraio 2026 vieta espressamente “buy-for-me agents, LLM-driven bots, o qualunque flusso end-to-end che tenti di effettuare ordini senza revisione umana.” Il confine è netto: lo scraping in sola lettura di pagine pubbliche poggia su basi solide; automatizzare il checkout no.
Buone pratiche: estrai solo dati pubblicamente visibili. Niente account falsi, niente login da aggirare. Non rivendere in blocco immagini protette da copyright. E per progetti commerciali su larga scala, fatti sentire un legale.
Conclusione e punti chiave
Python resta il modo più flessibile per scrapare eBay, ma chiede manutenzione costante ogni volta che cambia l’HTML del sito. La logica decisionale è questa:
- Usa la Browse API di eBay per query stabili, a volume moderato, sulle inserzioni attive
- Usa lo scraping Python per inserzioni vendute, recensioni, dati delle varianti e qualunque campo che l’API non espone
- Usa Thunderbit se vuoi i dati eBay senza scrivere né mantenere codice
Il codice di questa guida mette la resilienza al primo posto: prima l’estrazione JSON-LD, poi i fallback CSS a cascata, infine il parsing del JSON nascosto per le varianti. È questo approccio a strati a fare in modo che il tuo scraper non muoia al prossimo rifacimento del frontend di eBay.
Se vuoi tastare la strada no-code, il piano gratuito di Thunderbit ti permette di provarlo subito sulle pagine eBay. E se vuoi vedere all’opera il template eBay scraper, è a un clic di distanza.
Per altri contenuti sugli strumenti di web scraping, fai un salto sulle nostre guide ai migliori strumenti automatizzati di web scraping, su come estrarre dati da un sito web in Excel e sui migliori strumenti Python per il web scraping. Puoi anche dare un’occhiata ai tutorial sul canale YouTube di Thunderbit.
Prova Thunderbit per scrapare eBay Get Started Free
FAQ
1. Posso scrapare eBay gratuitamente con Python?
Sì. Tutte le librerie (Requests, BeautifulSoup, curl_cffi, pandas) sono gratuite e open source. I costi arrivano con la scala: i proxy residenziali per scraping ad alto volume viaggiano in genere sui 50–500 $ al mese, a seconda della banda. Per progetti piccoli (qualche centinaio di pagine) puoi lavorare dal tuo IP di casa, con un rate limiting attento.
2. Come faccio a scrapare gli articoli venduti e le inserzioni completate di eBay con Python?
Aggiungi LH_Complete=1&LH_Sold=1 ai parametri dell’URL di ricerca. Ci vogliono entrambi: il solo LH_Sold=1, in alcune categorie, ti riporta in silenzio alle inserzioni attive. Poi filtra i risultati controllando la classe CSS .POSITIVE sull’elemento prezzo, che segnala una vendita vera e non un’inserzione scaduta e invenduta.
3. eBay blocca il web scraping?
eBay usa Akamai Bot Manager, che individua gli scraper soprattutto via fingerprint TLS e analisi comportamentale. Le chiamate requests standard si beccano spesso un 403. Usare curl_cffi con impersonificazione del browser, User-Agent rotanti e ritardi casuali di 3–8 secondi tra le richieste risolve la maggior parte dei blocchi. Su scala, i proxy residenziali aiutano.
4. Dovrei usare l’API di eBay o lo scraping web?
La Browse API per query stabili, a volume moderato, sulle inserzioni attive (fino a 5.000 chiamate/giorno). Lo scraping quando ti servono storico dei prezzi venduti, dati completi delle varianti/MSKU, recensioni o qualunque campo che l’API non espone. La Marketplace Insights API in teoria fornisce i dati venduti, ma l’accesso è limitato e viene rifiutato di frequente.
5. Qual è il modo più semplice per scrapare eBay senza programmare?
L’estensione Chrome di Thunderbit usa l’AI per leggere le pagine eBay, proporre le colonne dati ed estrarre le inserzioni con un clic. Gestisce paginazione e arricchimento delle sottopagine, ed esporta su Google Sheets, Excel, Airtable o Notion. I template eBay scraper già pronti lo rendono ancora più rapido sui casi d’uso più comuni.
Scopri di più


