Jak scrapuji Hacker News pomocí Pythonu (2 metody, kompletní kód)

Naposledy aktualizováno August 20, 2026
Jak scrapuji Hacker News pomocí Pythonu (2 metody, kompletní kód)

Před pár měsíci jsem chtěl pro náš tým v Thunderbitu připravit denní přehled nejzajímavějších článků z Hacker News. První nápad byl úplně jednoduchý: web si jen uložit do záložek a každé ráno ho projít ručně. Vydrželo to asi tři dny, než mi došlo, že denně strávím 20 minut jen čtením nadpisů a kopírováním odkazů do tabulky.

Hacker News patří mezi nejbohatší a nejkoncentrovanější zdroje technologických informací na internetu — zhruba 13 milionů návštěv měsíčně, asi 1 300 nových příspěvků denně a přibližně 13 000 komentářů každý den. Ať už sledujete nové technologické trendy, hlídáte svou značku, stavíte náborový kanál z vláken „Who’s Hiring“, nebo prostě chcete mít přehled o tom, co hýbe vývojářským světem, ruční sledování je předem prohraný boj.

Dobrá zpráva je, že scrapování Hacker News pomocí Pythonu je překvapivě snadné. V tomhle průvodci vám ukážu dva kompletní postupy — HTML scrapování s BeautifulSoup a oficiální HN Firebase API — a přidám i stránkování, export dat, produkční postupy a no-code zkratku pro chvíle, kdy je Python zbytečně moc.

Proč scrapovat Hacker News pomocí Pythonu?

Hacker News není jen další agregátor odkazů. Je to pečlivě kurátorovaný feed řízený komunitou, kde se ty nejzajímavější technologické příběhy dostávají nahoru díky hlasům a živé diskusi. Publikum je výrazně orientované na technologické profesionály (přibližně 76 % mužů, hlavní věková skupina 25–34 let), a 66% podíl přímé návštěvnosti naznačuje, že jde o loajální publikum, ne o náhodné návštěvníky.

Proto lidé HN data scrapují:

Případ použitíCo získáte
Denní technologický digestTop příběhy, skóre a odkazy doručené do e-mailu nebo do Slacku
Monitoring značky/konkurenceUpozornění, když se zmíní vaše firma nebo produkt
Analýza trendůSledování technologií, jazyků nebo témat, která získávají na popularitě
NáborParsování vláken „Who’s Hiring“ pro nabídky práce, technologické stacky a signály o mzdách
Průzkum obsahuHledání témat, která mají výkon a stojí za to o nich psát nebo je sdílet
Sentiment analýzaZjišťování, jak komunita vnímá produkty, launch nebo změny v odvětví

Firmy s dohromady hodnotou přes 400 miliard dolarů — Stripe, Dropbox, Airbnb — připisují Hacker News zásadní ranou zpětnou vazbu i první uživatele. Drew Houston zveřejnil demo Dropboxu na HN v dubnu 2007, dostalo se na první místo a čekací listina na beta verzi vyletěla z 5 000 na 75 000 uživatelů během jediného dne. Data z HN tedy nejsou jen zajímavá — mají i přímou obchodní hodnotu.

Data jsou veřejně dostupná, ale struktura webu dělá ruční sběr zdlouhavým. Automatizace pomocí Pythonu je praktické řešení.

Dva způsoby, jak scrapovat Hacker News pomocí Pythonu: přehled

Tento průvodce pokrývá dva kompletní a spustitelné přístupy:

  1. HTML scrapování s requests + BeautifulSoup — stáhne surové HTML z news.ycombinator.com a rozparsuje ho, aby vytáhlo data o příspěvcích. Skvělé pro pochopení základů scrapování a získání přesně toho, co je na stránce.
  2. Oficiální Hacker News Firebase API — jde přímo na JSON endpointy, bez potřeby parsování HTML. Lepší pro spolehlivé datové pipeline, přístup ke komentářům a historická data.

Tady je srovnání vedle sebe, které vám pomůže vybrat správný postup:

KritériumHTML scrapování (requests + BS4)HN Firebase APIThunderbit (no-code)
Náročnost nastaveníStřední (parsování HTML selektorů)Nízká (JSON endpointy)Žádná (2 kliknutí v Chrome rozšíření)
Čerstvost datAktuální hlavní stránkaAktuální (libovolná položka podle ID)Aktuální
Riziko rate limituStřední (robots.txt uvádí 30s prodlevu)Nízké (oficiální, velkorysé)Řízeno Thunderbitem
Přístup ke komentářůmNáročný (vnořené HTML)Snadný (rekurzivní ID položek)Funkce scrapování podstránek
Historická dataOmezenáPřes Algolia Search APIN/A
Nejlepší proUčení základů scrapováníSpolehlivé datové pipelineNecodery, rychlé exporty

