Come estraggo Hacker News con Python (2 metodi, codice completo)

Ultimo aggiornamento il April 16, 2026

Qualche mese fa volevo creare un digest giornaliero delle storie più importanti di Hacker News per il team di Thunderbit. Il mio primo istinto è stato semplicemente aggiungere il sito ai preferiti e scorrerlo ogni mattina. È andata avanti per circa tre giorni, poi mi sono reso conto che stavo perdendo 20 minuti al giorno solo per leggere titoli e copiare-incollare link in un foglio di calcolo.

Hacker News è una delle fonti più ricche e concentrate di intelligence tecnologica su internet — circa , all’incirca 1.300 nuove storie inviate ogni giorno e circa 13.000 commenti generati quotidianamente. Che tu stia monitorando i trend tecnologici emergenti, controllando il tuo brand, costruendo un flusso di recruiting dalle discussioni “Who’s Hiring” o semplicemente cercando di restare al passo con ciò che conta per il mondo developer, tenerne traccia manualmente è una battaglia persa.

La buona notizia: estrarre dati da Hacker News con Python è sorprendentemente semplice. In questa guida ti mostrerò due metodi completi — il parsing HTML con BeautifulSoup e la Firebase API ufficiale di HN — insieme a paginazione, esportazione dei dati, pattern pronti per la produzione e una scorciatoia no-code per quando Python sembra eccessivo.

Perché estrarre Hacker News con Python?

Hacker News non è solo un altro aggregatore di link. È un feed curato dalla community in cui le storie tech più interessanti emergono grazie ai voti e alle discussioni attive. Il pubblico è fortemente orientato ai professionisti della tecnologia (circa ), e il 66% di traffico diretto del sito ti dice chiaramente che si tratta di una community fedele e abituale, non di visitatori occasionali.

Ecco perché molte persone estraggono dati da HN:

Caso d’usoCosa ottieni
Digest tech giornalieroStorie principali, punteggi e link consegnati via email o Slack
Monitoraggio brand/concorrentiAvvisi quando viene citata la tua azienda o il tuo prodotto
Analisi dei trendTraccia quali tecnologie, linguaggi o argomenti stanno guadagnando trazione nel tempo
RecruitingAnalizza i thread “Who’s Hiring” per offerte di lavoro, stack tecnologici e segnali salariali
Ricerca contenutiTrova argomenti ad alte prestazioni su cui scrivere o da condividere
Analisi del sentimentValuta l’opinione della community su prodotti, lanci o cambiamenti del settore

Aziende con una capitalizzazione complessiva superiore a 400 miliardi di dollari — Stripe, Dropbox, Airbnb — attribuiscono a Hacker News feedback iniziali cruciali e acquisizione di utenti. Drew Houston pubblicò la demo di Dropbox su HN nell’aprile 2007, arrivò al primo posto e la lista d’attesa beta passò da 5.000 a 75.000 utenti in un solo giorno. I dati di HN non sono solo interessanti: hanno valore commerciale.

I dati sono pubblici, ma la struttura del sito rende la raccolta manuale noiosa. L’automazione con Python è la soluzione pratica.

Due modi per estrarre Hacker News con Python: panoramica

Questa guida copre due approcci completi ed eseguibili:

  1. Parsing HTML con requests + BeautifulSoup — scarica l’HTML grezzo di news.ycombinator.com e analizzalo per estrarre i dati delle storie. Ottimo per imparare le basi dello scraping e prendere esattamente ciò che compare nella pagina.
  2. La Firebase API ufficiale di Hacker News — interroga direttamente endpoint JSON, senza bisogno di parsing HTML. Più adatta a pipeline affidabili, all’accesso ai commenti e ai dati storici.

Ecco un confronto affiancato per aiutarti a scegliere la soluzione più adatta:

CriterioScraping HTML (requests + BS4)HN Firebase APIThunderbit (No-Code)
Complessità inizialeMedia (selettori HTML da interpretare)Bassa (endpoint JSON)Nessuna (estensione Chrome in 2 clic)
Freschezza dei datiFront page in tempo realeTempo reale (qualsiasi item tramite ID)Tempo reale
Rischio di rate limitMedio (robots.txt indica 30s di crawl delay)Basso (API ufficiale, permissiva)Gestito da Thunderbit
Accesso ai commentiDifficile (HTML annidato)Facile (ID degli item in modo ricorsivo)Funzione di scraping delle sottopagine
Dati storiciLimitatiTramite Algolia Search APIN/D
Ideale perImparare le basi dello scrapingPipeline dati affidabiliNon sviluppatori, export rapidi

