Cum extrag Hacker News cu Python (2 metode, cod complet)

Ultima actualizare pe April 16, 2026

În urmă cu câteva luni, voiam să fac pentru echipa noastră de la Thunderbit un rezumat zilnic al celor mai importante articole de pe Hacker News. Prima idee a fost simplă: să salvez site-ul la bookmark și să-l răsfoiesc în fiecare dimineață. A mers vreo trei zile, până mi-am dat seama că pierdeam zilnic 20 de minute doar citind titluri și făcând copy-paste la linkuri într-un spreadsheet.

Hacker News este una dintre cele mai bogate și mai concentrate surse de informații tech de pe internet — aproximativ , în jur de 1.300 de articole noi trimise în fiecare zi și cam 13.000 de comentarii generate zilnic. Fie că urmărești trenduri noi, îți monitorizezi brandul, construiești un pipeline de recrutare din thread-urile „Who’s Hiring” sau pur și simplu vrei să ții pasul cu ce contează în lumea developerilor, să urmărești totul manual e o luptă pierdută.

Vestea bună este că extragerea datelor din Hacker News cu Python este surprinzător de simplă. În acest ghid, îți voi arăta două metode complete — parsare HTML cu BeautifulSoup și API-ul oficial HN Firebase — plus paginare, export de date, bune practici pentru producție și o variantă no-code pentru momentele în care Python pare prea mult.

De ce să extragi date din Hacker News cu Python?

Hacker News nu e doar încă un agregator de linkuri. Este un feed curatoriat, construit de comunitate, unde cele mai interesante știri tech urcă în top prin upvote-uri și discuții active. Publicul este foarte orientat spre profesioniști din tehnologie (aproximativ ), iar rata de trafic direct de 66% arată că vorbim despre o audiență fidelă, obișnuită, nu despre vizitatori ocazionali.

Iată de ce oamenii extrag date din HN:

Caz de utilizareCe obții
Rezumat zilnic techCele mai importante articole, scoruri și linkuri livrate în inbox sau în Slack
Monitorizare brand/concurențăAlerte când compania sau produsul tău este menționat
Analiză de tendințeUrmărești ce tehnologii, limbaje sau subiecte câștigă tracțiune în timp
RecrutareAnalizezi thread-urile „Who’s Hiring” pentru anunțuri, stack-uri tech și indicii de salariu
Cercetare de conținutGăsești subiecte cu performanță bună despre care să scrii sau să distribui
Analiză de sentimentEvaluezi opinia comunității despre produse, lansări sau schimbări din industrie

Companii evaluate împreună la peste 400 de miliarde de dolari — Stripe, Dropbox, Airbnb — spun că au primit feedback timpuriu esențial și utilizatori datorită Hacker News. Drew Houston a postat demo-ul Dropbox pe HN în aprilie 2007, a ajuns pe locul 1, iar lista de așteptare pentru beta a explodat de la 5.000 la 75.000 de utilizatori într-o singură zi. Datele din HN nu sunt doar interesante — sunt valoroase din punct de vedere comercial.

Datele sunt publice, dar structura site-ului face colectarea manuală anevoioasă. Automatizarea cu Python este soluția practică.

Două metode de a extrage Hacker News cu Python: vedere de ansamblu

Acest ghid acoperă două abordări complete, gata de rulat:

  1. Extragere HTML cu requests + BeautifulSoup — preiei HTML-ul brut de pe news.ycombinator.com și îl parsezi pentru a extrage datele articolelor. Excelentă pentru a învăța bazele web scraping-ului și pentru a lua exact ceea ce vezi pe pagină.
  2. API-ul oficial Hacker News Firebase — apelezi direct endpoint-uri JSON, fără să fie nevoie de parsare HTML. Este mai bun pentru fluxuri de date fiabile, acces la comentarii și date istorice.

Iată o comparație rapidă ca să alegi varianta potrivită:

CriteriuExtragere HTML (requests + BS4)HN Firebase APIThunderbit (No-Code)
Complexitate la configurareMedie (selectori HTML de parsare)Scăzută (endpoint-uri JSON)Inexistentă (extensie Chrome în 2 clicuri)
Prospețimea datelorTimp real, prima paginăTimp real (orice element după ID)Timp real
Risc de limitareMediu (robots.txt cere delay de 30 secunde)Scăzut (oficial, generos)Gestionat de Thunderbit
Acces la comentariiGreu (HTML imbricat)Ușor (ID-uri de elemente recursive)Funcție de extragere a subpaginilor
Date istoriceLimitatePrin Algolia Search APIN/A
Cel mai potrivit pentruÎnvățarea bazelor scraping-uluiFluxuri de date fiabileNon-dezvoltatori, export rapid

Ambele metode includ cod Python complet, gata de rulat. Iar dacă vrei doar datele, fără să scrii niciun rând de cod, acoperim și asta.

Înainte să începi

  • Dificultate: Începător spre intermediar
  • Timp necesar: ~15–20 de minute pentru fiecare metodă
  • Ai nevoie de:
    • Python 3.11+ instalat
    • Un terminal sau un editor de cod
    • Browser Chrome (dacă vrei să inspectezi HTML-ul HN sau să încerci opțiunea no-code)
    • (opțional, pentru metoda no-code)

scrape-hacker-news-methods.webp

Configurarea mediului Python

Înainte să ne atingem de datele din HN, hai să pregătim mediul. Îți recomand să creezi un mediu virtual, ca dependențele proiectului să rămână curate.

1# Creează și activează un mediu virtual
2python3 -m venv hn-scraper
3# macOS/Linux:
4source hn-scraper/bin/activate
5# Windows:
6hn-scraper\Scripts\activate
7# Instalează pachetele de care avem nevoie pentru ambele metode
8pip install requests==2.33.1 beautifulsoup4==4.14.3 pandas==3.0.2 openpyxl==3.1.5

Pentru modelele de producție de mai târziu (cache, retry-uri), vei mai vrea și:

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

Fără chei API speciale, fără token-uri de autentificare. Datele din HN sunt publice.

Metoda 1: Extragerea Hacker News cu Python folosind BeautifulSoup

Aceasta este metoda clasică — iei HTML-ul, îl parsezi și extragi datele de care ai nevoie. Așa învață majoritatea oamenilor web scraping-ul, iar structura simplă, bazată pe tabele, a HN o face un teren excelent de antrenament.

Pasul 1: Preia pagina principală Hacker News

Deschide editorul și creează un fișier numit scrape_hn_bs4.py. Iată codul de start:

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")

Rulează-l. Ar trebui să vezi Status: 200 și o lungime a paginii de aproximativ 40.000–50.000 de caractere. Acesta este HTML-ul brut al paginii principale HN, încărcat în memorie și gata de parsare.

Pasul 2: Înțelege structura HTML

HN folosește un layout bazat pe tabele — fără grid sau flexbox moderne. Fiecare articol de pe pagină este alcătuit din două rânduri <tr> esențiale:

  • Rândul articolului (<tr class="athing submission">): conține poziția, titlul și linkul
  • Rândul de metadate (următorul <tr>): conține punctele, autorul, timpul și numărul de comentarii

Selectorii importanți:

  • span.titleline > a — titlul articolului și URL-ul
  • span.score — numărul de voturi (de exemplu, „118 points”)
  • a.hnuser — numele de utilizator al autorului
  • span.age — momentul publicării
  • Ultimul <a> din .subtext care conține textul „comment” — numărul de comentarii

Dacă dai click dreapta pe un titlu în Chrome și alegi „Inspect”, vei vedea ceva de genul:

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

Iar dedesubt, rândul cu metadate:

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>

Înțelegerea acestor selectori este esențială — dacă HN își schimbă vreodată markup-ul, va trebui să îi actualizezi. (Spoiler: metoda API evită complet problema.)

Pasul 3: Extrage titluri, linkuri și scoruri