Obě metody obsahují kompletní, spustitelný Python kód. A pokud chcete data bez psaní jediného řádku kódu, ukážu vám i to.

Než začnete

  • Obtížnost: Začátečník až středně pokročilý
  • Čas potřebný: přibližně 15–20 minut pro každou metodu
  • Co budete potřebovat:
    • Nainstalovaný Python 3.11+
    • Terminál nebo editor kódu
    • Prohlížeč Chrome (pokud chcete prozkoumat HTML HN nebo vyzkoušet no-code variantu)
    • Thunderbit Chrome Extension (volitelné, pro no-code metodu)

scrape-hacker-news-methods.webp

Nastavení Python prostředí

Než sáhneme na jakákoli HN data, připravme si prostředí. Doporučuji vytvořit virtuální prostředí, aby byly závislosti projektu pěkně oddělené.

# Vytvoření a aktivace virtuálního prostředí
python3 -m venv hn-scraper
# macOS/Linux:
source hn-scraper/bin/activate
# Windows:
hn-scraper\Scripts\activate

# Instalace balíčků pro obě metody
pip install requests==2.33.1 beautifulsoup4==4.14.3 pandas==3.0.2 openpyxl==3.1.5

Pro produkční postupy později (kešování, retry) se vám budou hodit také:

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

Žádné speciální API klíče, žádné autentizační tokeny. Data z HN jsou otevřená.

Metoda 1: Scrapování Hacker News pomocí BeautifulSoup

Tohle je klasický přístup — stáhnout HTML, rozparsovat ho a vytáhnout potřebná data. Tímto způsobem se většina lidí učí web scraping a jednoduché tabulkové rozložení HN je ideální tréninkové hřiště.

Krok 1: Stažení hlavní stránky Hacker News

Otevřete editor a vytvořte soubor scrape_hn_bs4.py. Tady je výchozí kód:

import requests
from bs4 import BeautifulSoup

url = "https://news.ycombinator.com/news"
headers = {"User-Agent": "Mozilla/5.0 (educational HN scraper)"}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, "html.parser")

print(f"Status: {response.status_code}, Page length: {len(response.text)} chars")

Spusťte ho. Měli byste vidět Status: 200 a délku stránky kolem 40 000–50 000 znaků. To je surové HTML hlavní stránky HN uložené v paměti, připravené k parsování.

Krok 2: Pochopení struktury HTML

HN používá tabulkové rozvržení — žádný moderní CSS grid nebo flexbox. Každý příspěvek na stránce se skládá ze dvou klíčových řádků <tr>:

  • Řádek příspěvku (<tr class="athing submission">): obsahuje pořadí, název a odkaz
  • Metadatový řádek (následující <tr>): obsahuje body, autora, čas a počet komentářů

Důležité selektory:

  • span.titleline > a — název příspěvku a URL
  • span.score — počet hlasů (např. „118 points“)
  • a.hnuser — uživatelské jméno autora
  • span.age — čas publikace
  • Poslední <a> v .subtext s textem obsahujícím „comment“ — počet komentářů

Když v Chrome kliknete pravým tlačítkem na libovolný název příspěvku a zvolíte „Inspect“, uvidíte něco jako toto:

<span class="titleline">
  <a href="https://darkbloom.dev">Darkbloom – Private inference on idle Macs</a>
</span>

A pod tím metadatový řádek:

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

Pochopení těchto selektorů je zásadní — pokud HN někdy změní markup, budete muset selektory upravit. (Spoiler: metoda přes API tenhle problém obchází úplně.)

Krok 3: Extrakce názvů, odkazů a skóre

Teď to hlavní. Projdeme všechny řádky s příběhy, z řádku příspěvku vezmeme název a odkaz a z řádku pod ním pak skóre.

import requests
from bs4 import BeautifulSoup
from pprint import pprint

url = "https://news.ycombinator.com/news"
headers = {"User-Agent": "Mozilla/5.0 (educational HN scraper)"}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, "html.parser")

stories = []
story_rows = soup.select("tr.athing")

for row in story_rows:
    # Název a URL z řádku příspěvku
    title_tag = row.select_one("span.titleline > a")
    if not title_tag:
        continue
    title = title_tag.get_text()
    link = title_tag.get("href", "")

    # Metadata z následujícího řádku
    meta_row = row.find_next_sibling("tr")
    score = 0
    author = ""
    comments = 0

    if meta_row:
        if score_tag := meta_row.select_one("span.score"):
            score = int(score_tag.get_text().replace(" points", ""))
        if author_tag := meta_row.select_one("a.hnuser"):
            author = author_tag.get_text()
        # Počet komentářů: poslední <a> s textem obsahujícím "comment"
        for a_tag in meta_row.select("a"):
            text = a_tag.get_text()
            if "comment" in text:
                comments = int(text.split("\xa0")[0])

    stories.append({
        "title": title,
        "url": link,
        "score": score,
        "author": author,
        "comments": comments,
    })