Entrambi i metodi includono codice Python completo e funzionante. E se vuoi solo i dati senza scrivere codice, ti mostrerò anche quella strada.

Prima di iniziare

  • Difficoltà: da principiante a intermedio
  • Tempo richiesto: circa 15–20 minuti per ciascun metodo
  • Cosa ti serve:
    • Python 3.11+ installato
    • Un terminale o un editor di codice
    • Browser Chrome (se vuoi ispezionare l’HTML di HN o provare l’opzione no-code)
    • (facoltativa, per il metodo no-code)

scrape-hacker-news-methods.webp

Configurare l’ambiente Python

Prima di toccare i dati di HN, prepariamo l’ambiente. Ti consiglio di creare un ambiente virtuale, così le dipendenze del progetto restano pulite.

1# Crea e attiva un ambiente virtuale
2python3 -m venv hn-scraper
3# macOS/Linux:
4source hn-scraper/bin/activate
5# Windows:
6hn-scraper\Scripts\activate
7# Installa i pacchetti necessari per entrambi i metodi
8pip install requests==2.33.1 beautifulsoup4==4.14.3 pandas==3.0.2 openpyxl==3.1.5

Per i pattern più adatti alla produzione più avanti (cache, retry), ti serviranno anche:

1pip install requests-cache==1.3.1 tenacity==9.1.4

Nessuna chiave API speciale, nessun token di autenticazione. I dati di HN sono pubblici.

Metodo 1: estrarre Hacker News con Python usando BeautifulSoup

Questo è l’approccio classico — scarichi l’HTML, lo analizzi e recuperi i dati che ti servono. È il modo con cui la maggior parte delle persone impara il web scraping, e il layout semplice di HN basato su tabelle lo rende un ottimo banco di prova.

Passo 1: recuperare la front page di Hacker News

Apri l’editor e crea un file chiamato scrape_hn_bs4.py. Ecco il codice iniziale:

1import requests
2from bs4 import BeautifulSoup
3> This paragraph contains content that cannot be parsed and has been skipped.
4print(f"Status: {response.status_code}, Page length: {len(response.text)} chars")

Eseguilo. Dovresti vedere Status: 200 e una lunghezza della pagina intorno ai 40.000–50.000 caratteri. È l’HTML grezzo della front page di HN già in memoria, pronto per essere analizzato.

Passo 2: capire la struttura HTML

HN usa un layout basato su tabelle — niente moderni grid CSS o flexbox. Ogni storia nella pagina è composta da due righe <tr> chiave:

  • La riga della storia (<tr class="athing submission">): contiene posizione, titolo e link
  • La riga dei metadati (la <tr> successiva): contiene punti, autore, orario e numero di commenti

I selettori importanti:

  • span.titleline > a — titolo e URL della storia
  • span.score — punteggio/voti (ad esempio “118 points”)
  • a.hnuser — username dell’autore
  • span.age — orario di pubblicazione
  • L’ultimo <a> in .subtext con la parola “comment” nel testo — numero di commenti

Se fai clic destro sul titolo di una storia in Chrome e scegli “Ispeziona”, vedrai qualcosa del genere:

1<span class="titleline">
2  <a href="https://darkbloom.dev">DarkbloomPrivate inference on idle Macs</a>
3</span>

E sotto, la riga dei metadati:

1<span class="score" id="score_47788542">118 points</span>
2by <a href="user?id=twapi" class="hnuser">twapi</a>
3<span class="age" title="2026-04-16T04:06:39 1776312399">
4  <a href="item?id=47788542">2 hours ago</a>
5</span>
6| <a href="item?id=47788542">65&nbsp;comments</a>

Capire questi selettori è fondamentale: se HN cambiasse il markup, dovresti aggiornarli. (Spoiler: il metodo API evita del tutto questo problema.)

Ora entra in gioco il lavoro vero. Scorreremo ogni riga delle storie, prenderemo titolo e link dalla riga principale, poi il punteggio dalla riga dei metadati subito sotto.