Acum trecem la partea practică. Vom parcurge fiecare rând de articol, vom lua titlul și linkul din rândul articolului, apoi vom prelua scorul din rândul de metadate aflat imediat dedesubt.

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    # Titlu și URL din rândul articolului
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    # Metadate din rândul următor
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# Filtrează articolele cu 50+ puncte, ordonate după scor
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])

Câteva observații despre cod:

  • Operatorul walrus (:=) funcționează în Python 3.8+. Îți permite să atribui și să verifici în aceeași linie — util pentru elemente opționale precum span.score, care pot să nu existe pe fiecare rând (de exemplu, postările de job nu au scor).
  • HN folosește \xa0 (spațiu insesizabil) între număr și „comments”, așa că împărțim șirul după acel caracter.
  • Articolele care duc către alte pagini HN (cum ar fi postările „Ask HN”) au URL-uri relative care încep cu item?id=. Poate vrei să adaugi https://news.ycombinator.com/ în față pentru acestea.

Pasul 4: Rulează și vezi rezultatele

Salvează și rulează:

1python scrape_hn_bs4.py

Ar trebui să obții un rezultat de tipul:

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 ...]

Asta înseamnă 30 de articole de pe prima pagină. Dar HN are sute de articole active în orice moment. Vom acoperi paginarea într-o secțiune ulterioară.

Metoda 2: Extragerea Hacker News cu Python folosind API-ul oficial

API-ul HN Firebase este metoda oficială pentru accesarea datelor Hacker News. Fără autentificare, fără chei API, fără parsare HTML. Primești răspunsuri JSON curate. Eu folosesc această metodă pentru orice trebuie să ruleze fiabil în producție.

Endpoint-urile API cheie pe care trebuie să le știi

URL-ul de bază este https://hacker-news.firebaseio.com/v0/. Iată endpoint-urile importante:

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

Un element de tip story arată așa:

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}

Câmpul kids conține ID-urile comentariilor-copil directe. Fiecare comentariu este, la rândul său, un element care poate avea propriile sale kids — așa este structurată arborele de comentarii.

Pasul 1: Preia ID-urile articolelor de top

Creează un fișier numit scrape_hn_api.py:

1import requests
2import time
3from pprint import pprint
4API_BASE = "https://hacker-news.firebaseio.com/v0"
5# Preia ID-urile articolelor de top
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 de ID-uri de articole într-o singură cerere — fără parsare, fără selectori, doar un array JSON.

Pasul 2: Preia detaliile articolului după ID

Acum avem nevoie de datele reale ale articolului. Aici apare problema fan-out: 500 de articole înseamnă 500 de apeluri API individuale. În testele mele, fiecare request pentru un element durează aproximativ 1,2 secunde secvențial. Pentru 500 de articole, asta înseamnă cam 10 minute.

Pentru majoritatea cazurilor, nu ai nevoie de toate cele 500. Iată codul pentru a prelua primele 30:

1def fetch_story(story_id):
2    """Preia detaliile unui singur articol din API-ul 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# Sortează după scor și afișează primele 10
7top = sorted(stories, key=lambda x: x["score"], reverse=True)[:10]
8pprint(top)

time.sleep(0.1) adaugă o mică pauză de curtoazie. API-ul Firebase nu are o limită de rată declarată, dar să bombardezi orice API fără pauze nu este o practică bună.

Pasul 3: Extragerea comentariilor (parcurgere recursivă a arborelui)

Aici API-ul chiar strălucește față de parsarea HTML. Comentariile de pe HN sunt profund imbricate — răspunsuri la răspunsuri la răspunsuri. În HTML, asta înseamnă să parsezi structuri de tabele imbricate complicate. Cu API-ul, fiecare comentariu are în kids ID-urile copiilor săi, iar tu pur și simplu parcurgi arborele recursiv.

1def fetch_comments(item_id, depth=0, max_depth=3):
2    """Preia recursiv comentariile până la 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# Exemplu: preia comentariile pentru articolul de top
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]:  # Primele 5 comentarii de nivel superior
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}...")