# Filtrovat příběhy s 50+ body a seřadit podle skóre
top_stories = sorted(
    [s for s in stories if s["score"] >= 50],
    key=lambda x: x["score"],
    reverse=True,
)

pprint(top_stories[:10])

Pár poznámek ke kódu:

  • Walrus operátor (:=) funguje v Pythonu 3.8+. Umožňuje přiřadit a zároveň otestovat hodnotu v jednom řádku — hodí se pro volitelné prvky jako span.score, které nemusí existovat u každého řádku (např. job posty nemají skóre).
  • HN používá \xa0 (nezlomitelnou mezeru) mezi číslem a slovem „comments“, proto dělíme podle ní.
  • Příspěvky, které odkazují na jiné stránky HN (např. „Ask HN“), budou mít relativní URL začínající item?id=. Možná budete chtít doplnit https://news.ycombinator.com/.

Krok 4: Spuštění a kontrola výsledků

Uložte a spusťte:

python scrape_hn_bs4.py

Měli byste vidět výstup podobný tomuto:

[{'author': 'twapi',
  'comments': 65,
  'score': 118,
  'title': 'Darkbloom – Private inference on idle Macs',
  'url': 'https://darkbloom.dev'},
 {'author': 'sebg',
  'comments': 203,
  'score': 247,
  'title': 'Show HN: I built an open-source Perplexity alternative',
  'url': 'https://github.com/...'},
 ...]

To je 30 příběhů z první stránky. HN ale má v daný moment stovky aktivních příspěvků. Stránkování probereme v další části.

Metoda 2: Scrapování Hacker News pomocí oficiálního API

HN Firebase API je oficiálně schválený způsob, jak přistupovat k datům Hacker News. Žádná autentizace, žádné API klíče, žádné parsování HTML. Dostanete čisté JSON odpovědi. Tuhle metodu používám pro všechno, co má běžet spolehlivě v produkci.

Klíčové API endpointy, které potřebujete znát

Základní URL je https://hacker-news.firebaseio.com/v0/. Tady jsou důležité endpointy:

EndpointVracíPříklad
/v0/topstories.jsonPole až 500 ID top příběhů[47788542, 47787901, ...]
/v0/newstories.jsonAž 500 ID nejnovějších příběhůStejný formát
/v0/beststories.jsonAž 500 ID nejlepších příběhůStejný formát
/v0/askstories.jsonAž 200 ID příběhů „Ask HN“Stejný formát
/v0/showstories.jsonAž 200 ID příběhů „Show HN“Stejný formát
/v0/jobstories.jsonAž 200 ID pracovních příběhůStejný formát
/v0/item/{id}.jsonKompletní detail libovolné položky (příběh, komentář, anketa)JSON objekt
/v0/user/{username}.jsonUživatelský profilJSON objekt
/v0/maxitem.jsonAktuální nejvyšší ID položkyCelé číslo (např. 47789427)

Položka příběhu vypadá takto:

{
  "by": "twapi",
  "descendants": 65,
  "id": 47788542,
  "kids": [47789171, 47788769, 47788762],
  "score": 118,
  "time": 1776312399,
  "title": "Darkbloom – Private inference on idle Macs",
  "type": "story",
  "url": "https://darkbloom.dev"
}

Pole kids obsahuje ID přímých podkomentářů. Každý komentář je sám o sobě položka, která může mít vlastní kids — tak je postavený strom komentářů.

Krok 1: Stažení ID top příběhů

Vytvořte soubor scrape_hn_api.py:

import requests
import time
from pprint import pprint

API_BASE = "https://hacker-news.firebaseio.com/v0"

# Stažení ID top příběhů
response = requests.get(f"{API_BASE}/topstories.json")
story_ids = response.json()

print(f"Got {len(story_ids)} top story IDs")
# Output: Got 500 top story IDs

500 ID příběhů v jediném requestu — žádné parsování, žádné selektory, jen JSON pole.

Krok 2: Stažení detailů příběhu podle ID

Teď potřebujeme samotná data. Tady se ukáže problém fan-out: 500 příběhů znamená 500 samostatných API volání. V mém měření trvá jeden request na položku sekvenčně asi 1,2 sekundy. Pro 500 příběhů je to zhruba 10 minut.

Pro většinu použití ale 500 nepotřebujete. Tady je kód pro stažení top 30:

def fetch_story(story_id):
    """Stáhne detaily jednoho příběhu z HN API."""
    resp = requests.get(f"{API_BASE}/item/{story_id}.json")
    return resp.json()