1import requests
2from bs4 import BeautifulSoup
3from pprint import pprint
4> This paragraph contains content that cannot be parsed and has been skipped.
5stories = []
6story_rows = soup.select("tr.athing")
7for row in story_rows:
8    # Titolo e URL dalla riga della storia
9    title_tag = row.select_one("span.titleline > a")
10    if not title_tag:
11        continue
12    title = title_tag.get_text()
13    link = title_tag.get("href", "")
14    # Metadati dalla riga successiva
15    meta_row = row.find_next_sibling("tr")
16    score = 0
17    author = ""
18    comments = 0
19> This paragraph contains content that cannot be parsed and has been skipped.
20> This paragraph contains content that cannot be parsed and has been skipped.
21# Filtra le storie con almeno 50 punti, ordinate per punteggio
22top_stories = sorted(
23    [s for s in stories if s["score"] >= 50],
24    key=lambda x: x["score"],
25    reverse=True,
26)
27pprint(top_stories[:10])

Qualche nota sul codice:

  • L’operatore walrus (:=) funziona da Python 3.8 in poi. Permette di assegnare e verificare nella stessa riga — utile per elementi opzionali come span.score che potrebbero non esistere in ogni riga (ad esempio i post di lavoro non hanno punteggio).
  • HN usa \xa0 (spazio non separabile) tra il numero e “comments”, quindi lo separiamo su quel carattere.
  • Le storie che puntano ad altre pagine HN (come i post “Ask HN”) avranno URL relativi che iniziano con item?id=. Potresti voler anteporre https://news.ycombinator.com/ in quei casi.

Passo 4: eseguirlo e vedere i risultati

Salva ed esegui:

1python scrape_hn_bs4.py

Dovresti vedere un output simile a questo:

1[{'author': 'twapi',
2  'comments': 65,
3  'score': 118,
4  'title': 'Darkbloom – Private inference on idle Macs',
5  'url': 'https://darkbloom.dev'},
6 {'author': 'sebg',
7  'comments': 203,
8  'score': 247,
9  'title': 'Show HN: I built an open-source Perplexity alternative',
10  'url': 'https://github.com/...'},
11 ...]

Quelle sono 30 storie della pagina 1. Ma HN ha centinaia di storie attive in qualsiasi momento. La paginazione la vedremo in una sezione successiva.

Metodo 2: estrarre Hacker News con Python usando l’API ufficiale

La Firebase API di HN è il metodo ufficialmente supportato per accedere ai dati di Hacker News. Nessuna autenticazione, nessuna chiave API, nessun parsing HTML. Ottieni risposte JSON pulite. Io uso questo metodo per tutto ciò che deve funzionare in modo affidabile in produzione.

Endpoint API principali da conoscere

L’URL base è https://hacker-news.firebaseio.com/v0/. Ecco gli endpoint importanti:

This paragraph contains content that cannot be parsed and has been skipped.

Un item di tipo story appare così:

1{
2  "by": "twapi",
3  "descendants": 65,
4  "id": 47788542,
5  "kids": [47789171, 47788769, 47788762],
6  "score": 118,
7  "time": 1776312399,
8  "title": "Darkbloom – Private inference on idle Macs",
9  "type": "story",
10  "url": "https://darkbloom.dev"
11}

Il campo kids contiene gli ID dei commenti figli diretti. Ogni commento è a sua volta un item che può avere i propri kids: è così che si struttura l’albero dei commenti.

Passo 1: recuperare gli ID delle top story

Crea un file chiamato scrape_hn_api.py:

1import requests
2import time
3from pprint import pprint
4API_BASE = "https://hacker-news.firebaseio.com/v0"
5# Recupera gli ID delle top story
6response = requests.get(f"{API_BASE}/topstories.json")
7story_ids = response.json()
8print(f"Got {len(story_ids)} top story IDs")
9# Output: Got 500 top story IDs

500 ID di storie in una sola richiesta — niente parsing, niente selettori, solo un array JSON.

Passo 2: recuperare i dettagli delle storie tramite ID

Ora ci servono i dati reali delle storie. Qui emerge il problema del fan-out: 500 storie significano 500 chiamate API individuali. Nei miei benchmark, ogni richiesta per un item richiede circa 1,2 secondi in sequenza. Per 500 storie, si parla di circa 10 minuti.

Per la maggior parte dei casi, non ti servono tutte e 500. Ecco il codice per prendere le prime 30:

1def fetch_story(story_id):
2    """Recupera i dettagli di una singola storia dall'API HN."""
3    resp = requests.get(f"{API_BASE}/item/{story_id}.json")
4    return resp.json()
5> This paragraph contains content that cannot be parsed and has been skipped.
6# Ordina per punteggio, mostra le prime 10
7top = sorted(stories, key=lambda x: x["score"], reverse=True)[:10]
8pprint(top)