Această abordare recursivă este mult mai simplă decât încercarea de a parsa thread-uri de comentarii HTML imbricate. Dacă ai nevoie de arbori compleți de comentarii, API-ul este varianta corectă.

Pasul 4: Rulează și vezi rezultatele

1python scrape_hn_api.py

Vei vedea date structurate despre articole, urmate de o previzualizare ierarhică a comentariilor. Datele sunt mai curate, accesul la comentarii este banal și nu există riscul ca scraperul să se rupă pentru că HN a schimbat numele unei clase CSS.

Dincolo de prima pagină: paginare și date istorice

Majoritatea tutorialelor despre HN se opresc la pagina 1 — 30 de articole. Este suficient pentru un demo rapid, dar cazurile reale au adesea nevoie de mai mult.

Extragerea mai multor pagini cu BeautifulSoup

Paginarea HN folosește un model simplu de URL: ?p=2, ?p=3 etc. Fiecare pagină returnează 30 de articole, iar site-ul servește până în jurul paginii 20 (aproximativ 600 de articole în total). Dincolo de asta, primești pagini goale.

1import time
2def scrape_hn_pages(num_pages=5):
3    """Extrage mai multe pagini cu articole din prima pagină 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        # Respectă crawl-delay-ul de 30 de secunde din 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)}")

time.sleep(30) este important. de la HN solicită explicit un crawl delay de 30 de secunde. Dacă ignori asta, riști rate limiting (HTTP 429) sau blocare temporară. Cinci pagini la intervale de 30 de secunde înseamnă aproximativ 2,5 minute — nu instant, dar respectuos.

Pentru utilizatorii care nu vor să gestioneze codul de paginare, se ocupă automat de paginare prin clic și de infinite scroll. Apasă automat butonul „More” de la baza paginilor HN, fără nicio configurare.

Accesarea datelor istorice Hacker News cu Algolia API

Firebase API îți oferă datele curente. Pentru analiză istorică — „Care au fost cele mai bune articole despre Python în 2023?” sau „Cum s-a schimbat acoperirea subiectelor AI în ultimii 5 ani?” — ai nevoie de .

1import requests
2ALGOLIA_BASE = "https://hn.algolia.com/api/v1"
3> This paragraph contains content that cannot be parsed and has been skipped.
4# Exemplu: găsește articole despre Python scraping cu 10+ puncte din ian 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']}")

Pentru interogări filtrate după dată, folosește numericFilters:

1import calendar, datetime
2# Articole de la 1 ianuarie 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.
6Algolia API este rapidă (timp de procesare server de 59 ms), nu necesită cheie API și suportă paginare până la 500 de pagini. Pentru analize istorice în volum mare, este cea mai bună opțiune disponibilă.
7## Exportul datelor Hacker News în CSV, Excel și Google Sheets
8Fiecare tutorial despre HN se termină cu output în terminal prin `pprint()`. E util pentru debugging, dar dacă construiești un rezumat zilnic sau faci analiză de tendințe, ai nevoie de date într-un fișier. Iată cum le poți exporta.
9### Export în CSV cu Python
10```python
11import csv
12def export_to_csv(stories, filename="hn_stories.csv"):
13    """Salvează articolele extrase într-un fișier 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)

Export în Excel cu Python

