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ý digest | Top příběhy, skóre a odkazy doručené do e-mailu nebo do Slacku |
| Monitoring značky/konkurence | Upozorně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ábor | Parsování vláken „Who’s Hiring“ pro nabídky práce, technologické stacky a signály o mzdách |
| Průzkum obsahu | Hledání témat, která mají výkon a stojí za to o nich psát nebo je sdílet |
| Sentiment analýza | Zjišť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:
- 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. - 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érium | HTML scrapování (requests + BS4) | HN Firebase API | Thunderbit (no-code) |
|---|---|---|---|
| Náročnost nastavení | Střední (parsování HTML selektorů) | Nízká (JSON endpointy) | Žádná (2 kliknutí v Chrome rozšíření) |
| Čerstvost dat | Aktuální hlavní stránka | Aktuální (libovolná položka podle ID) | Aktuální |
| Riziko rate limitu | Střední (robots.txt uvádí 30s prodlevu) | Nízké (oficiální, velkorysé) | Řízeno Thunderbitem |
| Přístup ke komentářům | Náročný (vnořené HTML) | Snadný (rekurzivní ID položek) | Funkce scrapování podstránek |
| Historická data | Omezená | Přes Algolia Search API | N/A |
| Nejlepší pro | Učení základů scrapování | Spolehlivé datové pipeline | Necodery, 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)

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 URLspan.score— počet hlasů (např. „118 points“)a.hnuser— uživatelské jméno autoraspan.age— čas publikace- Poslední
<a>v.subtexts 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 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 jakospan.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 doplnithttps://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:
| Endpoint | Vrací | Příklad |
|---|---|---|
/v0/topstories.json | Pole až 500 ID top příběhů | [47788542, 47787901, ...] |
/v0/newstories.json | Až 500 ID nejnovějších příběhů | Stejný formát |
/v0/beststories.json | Až 500 ID nejlepších příběhů | Stejný formát |
/v0/askstories.json | Až 200 ID příběhů „Ask HN“ | Stejný formát |
/v0/showstories.json | Až 200 ID příběhů „Show HN“ | Stejný formát |
/v0/jobstories.json | Až 200 ID pracovních příběhů | Stejný formát |
/v0/item/{id}.json | Kompletní detail libovolné položky (příběh, komentář, anketa) | JSON objekt |
/v0/user/{username}.json | Uživatelský profil | JSON objekt |
/v0/maxitem.json | Aktuální nejvyšší ID položky | Celé čí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:
- Otevřete
news.ycombinator.comv Chrome - Klikněte na ikonu rozšíření Thunderbit a pak na „AI Suggest Fields“
- AI přečte stránku a navrhne sloupce: Title, URL, Score, Author, Comment Count, Time Posted
- 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í“)
- Klikněte na „Scrape“ — data se zobrazí ve strukturované tabulce
- 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í.

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érium | BeautifulSoup (HTML) | Firebase API | Algolia API | Thunderbit (no-code) |
|---|---|---|---|---|
| Potřebná technická úroveň | Středně pokročilý Python | Začátečnický Python | Začátečnický Python | Žádná |
| Čas na nastavení | 10–15 min | 5–10 min | 5–10 min | 2 min |
| Nároky na údržbu | Střední (selektory se rozbijí) | Nízké (stabilní JSON) | Nízké (stabilní JSON) | Žádné |
| Hloubka dat | Jen hlavní stránka | Libovolná položka, uživatelé | Vyhledávání + historie | Hlavní stránka + podstránky |
| Komentáře | Náročné | Snadné (rekurzivně) | Snadné (vnořený strom) | Scrapování podstránek |
| Historická data | Ne | Ne | Ano (plný archiv) | Ne |
| Možnosti exportu | Naprogramujete sami | Naprogramujete sami | Naprogramujete sami | Vestavěné (Excel, Sheets atd.) |
| Plánování | cron / GitHub Actions | cron / GitHub Actions | cron / GitHub Actions | Vestavěný plánovač |
| Nejlepší pro | Učení scrapování | Spolehlivé pipeline | Výzkum a analýzu | Rychlé 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