Il time.sleep(0.1) aggiunge una piccola pausa di cortesia. La Firebase API non dichiara un rate limit esplicito, ma martellare qualsiasi API senza pause è una cattiva pratica.

Passo 3: estrarre i commenti (visita ricorsiva dell’albero)

Qui l’API brilla davvero rispetto allo scraping HTML. I commenti su HN sono profondamente annidati — risposte a risposte a risposte. In HTML, questo significa interpretare strutture di tabelle annidate molto complesse. Con l’API, invece, il campo kids di ogni commento ti dà gli ID dei figli e puoi semplicemente attraversare l’albero in modo ricorsivo.

1def fetch_comments(item_id, depth=0, max_depth=3):
2    """Recupera ricorsivamente i commenti fino a max_depth."""
3    item = requests.get(f"{API_BASE}/item/{item_id}.json").json()
4    if not item or item.get("type") != "comment":
5        return []
6> This paragraph contains content that cannot be parsed and has been skipped.
7    if depth < max_depth and item.get("kids"):
8        for kid_id in item["kids"]:
9            comments.extend(fetch_comments(kid_id, depth + 1, max_depth))
10            time.sleep(0.05)
11    return comments
12# Esempio: recupera i commenti della top story
13if stories:
14    top_story = stories[0]
15    top_story_full = requests.get(f"{API_BASE}/item/{top_story['id']}.json").json()
16    if top_story_full.get("kids"):
17        print(f"\nComments for: {top_story['title']}")
18        all_comments = []
19        for kid_id in top_story_full["kids"][:5]:  # Primi 5 commenti di primo livello
20            all_comments.extend(fetch_comments(kid_id, depth=0, max_depth=2))
21            time.sleep(0.1)
22        for c in all_comments[:15]:
23            indent = "  " * c["depth"]
24            preview = c["text"][:80].replace("\n", " ") if c["text"] else "[no text]"
25            print(f"{indent}[{c['author']}] {preview}...")

Questo approccio ricorsivo è molto più semplice che cercare di interpretare i thread di commenti HTML annidati. Se ti servono alberi completi dei commenti, l’API è la scelta giusta.

Passo 4: esegui e visualizza i risultati

1python scrape_hn_api.py

Vedrai i dati strutturati delle storie seguiti da un’anteprima dei commenti annidati. I dati sono più puliti, l’accesso ai commenti è banale e non rischi che il tuo scraper si rompa perché HN ha cambiato il nome di una classe CSS.

Andare oltre la pagina 1: paginazione e dati storici

La maggior parte dei tutorial su HN si ferma alla pagina 1 — 30 storie. Va bene per una demo veloce, ma i casi d’uso reali spesso richiedono più profondità.

Estrarre più pagine con BeautifulSoup

La paginazione di HN usa un pattern URL semplice: ?p=2, ?p=3, ecc. Ogni pagina restituisce 30 storie, e il sito arriva fino a circa la pagina 20 (circa 600 storie totali). Oltre, ottieni pagine vuote.

1import time
2def scrape_hn_pages(num_pages=5):
3    """Estrae più pagine di storie della front page di HN."""
4    all_stories = []
5    for page in range(1, num_pages + 1):
6        url = f"https://news.ycombinator.com/news?p={page}"
7        response = requests.get(url, headers=headers)
8        soup = BeautifulSoup(response.text, "html.parser")
9        story_rows = soup.select("tr.athing")
10        if not story_rows:
11            print(f"Page {page}: no stories found, stopping.")
12            break
13        for row in story_rows:
14            title_tag = row.select_one("span.titleline > a")
15            if not title_tag:
16                continue
17            meta_row = row.find_next_sibling("tr")
18            score = 0
19            if meta_row and (score_tag := meta_row.select_one("span.score")):
20                score = int(score_tag.get_text().replace(" points", ""))
21> This paragraph contains content that cannot be parsed and has been skipped.
22        print(f"Page {page}: scraped {len(story_rows)} stories")
23        # Rispetta il crawl-delay di 30 secondi indicato in robots.txt
24        if page < num_pages:
25            time.sleep(30)
26    return all_stories
27stories = scrape_hn_pages(5)
28print(f"\nTotal stories scraped: {len(stories)}")