1import pandas as pd
2def export_to_excel(stories, filename="hn_stories.xlsx"):
3    """Salvează articolele extrase într-un fișier 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)

Asigură-te că openpyxl este instalat — pandas îl folosește ca motor pentru Excel. Dacă lipsește, vei primi un ImportError.

Trimite datele în Google Sheets (opțional)

Pentru fluxuri automate, ai putea dori să trimiți datele direct în Google Sheets folosind biblioteca gspread. Asta necesită configurarea unui service account Google Cloud (un proces făcut o singură dată):

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

Alternativa no-code pentru export

Dacă setarea service account-urilor și scrierea codului de export pare mai multă muncă decât scraping-ul în sine, te înțeleg. La Thunderbit, am construit export de date gratuit care îți permite să trimiți datele extrase direct în Excel, Google Sheets, Airtable sau Notion — fără cod, fără credențiale, fără pipeline de întreținut. Pentru o extragere punctuală, este sincer mai rapid. Mai jos explicăm și asta.

Cum îți faci scraperul pregătit pentru producție: gestionarea erorilor, cache și programare

Dacă rulezi scraperul o singură dată, de distracție, codul de mai sus este suficient. Dacă îl rulezi zilnic ca parte dintr-un workflow, ai nevoie de câteva componente suplimentare.

Gestionarea erorilor și logica de retry

Rețelele pică. Serverele limitează. Un singur request prost nu ar trebui să oprească întreaga extragere. Iată o funcție de retry cu exponential backoff:

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    """Preia un URL cu retry automat și exponential backoff."""
6    response = requests.get(url, timeout=10)
7    response.raise_for_status()
8    return response
9# Utilizare:
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}")

Biblioteca tenacity gestionează elegant logica de retry. Va reîncerca de până la 5 ori cu exponential backoff cu jitter — începând de la 1 secundă și ajungând până la 60 de secunde. Asta tratează grațios HTTP 429 (rate limited), 503 (service unavailable) și erorile de rețea tranzitorii.

Cache pentru a evita re-crawling-ul

În timpul dezvoltării, vei rula scraperul de multe ori în timp ce ajustezi logica de parsare. Fără cache, fiecare rulare lovește din nou serverele HN pentru aceleași date. Biblioteca requests-cache rezolvă asta în două linii:

1import requests_cache
2requests_cache.install_cache("hn_cache", expire_after=3600)  # Cache pentru 1 oră

După ce adaugi aceste linii în partea de sus a scriptului, toate apelurile requests.get() sunt cache-uite automat într-o bază locală SQLite. Dacă rulezi scriptul de 10 ori într-o oră, doar prima rulare va folosi rețeaua. Este un instrument recomandat frecvent de utilizatorii de pe forum și pe bună dreptate.

Separarea crawling-ului de parsare

O practică apreciată de scrapperii cu experiență: descarcă mai întâi datele brute, parsează-le abia apoi. În acest fel, dacă logica de parsare are o eroare, o repari și re-parsarea se face fără să mai faci request-uri.

1import os, json
2def crawl_and_save(story_ids, output_dir="raw_data"):
3    """Preia datele articolului și salvează JSON brut pe disc."""
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  # Sare peste elementele deja preluate
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.
13Această abordare în doi pași este foarte utilă atunci când extragi sute de elemente și vrei să iterezi rapid asupra modului în care procesezi datele.
14### Automatizarea scraperului după program
15Pentru un digest zilnic HN, ai nevoie ca scraperul să ruleze automat. Două opțiuni comune:
16**Opțiunea 1: cron (Linux/Mac)**
17```bash
18# Rulează în fiecare zi la 8:30 AM UTC
1930 8 * * * /usr/bin/python3 /home/user/scrape_hn.py >> /home/user/scrape.log 2>&1

Opțiunea 2: GitHub Actions (gratuit, fără server)

1name: Scrape Hacker News
2on:
3  schedule:
4    - cron: '30 8 * * *'  # Zilnic la 8:30 AM UTC
5  workflow_dispatch:        # Buton de rulare manuală
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

Câteva capcane la programarea cu GitHub Actions: toate orele cron sunt în UTC, întârzierile de 15–60 de minute sunt frecvente (folosește minute „off”, cum ar fi :30, nu :00), iar GitHub poate dezactiva workflow-urile programate pentru repo-uri fără activitate timp de 60 de zile. Include mereu workflow_dispatch ca să poți porni manual pentru testare.

Pentru o variantă mai simplă, funcția Scheduled Scraper de la Thunderbit îți permite să descrii programul în limbaj natural — ceva de genul „scrape every morning at 8am” — fără server sau configurare cron.

Când Python este prea mult: varianta no-code pentru Hacker News

O să fiu sincer aici, chiar dacă sunt pasionat de Python și echipa mea construiește instrumente pentru developeri. Dacă ai nevoie doar de primele 100 de articole HN de azi într-un spreadsheet — chiar acum, o singură dată — să scrii, să depanezi și să rulezi un script Python este un efort inutil. Doar configurarea (mediu virtual, instalare de pachete, înțelegerea selectorilor) durează mai mult decât colectarea propriu-zisă a datelor.

Aici se potrivește . Iată fluxul:

  1. Deschide news.ycombinator.com în Chrome
  2. Dă click pe iconița extensiei Thunderbit, apoi pe „AI Suggest Fields”
  3. AI-ul citește pagina și propune coloane: Title, URL, Score, Author, Comment Count, Time Posted
  4. Ajustează câmpurile dacă vrei (redenumire, ștergere sau adăugare de câmpuri personalizate — poți chiar adăuga un prompt AI precum „Categorize as AI/DevTools/Web/Other”)
  5. Dă click pe „Scrape” — datele apar într-un tabel structurat
  6. Exportă în Excel, Google Sheets, Airtable sau Notion

Două clicuri până la date structurate. Fără selectori, fără cod, fără întreținere.

Un avantaj real aici: AI-ul Thunderbit se adaptează automat la schimbările de layout. Scraper-ele tradiționale bazate pe selectori CSS se rup atunci când un site își schimbă markup-ul — iar deși HTML-ul HN este destul de stabil, s-a schimbat (clasa class="athing submission" a fost actualizată, span.titleline a înlocuit vechiul a.storylink). Un scraper alimentat de AI citește pagina de fiecare dată de la zero, deci nu îi pasă de schimbările de nume ale claselor.

python-vs-thunderbit-comparison.webp

Thunderbit gestionează și paginarea (apasă automat butonul „More” de pe HN) și extragerea subpaginilor (vizitează pagina de comentarii a fiecărui articol pentru a prelua discuția). Pentru cazul de utilizare de , asta este echivalentul codului API recursiv din Metoda 2 — dar fără să scrii o singură linie.

Compromisul este simplu: Python este alegerea potrivită când ai nevoie de logică personalizată, transformări complexe ale datelor, fluxuri automate programate sau când înveți să codezi. Thunderbit este alegerea potrivită când ai nevoie de date rapid, nu vrei să întreții cod sau nu ești developer. Alege instrumentul care se potrivește situației tale.

Python vs. API vs. No-Code: ce metodă ar trebui să alegi?

Iată cadrul complet de decizie:

CriteriuBeautifulSoup (HTML)Firebase APIAlgolia APIThunderbit (No-Code)
Nivel tehnic necesarPython intermediarPython începătorPython începătorNiciunul
Timp de configurare10–15 min5–10 min5–10 min2 min
Sarcină de întreținereMedie (selectorii se pot rupe)Redusă (JSON stabil)Redusă (JSON stabil)Inexistentă
Profunzimea datelorDoar prima paginăOrice element, utilizatoriCăutare + istoricPrima pagină + subpagini
ComentariiGreuUșor (recursiv)Ușor (arbore imbricat)Extragere subpagini
Date istoriceNuNuDa (arhivă completă)Nu
Opțiuni de exportLe scrii tuLe scrii tuLe scrii tuIntegrat (Excel, Sheets etc.)
Programarecron / GitHub Actionscron / GitHub Actionscron / GitHub ActionsScheduler integrat
Cel mai bun pentruÎnvățare scrapingFluxuri fiabileCercetare și analizăExtrageri rapide

Dacă înveți Python sau construiești ceva personalizat, mergi pe Metoda 1 sau 2. Dacă ai nevoie de analiză istorică, adaugă Algolia API. Dacă vrei doar datele fără cod, .

Concluzie și idei-cheie

Iată ce ai acum în arsenal:

  • Două metode Python complete pentru a extrage Hacker News — BeautifulSoup pentru parsarea HTML și Firebase API pentru date JSON curate
  • Tehnici de paginare pentru a merge dincolo de prima pagină, inclusiv Algolia API pentru date istorice încă din 2007
  • Cod de export pentru CSV, Excel și Google Sheets — pentru că datele într-un terminal nu sunt utile nimănui altcuiva din echipa ta
  • Modele pentru producție — retry logic, cache, separarea crawling/parsing și automatizare programată prin cron sau GitHub Actions
  • O alternativă no-code pentru momentele în care Python este mai mult instrument decât ai nevoie

Recomandarea mea: începe cu Firebase API (Metoda 2) pentru majoritatea cazurilor. Este mai curat, mai fiabil și îți oferă acces la comentarii fără bătaia de cap a parsării HTML-ului imbricat. Adaugă Algolia API când ai nevoie de date istorice. Și păstrează la favorite pentru situațiile în care vrei doar un spreadsheet rapid și nu vrei să pornești un proiect Python întreg.

Dacă vrei să mergi mai departe, încearcă să extragi comentariile HN pentru , construiește un pipeline zilnic de rezumat cu GitHub Actions sau explorează Algolia API pentru a urmări cum s-au schimbat tendințele tehnologice în ultimul deceniu.

Încearcă Thunderbit pentru extragerea rapidă a Hacker News

Întrebări frecvente

Datele din HN sunt publice, iar Y Combinator oferă un API oficial special pentru acces programatic. al site-ului permite extragerea conținutului doar pentru citire (pagina principală, paginile de elemente, paginile de utilizator), dar solicită un delay de 30 de secunde la crawl. Respectă această pauză, nu extrage endpoint-uri interactive (votare, login) și ești în regulă. Pentru mai multe detalii despre etica scraping-ului, vezi ghidul nostru despre .

Hacker News are un API oficial?

Da. de la hacker-news.firebaseio.com/v0/ este gratuit, nu necesită autentificare și oferă acces la story-uri, comentarii, profiluri de utilizator și toate tipurile de feed (top, new, best, ask, show, jobs). Returnează JSON curat și nu are o limită de rată declarată, deși este mereu recomandat să fii politicos cu frecvența request-urilor.

Cum extrag comentariile Hacker News cu Python?

Folosind Firebase API, preiei un articol ca să obții câmpul său kids (un array cu ID-urile comentariilor de nivel superior). Fiecare comentariu este, la rândul lui, un element cu propriul kids pentru răspunsuri. Parcurgi arborele recursiv cu o funcție care preia fiecare comentariu și copiii săi. Vezi secțiunea „Extragerea comentariilor (parcurgere recursivă a arborelui)” de mai sus pentru cod complet. Alternativ, endpoint-ul returnează întregul arbore de comentarii imbricat într-o singură cerere — mult mai rapid pentru articole cu multe comentarii.

Pot extrage Hacker News fără să scriu cod?

Da. funcționează ca extensie Chrome — deschizi HN, dai click pe „AI Suggest Fields” și identifică automat coloane precum titlu, URL, scor și autor. Apeși „Scrape” și exporți direct în Excel, Google Sheets, Airtable sau Notion. Gestionează paginarea și poate chiar vizita subpagini pentru a prelua comentarii. Fără Python, fără selectori, fără întreținere.

Cum obțin date istorice din Hacker News?

este cel mai bun instrument pentru asta. Folosește endpoint-ul search_by_date cu numericFilters=created_at_i>TIMESTAMP pentru a filtra după interval de date. Poți căuta după cuvinte-cheie, filtra după tipul articolului și parcurge până la 500 de pagini cu rezultate. Pentru analiză istorică în volum mare, seturi publice de date sunt disponibile și pe (arhivă completă), (28 de milioane de înregistrări) și (4 milioane de articole).

Află mai mult

Cuprins

Încearcă Thunderbit

Extrage leaduri și alte date în doar 2 clicuri. Alimentat de AI.

Obține Thunderbit Este gratuit
Extrage date folosind AI
Transferă ușor datele în Google Sheets, Airtable sau Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week