# Stažení detailů pro top 30 příběhů
stories = []
for sid in story_ids[:30]:
    story = fetch_story(sid)
    if story and story.get("type") == "story":
        stories.append({
            "title": story.get("title", ""),
            "url": story.get("url", ""),
            "score": story.get("score", 0),
            "author": story.get("by", ""),
            "comments": story.get("descendants", 0),
            "time": story.get("time", 0),
            "id": story.get("id"),
        })
    time.sleep(0.1)  # Buďte ohleduplní — malá prodleva mezi requesty

# Seřadit podle skóre, zobrazit top 10
top = sorted(stories, key=lambda x: x["score"], reverse=True)[:10]
pprint(top)

time.sleep(0.1) přidává malou zdvořilostní prodlevu. Firebase API nemá uvedený rate limit, ale bombardovat jakékoli API bez pauz je prostě špatná praxe.

Krok 3: Scrapování komentářů (rekurzivní průchod stromem)

Tady API opravdu září oproti HTML scrapování. Komentáře na HN jsou hluboce zanořené — odpovědi na odpovědi na odpovědi. V HTML to znamená parsovat složitou vnořenou tabulkovou strukturu. S API má každý komentář ve svém poli kids ID potomků, takže strom projdete rekurzivně.

def fetch_comments(item_id, depth=0, max_depth=3):
    """Rekurzivně stáhne komentáře až do max_depth."""
    item = requests.get(f"{API_BASE}/item/{item_id}.json").json()
    if not item or item.get("type") != "comment":
        return []

    comments = [{
        "author": item.get("by", "[deleted]"),
        "text": item.get("text", ""),
        "depth": depth,
        "id": item.get("id"),
    }]

    if depth < max_depth and item.get("kids"):
        for kid_id in item["kids"]:
            comments.extend(fetch_comments(kid_id, depth + 1, max_depth))
            time.sleep(0.05)

    return comments

# Ukázka: komentáře k nejvýše postavenému příběhu
if stories:
    top_story = stories[0]
    top_story_full = requests.get(f"{API_BASE}/item/{top_story['id']}.json").json()
    if top_story_full.get("kids"):
        print(f"\nKomentáře pro: {top_story['title']}")
        all_comments = []
        for kid_id in top_story_full["kids"][:5]:  # Prvních 5 komentářů na nejvyšší úrovni
            all_comments.extend(fetch_comments(kid_id, depth=0, max_depth=2))
            time.sleep(0.1)

        for c in all_comments[:15]:
            indent = "  " * c["depth"]
            preview = c["text"][:80].replace("\n", " ") if c["text"] else "[bez textu]"
            print(f"{indent}[{c['author']}] {preview}...")

Tento rekurzivní přístup je výrazně jednodušší než parsování vnořených HTML vláken komentářů. Pokud potřebujete celý strom komentářů, API je správná cesta.

Krok 4: Spuštění a zobrazení výsledků

python scrape_hn_api.py

Uvidíte strukturovaná data příběhů a pak i náhled zanořených komentářů. Data jsou čistší, přístup ke komentářům je triviální a nehrozí, že se vám scraper rozbije jen proto, že HN změnil název CSS třídy.

Nad rámec první stránky: stránkování a historická data

Většina tutoriálů na HN scraping končí na první stránce — tedy 30 příbězích. Na rychlou ukázku to stačí, ale reálné scénáře často vyžadují víc.

Scrapování více stránek pomocí BeautifulSoup

Stránkování HN používá jednoduchý vzor URL: ?p=2, ?p=3 atd. Každá stránka vrací 30 příběhů a web servíruje zhruba do 20. stránky (asi 600 příběhů celkem). Pak už jsou stránky prázdné.

import time

def scrape_hn_pages(num_pages=5):
    """Scrapuje více stránek hlavního feedu HN."""
    all_stories = []

    for page in range(1, num_pages + 1):
        url = f"https://news.ycombinator.com/news?p={page}"
        response = requests.get(url, headers=headers)
        soup = BeautifulSoup(response.text, "html.parser")

        story_rows = soup.select("tr.athing")
        if not story_rows:
            print(f"Page {page}: no stories found, stopping.")
            break

        for row in story_rows:
            title_tag = row.select_one("span.titleline > a")
            if not title_tag:
                continue
            meta_row = row.find_next_sibling("tr")
            score = 0
            if meta_row and (score_tag := meta_row.select_one("span.score")):
                score = int(score_tag.get_text().replace(" points", ""))

            all_stories.append({
                "title": title_tag.get_text(),
                "url": title_tag.get("href", ""),
                "score": score,
            })

        print(f"Page {page}: scraped {len(story_rows)} stories")

        # Respektovat robots.txt a 30sekundovou prodlevu
        if page < num_pages:
            time.sleep(30)

    return all_stories

stories = scrape_hn_pages(5)
print(f"\nTotal stories scraped: {len(stories)}")