Quel time.sleep(30) è importante. Il di HN richiede esplicitamente un crawl delay di 30 secondi. Ignorarlo può portare a rate limit (HTTP 429) o a un blocco temporaneo. Cinque pagine a intervalli di 30 secondi richiedono circa 2,5 minuti — non istantaneo, ma rispettoso.

Per chi non vuole gestire il codice della paginazione, gestisce automaticamente la paginazione a clic e quella infinite-scroll. Fa clic sul pulsante “More” in fondo alle pagine di HN senza alcuna configurazione.

Accedere ai dati storici di Hacker News con l’API Algolia

La Firebase API ti dà i dati attuali. Per analisi storiche — “Quali erano le migliori storie su Python nel 2023?” oppure “Come è cambiata la copertura sull’AI negli ultimi 5 anni?” — ti serve la .

1import requests
2ALGOLIA_BASE = "https://hn.algolia.com/api/v1"
3> This paragraph contains content that cannot be parsed and has been skipped.
4# Esempio: trova storie su Python scraping con 10+ punti da gennaio 2024
5results = search_hn(
6    query="python scraping",
7    tags="story",
8)
9print(f"Found {results['nbHits']} total results")
10for hit in results["hits"][:5]:
11    print(f"  [{hit.get('points', 0)} pts] {hit['title']}")

Per query filtrate per data, usa numericFilters:

1import calendar, datetime
2# Storie dal 1° gennaio 2024
3start_date = datetime.datetime(2024, 1, 1)
4start_ts = int(calendar.timegm(start_date.timetuple()))
5> This paragraph contains content that cannot be parsed and has been skipped.
6L’API Algolia è veloce (59 ms di tempo di elaborazione lato server), non richiede chiave API e supporta la paginazione fino a 500 pagine. Per analisi storiche su larga scala è la migliore opzione disponibile.
7## Esportare i dati estratti da Hacker News in CSV, Excel e Google Sheets
8Ogni tutorial sullo scraping di HN che ho visto finisce con un output `pprint()` nel terminale. È utile per il debug, ma se stai costruendo un digest giornaliero o facendo analisi dei trend, i dati devono finire in un file. Ecco come farlo.
9### Esportare in CSV con Python
10```python
11import csv
12def export_to_csv(stories, filename="hn_stories.csv"):
13    """Salva le storie estratte in un file CSV."""
14    fieldnames = ["title", "url", "score", "author", "comments"]
15    with open(filename, "w", newline="", encoding="utf-8") as f:
16        writer = csv.DictWriter(f, fieldnames=fieldnames)
17        writer.writeheader()
18        writer.writerows(stories)
19    print(f"Saved {len(stories)} stories to {filename}")
20export_to_csv(stories)

Esportare in Excel con Python

1import pandas as pd
2def export_to_excel(stories, filename="hn_stories.xlsx"):
3    """Salva le storie estratte in un file Excel."""
4    df = pd.DataFrame(stories)
5    df.to_excel(filename, index=False, engine="openpyxl")
6    print(f"Saved {len(stories)} stories to {filename}")
7export_to_excel(stories)

Assicurati che openpyxl sia installato — pandas lo usa come motore per Excel. Se manca, riceverai un errore ImportError.

Inviare a Google Sheets (opzionale)

Per workflow automatizzati, potresti voler inviare i dati direttamente su Google Sheets usando la libreria gspread. Questo richiede la configurazione di un service account Google Cloud (un processo una tantum):

1import gspread
2gc = gspread.service_account(filename="service_account.json")
3sh = gc.open("HN Daily Digest")
4worksheet = sh.sheet1
5# Converti le storie in righe
6header = list(stories[0].keys())
7rows = [list(s.values()) for s in stories]
8worksheet.clear()
9worksheet.update([header] + rows)
10print("Pushed to Google Sheets")

L’alternativa no-code per l’esportazione

Se configurare service account e scrivere codice di esportazione ti sembra più lavoro dello scraping stesso, ti capisco. In Thunderbit abbiamo creato un’esportazione dati gratuita che ti permette di inviare i dati estratti direttamente a Excel, Google Sheets, Airtable o Notion — senza codice, senza credenziali, senza pipeline da mantenere. Per un’estrazione occasionale, è davvero più veloce. Più avanti ti spiego meglio.

Rendere lo scraper pronto per la produzione: gestione errori, cache e scheduling

Se esegui uno scraper una sola volta per curiosità, il codice sopra va benissimo. Se invece lo usi ogni giorno all’interno di un flusso di lavoro, servono alcuni componenti in più.

Gestione errori e logica di retry

Le reti falliscono. I server limitano le richieste. Una singola richiesta sbagliata non dovrebbe mandare in crash tutto lo scraping. Ecco una funzione di retry con backoff esponenziale:

1from tenacity import retry, stop_after_attempt, wait_exponential_jitter
2import requests
3@retry(stop=stop_after_attempt(5), wait=wait_exponential_jitter(initial=1, max=60))
4def fetch_with_retry(url):
5    """Recupera un URL con retry automatici e backoff esponenziale."""
6    response = requests.get(url, timeout=10)
7    response.raise_for_status()
8    return response
9# Uso:
10try:
11    resp = fetch_with_retry("https://hacker-news.firebaseio.com/v0/topstories.json")
12    story_ids = resp.json()
13except Exception as e:
14    print(f"Failed after retries: {e}")

La libreria tenacity gestisce bene la logica di retry. Ritenta fino a 5 volte con backoff esponenziale e jitter — partendo da 1 secondo fino a un massimo di 60 secondi. Questo gestisce in modo elegante HTTP 429 (rate limit), 503 (servizio non disponibile) ed errori di rete transitori.

Mettere in cache le risposte per evitare di ricrawlarle

Durante lo sviluppo eseguirai lo scraper molte volte mentre modifichi la logica di parsing. Senza cache, ogni esecuzione colpisce di nuovo i server di HN per gli stessi dati. La libreria requests-cache risolve tutto in due righe:

1import requests_cache
2requests_cache.install_cache("hn_cache", expire_after=3600)  # Cache per 1 ora

Dopo aver aggiunto queste righe all’inizio dello script, tutte le chiamate requests.get() vengono automaticamente memorizzate in una base dati SQLite locale. Riesegui lo script 10 volte in un’ora, e solo la prima esecuzione andrà davvero in rete. È uno strumento che , e per ottime ragioni.

Separare il crawling dal parsing

Un pattern che gli scraper esperti consigliano sempre: prima scarica i dati grezzi, poi esegui il parsing. In questo modo, se la logica di parsing ha un bug, puoi correggerla e riprocessare senza rifare il fetch.

1import os, json
2def crawl_and_save(story_ids, output_dir="raw_data"):
3    """Recupera i dati delle storie e salva il JSON grezzo su disco."""
4    os.makedirs(output_dir, exist_ok=True)
5    for sid in story_ids:
6        filepath = os.path.join(output_dir, f"{sid}.json")
7        if os.path.exists(filepath):
8            continue  # Salta gli elementi già recuperati
9        resp = fetch_with_retry(f"{API_BASE}/item/{sid}.json")
10        with open(filepath, "w") as f:
11            json.dump(resp.json(), f)
12> This paragraph contains content that cannot be parsed and has been skipped.
13Questo approccio in due fasi è particolarmente utile quando estrai centinaia di elementi e vuoi iterare rapidamente sul modo in cui processi i dati.
14### Automatizzare lo scraper con una pianificazione
15Per un digest giornaliero di HN, lo scraper deve girare automaticamente. Due opzioni comuni:
16**Opzione 1: cron (Linux/Mac)**
17```bash
18# Esegui ogni giorno alle 8:30 UTC
1930 8 * * * /usr/bin/python3 /home/user/scrape_hn.py >> /home/user/scrape.log 2>&1

Opzione 2: GitHub Actions (gratis, senza server)

1name: Scrape Hacker News
2on:
3  schedule:
4    - cron: '30 8 * * *'  # Ogni giorno alle 8:30 UTC
5  workflow_dispatch:        # Pulsante di esecuzione manuale
6jobs:
7  scrape:
8    runs-on: ubuntu-latest
9    steps:
10      - uses: actions/checkout@v4
11      - uses: actions/setup-python@v6
12        with:
13          python-version: '3.12'
14      - run: pip install requests beautifulsoup4 pandas openpyxl
15      - run: python scrape_hn.py
16      - run: |
17          git config user.name "GitHub Actions Bot"
18          git config user.email "actions@github.com"
19          git add -A
20          git diff --staged --quiet || git commit -m "Update HN data $(date -u +%Y-%m-%dT%H:%M:%SZ)"
21          git push

