Bot Tracker Biglietti Concerti
Bot Telegram che monitora la disponibilità di biglietti su FanSale (rivendita) e TicketOne (primaria) e notifica l'utente appena un biglietto per la data tracciata diventa disponibile. Tre componenti disaccoppiati: API di scraping, bot e worker asincrono.
Contesto
Comprare biglietti per i concerti su siti di rivendita come FanSale è una corsa contro il tempo: i biglietti compaiono e spariscono in minuti. Il progetto è un bot Telegram che permette di impostare “tracker” su date specifiche e notifica appena un biglietto diventa disponibile.
Il sistema doveva essere efficiente (poche richieste ai siti, rischio di blocco anti-bot) e manutenibile (i siti cambiano struttura HTML e API continuamente).
Architettura
Il sistema è progettato come tre componenti disaccoppiati, ciascuno con una responsabilità chiara:
flowchart LR
U["Utente Telegram"] <--> B["Bot Telegram<br/>python-telegram-bot"]
B -->|"scelte utente"| API["API FastAPI<br/>scraping centralizzato"]
API -->|"scrapling / Playwright"| FAN["FanSale"]
API -->|"API ufficiale"| T1["TicketOne"]
W["Worker asincrono<br/>(asyncio)"] -->|"aggiornamenti periodici"| API
W <--> DB[("SQLite<br/>artists / events / trackers")]
B <--> DB
API, bot e worker: tre componenti che condividono il database
-
Livello API (FastAPI). Interfaccia RESTful centralizzata per tutto lo scraping. Il bot non contiene logica di scraping: se un sito cambia struttura, si aggiorna solo l’endpoint. Lo scraping usa scrapling (httpx + selectolax) con fallback Playwright per contenuti caricati via JavaScript.
-
Livello Bot (python-telegram-bot).
ConversationHandlerper flussi guidati a stati (aggiunta/rimozione tracker). Il bot è “stupido”: presenta informazioni e raccoglie scelte, tutta la logica di business è nell’API e negli helper. -
Livello Worker (asyncio). Esegue i task periodici in background: aggiorna i dati FanSale a intervalli brevi, i dati TicketOne ogni 24h (nuove date o cancellazioni), e processa le notifiche confrontando i dati aggiornati con i tracker degli utenti.
Ottimizzazione chiave: il caching nel database
Il problema: se 100 utenti tracciano 10 concerti diversi dello stesso artista, un approccio ingenuo farebbe 100 richieste alla stessa pagina FanSale. La soluzione:
- Il worker esegue una sola richiesta per artista e salva la lista completa dei biglietti in JSON nel campo
fansale_tickets_bodydella tabellaartists. - Quando si controllano le notifiche, il sistema legge il dato in cache dal DB per tutti gli utenti, senza più contattare FanSale.
Riduce drasticamente il numero di richieste e il rischio di essere bloccati, a costo di una latenza di aggiornamento pari all’intervallo del worker (configurabile).
Strategia anti-bot
Il reverse engineering dei siti è documentato nel repository: su FanSale, Playwright headless intercetta solo la challenge Akamai e poi Access Denied; curl_cffi con impersonazione safari17_0 riceve invece l’HTML reale. Lo scraper prova quindi prima la strada leggera e usa Playwright solo come fallback. Due script di discovery (tools/) permettono di ispezionare endpoint nascosti senza toccare il bot produttivo.
Scelte progettuali
- API separata dal bot: disaccoppiamento che rende lo scraping riusabile (futura dashboard/mobile) e isolato da modifiche dei siti.
- Aggiornamenti in batch: prima l’aggiornamento di massa di artisti/eventi, poi l’elaborazione notifiche — non un controllo tracker per tracker.
- Query efficienti:
get_all_active_trackers_efficiently()carica i dati degli artisti (con i body cache) e li unisce in Python con i tracker, invece di JOIN complessi per utente.
Risultati
Un sistema funzionante end-to-end: l’utente cerca l’artista/tour via API TicketOne, seleziona l’evento e la data, e riceve notifiche Telegram istantanee quando il biglietto compare su FanSale. Docker Compose per l’avvio dell’intero stack.