time.sleep(30) je důležité. robots.txt HN výslovně žádá 30sekundovou prodlevu mezi crawl requests. Ignorujte to a můžete skončit s rate limitingem (HTTP 429) nebo dočasným blokem. Pět stránek s 30sekundovými intervaly zabere asi 2,5 minuty — ne okamžitě, ale ohleduplně.

Pro uživatele, kteří nechtějí řešit stránkování v kódu, Thunderbit zvládá stránkování přes klikání i infinite scroll automaticky. Klikne na tlačítko „More“ dole na stránkách HN bez jakéhokoli nastavování.

Scrapujte stránky Hacker News pomocí AI

Přístup k historickým datům Hacker News přes Algolia API

Firebase API vám dá aktuální data. Pro historickou analýzu — „Jaké byly nejlepší Python příběhy v roce 2023?“ nebo „Jak se za posledních 5 let změnilo pokrytí AI?“ — potřebujete HN Algolia Search API.

import requests

ALGOLIA_BASE = "https://hn.algolia.com/api/v1"

def search_hn(query, tags="story", page=0, hits_per_page=20):
    """Vyhledávání v HN přes Algolia API."""
    params = {
        "query": query,
        "tags": tags,
        "page": page,
        "hitsPerPage": hits_per_page,
    }
    resp = requests.get(f"{ALGOLIA_BASE}/search", params=params)
    return resp.json()

# Příklad: najít příběhy o Python scrapingu s 10+ body od ledna 2024
results = search_hn(
    query="python scraping",
    tags="story",
)
print(f"Found {results['nbHits']} total results")

for hit in results["hits"][:5]:
    print(f"  [{hit.get('points', 0)} pts] {hit['title']}")

Pro dotazy filtrované podle data použijte numericFilters:

import calendar, datetime

# Příběhy od 1. ledna 2024
start_date = datetime.datetime(2024, 1, 1)
start_ts = int(calendar.timegm(start_date.timetuple()))

params = {
    "query": "python web scraping",
    "tags": "story",
    "numericFilters": f"created_at_i>{start_ts},points>10",
    "hitsPerPage": 50,
}
resp = requests.get(f"{ALGOLIA_BASE}/search_by_date", params=params)
data = resp.json()
print(f"Found {data['nbHits']} stories about Python web scraping since 2024 with >10 points")

Algolia API je rychlé (serverové zpracování za 5–9 ms), nevyžaduje API klíč a podporuje stránkování až do 500 stran. Pro hromadnou historickou analýzu je to nejlepší dostupná možnost.

Export scraped dat z Hacker News do CSV, Excelu a Google Sheets

Každý HN scraping tutorial, který jsem viděl, končí výpisem z pprint() v terminálu. To je fajn pro ladění, ale pokud tvoříte denní digest nebo děláte analýzu trendů, potřebujete data v souboru. Tady je, jak je tam dostat.

Export do CSV pomocí Pythonu

import csv