Alcuni dettagli da tenere a mente con la pianificazione su GitHub Actions: tutti gli orari cron sono in UTC, sono comuni ritardi di 15–60 minuti (usa orari non “tondi” come :30 invece di :00) e GitHub può disattivare i workflow pianificati nei repository inattivi per 60 giorni. Includi sempre workflow_dispatch così puoi avviare tutto manualmente durante i test.

Per un’opzione più semplice, la funzione Scheduled Scraper di Thunderbit ti consente di descrivere la pianificazione in linguaggio naturale — qualcosa come “estrai ogni mattina alle 8” — senza server né configurazione cron.

Quando Python è eccessivo: il modo no-code per estrarre Hacker News

Voglio essere onesto, anche se sono un appassionato di Python e il mio team costruisce strumenti per sviluppatori. Se ti servono solo le prime 100 storie di HN di oggi in un foglio di calcolo — subito, una sola volta — scrivere, debuggare ed eseguire uno script Python è un overhead inutile. Solo la configurazione iniziale (ambiente virtuale, installazione dei pacchetti, individuazione dei selettori) richiede più tempo della raccolta dati vera e propria.

È qui che entra in gioco . Ecco il flusso di lavoro:

  1. Apri news.ycombinator.com in Chrome
  2. Clicca l’icona dell’estensione Thunderbit, poi “AI Suggest Fields”
  3. L’AI legge la pagina e propone le colonne: Titolo, URL, Punteggio, Autore, Numero commenti, Orario di pubblicazione
  4. Modifica i campi se vuoi (rinomina, rimuovi o aggiungi campi personalizzati — puoi anche aggiungere un prompt AI come “Classifica come AI/DevTools/Web/Altro”)
  5. Clicca “Scrape” — i dati compaiono in una tabella strutturata
  6. Esporta in Excel, Google Sheets, Airtable o Notion

Due clic per arrivare ai dati strutturati. Nessun selettore, nessun codice, nessuna manutenzione.

Un vantaggio concreto: l’AI di Thunderbit si adatta automaticamente ai cambiamenti di layout. I classici scraper basati su selettori CSS si rompono quando un sito modifica il markup — e anche se l’HTML di HN è abbastanza stabile, è cambiato nel tempo (la classe class="athing submission" è stata aggiornata, span.titleline ha sostituito il vecchio a.storylink). Uno scraper AI legge la pagina ogni volta da zero, quindi non dipende dai nomi delle classi.

python-vs-thunderbit-comparison.webp

Thunderbit gestisce anche la paginazione (cliccando automaticamente il pulsante “More” di HN) e lo scraping delle sottopagine (visitando la pagina dei commenti di ogni storia per raccogliere i dati della discussione). Per il caso d’uso di , è l’equivalente del codice API ricorsivo del Metodo 2 — ma senza scrivere una sola riga.

I compromessi sono semplici: Python è la scelta giusta quando hai bisogno di logiche personalizzate, trasformazioni complesse dei dati, pipeline automatizzate pianificate o stai imparando a programmare. Thunderbit è la scelta giusta quando ti servono dati subito, non vuoi mantenere codice o non sei uno sviluppatore. Scegli lo strumento che corrisponde alla tua situazione.

Python vs API vs No-Code: quale metodo scegliere?

Ecco il quadro decisionale completo:

CriterioBeautifulSoup (HTML)Firebase APIAlgolia APIThunderbit (No-Code)
Competenze tecniche richiestePython intermedioPython basePython baseNessuna
Tempo di configurazione10–15 min5–10 min5–10 min2 min
ManutenzioneMedia (i selettori possono rompersi)Bassa (JSON stabile)Bassa (JSON stabile)Nessuna
Profondità dei datiSolo front pageQualsiasi item, utentiRicerca + storicoFront page + sottopagine
CommentiDifficileFacile (ricorsivo)Facile (albero annidato)Scraping delle sottopagine
Dati storiciNoNoSì (archivio completo)No
Opzioni di exportDa programmareDa programmareDa programmareIntegrato (Excel, Sheets, ecc.)
Schedulingcron / GitHub Actionscron / GitHub Actionscron / GitHub ActionsPianificatore integrato
Ideale perImparare lo scrapingPipeline affidabiliRicerca e analisiEstrazioni rapide

Se stai imparando Python o stai costruendo qualcosa di personalizzato, scegli il Metodo 1 o 2. Se hai bisogno di analisi storiche, aggiungi l’Algolia API. Se vuoi solo i dati senza codice, .