def export_to_csv(stories, filename="hn_stories.csv"):
    """Uloží scrapované příběhy do CSV souboru."""
    fieldnames = ["title", "url", "score", "author", "comments"]
    with open(filename, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(stories)
    print(f"Saved {len(stories)} stories to {filename}")

export_to_csv(stories)

Export do Excelu pomocí Pythonu

import pandas as pd

def export_to_excel(stories, filename="hn_stories.xlsx"):
    """Uloží scrapované příběhy do Excel souboru."""
    df = pd.DataFrame(stories)
    df.to_excel(filename, index=False, engine="openpyxl")
    print(f"Saved {len(stories)} stories to {filename}")

export_to_excel(stories)

Ujistěte se, že máte nainstalovaný openpyxl — pandas ho používá jako Excel engine. Pokud chybí, dostanete ImportError.

Odeslání do Google Sheets (volitelné)

Pro automatizované workflow můžete data posílat přímo do Google Sheets pomocí knihovny gspread. To vyžaduje nastavení Google Cloud service accountu (jednorázový proces):

import gspread

gc = gspread.service_account(filename="service_account.json")
sh = gc.open("HN Daily Digest")
worksheet = sh.sheet1

# Převod stories na řádky
header = list(stories[0].keys())
rows = [list(s.values()) for s in stories]

worksheet.clear()
worksheet.update([header] + rows)
print("Pushed to Google Sheets")

No-code alternativa exportu

Jestli nastavení service accountů a psaní exportního kódu zní jako víc práce než samotné scrapování, rozumím tomu. V Thunderbitu jsme vytvořili bezplatný export dat, díky kterému můžete odesílat scrapovaná data přímo do Excelu, Google Sheets, Airtable nebo Notion — bez kódu, bez přihlašovacích údajů, bez pipeline na údržbu. Pro jednorázové stažení dat je to upřímně rychlejší. Níže o tom víc.

Jak udělat scraper připravený pro produkci: ošetření chyb, kešování a plánování

Když scraper spouštíte jednou jen tak pro zábavu, výše uvedený kód stačí. Když ho ale spouštíte denně jako součást workflow, potřebujete ještě pár věcí.

Ošetření chyb a retry logika

Sítě selhávají. Servery omezují provoz. Jediný chybný request by neměl shodit celý scraping. Tady je retry funkce s exponenciálním backoffem:

from tenacity import retry, stop_after_attempt, wait_exponential_jitter
import requests

@retry(stop=stop_after_attempt(5), wait=wait_exponential_jitter(initial=1, max=60))
def fetch_with_retry(url):
    """Stáhne URL s automatickými pokusy a exponenciálním backoffem."""
    response = requests.get(url, timeout=10)
    response.raise_for_status()
    return response

# Použití:
try:
    resp = fetch_with_retry("https://hacker-news.firebaseio.com/v0/topstories.json")
    story_ids = resp.json()
except Exception as e:
    print(f"Failed after retries: {e}")

Knihovna tenacity řeší retry logiku elegantně. Zkusí request až 5krát s jitterovaným exponenciálním backoffem — začne na 1 sekundě a maximálně dosáhne 60 sekund. Dobře tím pokryjete HTTP 429 (rate limit), 503 (service unavailable) i přechodné síťové chyby.

Kešování odpovědí, abyste neprocházeli web znovu a znovu

Při vývoji budete scraper spouštět mnohokrát, zatímco ladíte parsovací logiku. Bez keše se při každém spuštění na stejné data znovu a znovu obracíte na servery HN. Knihovna requests-cache to vyřeší dvěma řádky:

import requests_cache

requests_cache.install_cache("hn_cache", expire_after=3600)  # Keš na 1 hodinu

Po přidání těchto řádků na začátek skriptu budou všechny requests.get() automaticky kešované v lokální SQLite databázi. Spusťte skript během hodiny 10× a jen první běh skutečně sáhne na síť. To je nástroj, který uživatelé fór často doporučují, a má to dobrý důvod.

Oddělení crawlování od parsování

Zkušení scrapovači nedají dopustit na tenhle vzor: nejdřív stáhnout surová data, až potom je parsovat. Když se vám parser pokazí, prostě ho opravíte a data rozparsujete znovu, aniž byste je museli znovu stahovat.

import os, json

def crawl_and_save(story_ids, output_dir="raw_data"):
    """Stáhne data příběhů a uloží surové JSON na disk."""
    os.makedirs(output_dir, exist_ok=True)
    for sid in story_ids:
        filepath = os.path.join(output_dir, f"{sid}.json")
        if os.path.exists(filepath):
            continue  # Přeskočit už stažené položky
        resp = fetch_with_retry(f"{API_BASE}/item/{sid}.json")
        with open(filepath, "w") as f:
            json.dump(resp.json(), f)

def parse_saved_data(input_dir="raw_data"):
    """Rozparsuje uložené JSON soubory do strukturovaného seznamu příběhů."""
    stories = []
    for filename in os.listdir(input_dir):
        with open(os.path.join(input_dir, filename)) as f:
            item = json.load(f)
        if item and item.get("type") == "story":
            stories.append({
                "title": item.get("title", ""),
                "url": item.get("url", ""),
                "score": item.get("score", 0),
                "author": item.get("by", ""),
                "comments": item.get("descendants", 0),
            })
    return stories

Tenhle dvoufázový přístup je obzvlášť užitečný, když scrapujete stovky položek a chcete rychle iterovat nad tím, jak data zpracováváte.

Automatizace scrapingu podle plánu

Pro denní HN digest potřebujete, aby scraper běžel automaticky. Dvě běžné možnosti:

Možnost 1: cron (Linux/Mac)

# Spustit každý den v 8:30 UTC
30 8 * * * /usr/bin/python3 /home/user/scrape_hn.py >> /home/user/scrape.log 2>&1

Možnost 2: GitHub Actions (zdarma, bez serveru)

name: Scrape Hacker News

on:
  schedule:
    - cron: '30 8 * * *'  # Denně v 8:30 UTC
  workflow_dispatch:        # Tlačítko pro ruční spuštění

jobs:
  scrape:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v6
        with:
          python-version: '3.12'
      - run: pip install requests beautifulsoup4 pandas openpyxl
      - run: python scrape_hn.py
      - run: |
          git config user.name "GitHub Actions Bot"
          git config user.email "actions@github.com"
          git add -A
          git diff --staged --quiet || git commit -m "Update HN data $(date -u +%Y-%m-%dT%H:%M:%SZ)"
          git push

Pár háčků u plánování v GitHub Actions: všechny cron časy jsou v UTC, zpoždění 15–60 minut je běžné (používejte třeba :30 místo :00) a GitHub může naplánované workflow vypnout u repozitářů bez aktivity po dobu 60 dnů. Vždy přidejte workflow_dispatch, abyste mohli workflow ručně spustit při testování.

Pro jednodušší variantu Thunderbit nabízí funkci Scheduled Scraper, kde můžete plán popsat normální angličtinou — třeba „scrape every morning at 8am“ — bez serveru a bez nastavování cronu.

Kdy je Python zbytečně moc: no-code způsob, jak scrapovat Hacker News

Budu upřímný, i když jsem fanoušek Pythonu a můj tým staví vývojářské nástroje. Když potřebujete jen dnešních top 100 příběhů z HN v tabulce — hned, jednorázově — psát, ladit a spouštět Python skript je zbytečná režie. Jen samotné nastavení (virtuální prostředí, instalace balíčků, hledání selektorů) zabere víc času než samotný sběr dat.

Právě sem patří Thunderbit. Postup vypadá takto:

  1. Otevřete news.ycombinator.com v Chrome
  2. Klikněte na ikonu rozšíření Thunderbit a pak na „AI Suggest Fields“
  3. AI přečte stránku a navrhne sloupce: Title, URL, Score, Author, Comment Count, Time Posted
  4. Pole si upravte podle potřeby (přejmenujte, odstraňte nebo přidejte vlastní — můžete přidat i AI prompt typu „Klasifikuj jako AI/DevTools/Web/Ostatní“)
  5. Klikněte na „Scrape“ — data se zobrazí ve strukturované tabulce
  6. Exportujte do Excelu, Google Sheets, Airtable nebo Notion

Dva kliky a máte strukturovaná data. Žádné selektory, žádný kód, žádná údržba.

Velká výhoda: Thunderbit se automaticky přizpůsobuje změnám rozložení. Tradiční scrapers založené na CSS selektorech se rozbijí, když web změní markup — a i když je HTML HN poměrně stabilní, měnilo se (class="athing submission" se aktualizovalo, span.titleline nahradilo starší a.storylink). AI scraper si stránku načte znovu pokaždé, takže mu změny názvů tříd nevadí.

python-vs-thunderbit-comparison.webp

Thunderbit také zvládá stránkování (automaticky kliká na tlačítko „More“ na HN) a scrapování podstránek (navštíví stránku komentářů u každého příběhu a stáhne diskusi). Pro use case obohacení o komentáře je to ekvivalent rekurzivního API kódu z Metody 2 — ale bez psaní jediného řádku.

Rozhodnutí je celkem jasné: Python je správná volba, když potřebujete vlastní logiku, složité transformace dat, automatizované plánované pipeline nebo se prostě učíte programovat. Thunderbit je správná volba, když chcete data rychle, nechcete udržovat kód, nebo nejste vývojář. Vyberte si nástroj, který odpovídá vaší situaci.

Python vs. API vs. no-code: kterou metodu zvolit?

Tady je kompletní rozhodovací rámec:

KritériumBeautifulSoup (HTML)Firebase APIAlgolia APIThunderbit (no-code)
Potřebná technická úroveňStředně pokročilý PythonZačátečnický PythonZačátečnický PythonŽádná
Čas na nastavení10–15 min5–10 min5–10 min2 min
Nároky na údržbuStřední (selektory se rozbijí)Nízké (stabilní JSON)Nízké (stabilní JSON)Žádné
Hloubka datJen hlavní stránkaLibovolná položka, uživateléVyhledávání + historieHlavní stránka + podstránky
KomentářeNáročnéSnadné (rekurzivně)Snadné (vnořený strom)Scrapování podstránek
Historická dataNeNeAno (plný archiv)Ne
Možnosti exportuNaprogramujete samiNaprogramujete samiNaprogramujete samiVestavěné (Excel, Sheets atd.)
Plánovánícron / GitHub Actionscron / GitHub Actionscron / GitHub ActionsVestavěný plánovač
Nejlepší proUčení scrapováníSpolehlivé pipelineVýzkum a analýzuRychlé získání dat

Pokud se učíte Python nebo stavíte něco na míru, zvolte Metodu 1 nebo 2. Pokud potřebujete historickou analýzu, přidejte Algolia API. Pokud chcete data bez kódu, vyzkoušejte Thunderbit.

Vyzkoušejte Thunderbit pro scrapování Hacker News

Závěr a klíčová zjištění

Teď máte v nástrojové sadě:

  • Dvě kompletní Python metody pro scrapování Hacker News — BeautifulSoup pro parsování HTML a Firebase API pro čistá JSON data
  • Techniky stránkování pro scrapování za první stránku, včetně Algolia API pro historická data sahající zpět do roku 2007
  • Exportní kód pro CSV, Excel a Google Sheets — protože data v terminálu jsou ostatním v týmu k ničemu
  • Produkční postupy — retry logika, kešování, oddělení crawl/parsing a plánovaná automatizace přes cron nebo GitHub Actions
  • No-code alternativu pro chvíle, kdy je Python větší nástroj, než potřebujete

Moje doporučení: pro většinu případů začněte s Firebase API (Metoda 2). Je čistší, spolehlivější a umožňuje přístup ke komentářům bez trápení s parsováním vnořeného HTML. Když potřebujete historická data, přidejte Algolia API. A Thunderbit si uložte do záložek pro chvíle, kdy chcete jen rychlou tabulku a nechcete rozjíždět celý Python projekt.

Pokud chcete jít víc do hloubky, zkuste scrapovat komentáře na HN pro sentiment analýzu, postavte denní digest pipeline pomocí GitHub Actions nebo prozkoumejte Algolia API a sledujte, jak se technologické trendy změnily za poslední dekádu.

Vyzkoušejte Thunderbit pro rychlé scrapování Hacker News Get Started Free

Často kladené otázky

Je legální scrapovat Hacker News?

Data z HN jsou veřejně dostupná a Y Combinator poskytuje oficiální API právě pro programatický přístup. robots.txt webu dovoluje scrapování jen pro čtení dostupného obsahu (hlavní stránka, stránky položek, uživatelské stránky), ale žádá 30sekundovou prodlevu mezi crawl requests. Když tu prodlevu dodržíte, nesaháte na interaktivní endpointy (hlasování, přihlášení) a držíte se rozumného tempa, jste na bezpečné půdě. Více k etice scrapování najdete v našem průvodci právními dopady web scrapingu.

Má Hacker News oficiální API?

Ano. HN Firebase API na adrese hacker-news.firebaseio.com/v0/ je zdarma, nevyžaduje autentizaci a poskytuje přístup k příběhům, komentářům, uživatelským profilům i všem typům feedů (top, new, best, ask, show, jobs). Vrací čistý JSON a nemá uvedený rate limit, i když je vždy dobré být ohleduplný v četnosti requestů.

Jak scrapovat komentáře z Hacker News pomocí Pythonu?

Pomocí Firebase API si stáhněte položku příběhu a získejte pole kids (pole ID top-level komentářů). Každý komentář je zase položka s vlastním polem kids pro odpovědi. Strom projděte rekurzivní funkcí, která načte každý komentář a jeho potomky. Kompletní kód najdete výše v části „Scrapování komentářů (rekurzivní průchod stromem)“. Alternativně endpoint Algolia API /items/<id> vrací celý zanořený strom komentářů v jediném requestu — výrazně rychlejší u příběhů s velkým množstvím komentářů.

Dá se Hacker News scrapovat i bez kódu?

Ano. AI web scraper od Thunderbitu funguje jako Chrome rozšíření — otevřete HN, klikněte na „AI Suggest Fields“ a automaticky rozpozná sloupce jako title, URL, score a author. Klikněte na „Scrape“ a exportujte přímo do Excelu, Google Sheets, Airtable nebo Notion. Zvládá stránkování a umí dokonce navštívit podstránky, aby získal i data z komentářů. Žádný Python, žádné selektory, žádná údržba.

Jak získám historická data z Hacker News?

Nejlepší nástroj pro to je HN Algolia Search API. Použijte endpoint search_by_date s numericFilters=created_at_i>TIMESTAMP pro filtrování podle časového období. Můžete vyhledávat podle klíčového slova, filtrovat podle typu příběhu a stránkovat až do 500 stran výsledků. Pro hromadnou historickou analýzu jsou veřejně dostupné také datasety na Google BigQuery (plný archiv), ClickHouse (28 milionů záznamů) a Hugging Face (4 miliony příběhů).

Další články

Shuai Guan
Shuai Guan
CEO ve společnosti Thunderbit | Expert na automatizaci dat s využitím AI Shuai Guan je CEO společnosti Thunderbit a absolvent inženýrského oboru na University of Michigan. Na základě téměř deseti let zkušeností v oblasti technologií a architektury SaaS se zaměřuje na převádění složitých modelů AI do praktických nástrojů pro extrakci dat bez nutnosti programování. Na tomto blogu sdílí nezkreslené a v praxi ověřené poznatky o web scrapingu a automatizačních strategiích, které vám pomohou vytvářet chytřejší datově řízené pracovní postupy. Když zrovna neoptimalizuje datové workflow, věnuje stejný důraz na detail také své vášni pro fotografii.
Obsah
Thunderbit · AI agent pro webová data

Extrahuj data z libovolné stránky za 1 kliknutí

Důvěřuje mu více než 250 000 uživatelů
k dispozici bezplatný plán
Z webové stránky do tabulky
Popiš, co potřebuješ — AI agent Thunderbit to nasbírá a exportuje do Excelu, Google Sheets, Airtable nebo Notion. Začni zdarma.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week