Conclusione e punti chiave

Ecco cosa hai ora nel tuo toolkit:

  • Due metodi Python completi per estrarre Hacker News — BeautifulSoup per il parsing HTML e la Firebase API per dati JSON puliti
  • Tecniche di paginazione per andare oltre la pagina 1, inclusa l’Algolia API per dati storici dal 2007 in poi
  • Codice di export per CSV, Excel e Google Sheets — perché i dati nel terminale non servono a nessuno nel team
  • Pattern pronti per la produzione — retry logic, cache, separazione tra crawling e parsing e automazione pianificata con cron o GitHub Actions
  • Un’alternativa no-code per i casi in cui Python è più strumento del necessario

Il mio consiglio: parti dalla Firebase API (Metodo 2) per la maggior parte dei casi d’uso. È più pulita, più affidabile e ti permette di accedere ai commenti senza dover affrontare il parsing dell’HTML annidato. Aggiungi l’Algolia API quando hai bisogno di dati storici. E tieni tra i preferiti per quei momenti in cui ti serve solo un foglio di calcolo veloce e non vuoi avviare un intero progetto Python.

Se vuoi andare più a fondo, prova a estrarre i commenti di HN per , crea una pipeline di digest giornaliero con GitHub Actions o esplora l’Algolia API per capire come sono cambiati i trend tecnologici nell’ultimo decennio.

Prova Thunderbit per uno scraping rapido di Hacker News

FAQ

È legale estrarre dati da Hacker News?

I dati di HN sono pubblicamente disponibili e Y Combinator offre un’API ufficiale proprio per l’accesso programmatico. Il del sito consente lo scraping dei contenuti di sola lettura (front page, pagine item, pagine utente) ma richiede un crawl delay di 30 secondi. Rispetta il delay, non estrarre endpoint interattivi (votazioni, login) e sei in una posizione solida. Per approfondire l’etica dello scraping, consulta la nostra guida sulle .

Hacker News ha un’API ufficiale?

Sì. La su hacker-news.firebaseio.com/v0/ è gratuita, non richiede autenticazione e offre accesso a storie, commenti, profili utente e a tutti i tipi di feed (top, new, best, ask, show, jobs). Restituisce JSON pulito e non ha un rate limit dichiarato, anche se è sempre consigliabile usare una frequenza di richieste ragionevole.

Come faccio a estrarre i commenti di Hacker News con Python?

Usando la Firebase API, recupera un item di tipo story per ottenere il campo kids (un array con gli ID dei commenti di primo livello). Ogni commento è a sua volta un item con il proprio campo kids per le risposte. Attraversa l’albero in modo ricorsivo con una funzione che recupera ogni commento e i suoi figli. Vedi sopra la sezione “Estrarre i commenti (visita ricorsiva dell’albero)” per il codice completo. In alternativa, l’endpoint /items/<id> della restituisce l’intero albero annidato dei commenti in una sola richiesta — molto più veloce per le storie con molti commenti.

Posso estrarre Hacker News senza scrivere codice?

Sì. L’ funziona come estensione Chrome: apri HN, clicca “AI Suggest Fields” e identifica automaticamente colonne come titolo, URL, punteggio e autore. Clicca “Scrape” ed esporta direttamente su Excel, Google Sheets, Airtable o Notion. Gestisce anche la paginazione e può visitare le sottopagine per raccogliere i dati dei commenti. Niente Python, niente selettori, niente manutenzione.

Come ottengo dati storici di Hacker News?

La è lo strumento migliore per questo. Usa l’endpoint search_by_date con numericFilters=created_at_i>TIMESTAMP per filtrare per intervallo di date. Puoi cercare per parola chiave, filtrare per tipo di storia e paginare fino a 500 pagine di risultati. Per analisi storiche su larga scala, sono disponibili anche dataset pubblici su (archivio completo), (28 milioni di record) e (4 milioni di storie).

Scopri di più

Shuai Guan
Shuai Guan
Co-founder/CEO @ Thunderbit. Passionate about cross section of AI and Automation. He's a big advocate of automation and loves making it more accessible to everyone. Beyond tech, he channels his creativity through a passion for photography, capturing stories one picture at a time.
Indice

Prova Thunderbit

Estrai lead e altri dati in soli 2 clic. Potenziato dall’AI.

Scarica Thunderbit È gratis
Estrai dati con l’AI
Trasferisci facilmente i dati a Google Sheets, Airtable o Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week