Wie ich Hacker News mit Python scrape (2 Methoden, kompletter Code)

Zuletzt aktualisiert am April 16, 2026
Wie ich Hacker News mit Python scrape (2 Methoden, kompletter Code)

Vor ein paar Monaten wollte ich für unser Team bei Thunderbit einen täglichen Überblick über die wichtigsten Hacker-News-Storys aufsetzen. Mein erster Gedanke war, die Seite einfach zu bookmarken und mir jeden Morgen die Beiträge anzuschauen. Das hat ungefähr drei Tage funktioniert, bis mir klar wurde, dass ich jeden Tag rund 20 Minuten damit verbringe, Überschriften zu lesen und Links händisch in eine Tabelle zu kopieren.

Hacker News ist eine der ergiebigsten und zugleich am stärksten verdichteten Quellen für Tech-Intelligenz im Internet — mit rund 13 Millionen Besuchen pro Monat, etwa 1.300 neu eingereichten Stories pro Tag und ungefähr 13.000 Kommentaren täglich. Egal ob du neue Tech-Trends verfolgen, deine Marke im Blick behalten, aus "Who's Hiring"-Threads einen Recruiting-Stream bauen oder einfach nah dran bleiben willst, was in der Entwicklerwelt gerade abgeht: Alles manuell mitzulesen ist ein Kampf, den man auf Dauer nicht gewinnt.

Die gute Nachricht: Hacker News mit Python zu scrapen ist überraschend einfach. In diesem Leitfaden zeige ich dir zwei vollständige Wege — HTML-Scraping mit BeautifulSoup und die offizielle HN Firebase API — inklusive Pagination, Datenexport, produktionsreifen Mustern und einem No-Code-Shortcut für den Fall, dass Python dir zu viel des Guten erscheint.

Warum Hacker News mit Python scrapen?

Hacker News ist nicht bloß ein weiterer Link-Aggregator. Es ist ein kuratierter, von der Community getriebener Feed, bei dem die spannendsten Tech-Storys durch Upvotes und lebhafte Diskussionen nach oben gespült werden. Die Zielgruppe ist stark technikaffin (etwa 76 % männlich, Hauptalter 25–34), und die Direktzugriffsrate von 66 % zeigt: Hier liest eine treue Stammleserschaft mit — nicht zufällige Laufkundschaft.

Darum scrapen Menschen HN-Daten:

AnwendungsfallWas du bekommst
Tägliches Tech-BriefingTop-Storys, Scores und Links direkt per E-Mail oder Slack
Marken- und WettbewerbsmonitoringBenachrichtigungen, wenn dein Unternehmen oder Produkt erwähnt wird
TrendanalyseVerfolge, welche Technologien, Sprachen oder Themen im Zeitverlauf an Fahrt gewinnen
RecruitingAnalysiere "Who's Hiring"-Threads nach Stellenangeboten, Tech-Stacks und Gehaltsindikatoren
Content-RechercheFinde Themen mit hoher Resonanz für neue Inhalte
Sentiment-AnalyseErmittle die Stimmung der Community zu Produkten, Launches oder Branchenentwicklungen

Unternehmen mit zusammen mehr als 400 Milliarden US-Dollar Marktkapitalisierung — darunter Stripe, Dropbox und Airbnb — haben Hacker News wichtige frühe Rückmeldungen und Nutzer zu verdanken. Drew Houston stellte im April 2007 die Dropbox-Demo auf HN ein, sie landete auf Platz 1, und die Beta-Warteliste sprang an einem einzigen Tag von 5.000 auf 75.000 Nutzer. HN-Daten sind also nicht nur spannend, sondern auch wirtschaftlich relevant.

Die Daten sind öffentlich verfügbar, aber die Struktur der Seite macht die manuelle Erfassung mühsam. Automatisierung mit Python ist hier die pragmatische Lösung.

Zwei Wege, Hacker News mit Python zu scrapen: Überblick

Dieser Leitfaden deckt zwei vollständige, direkt ausführbare Ansätze ab:

  1. HTML-Scraping mit requests + BeautifulSoup — lädt das rohe HTML von news.ycombinator.com und liest daraus die Story-Daten aus. Ideal, um die Grundlagen des Scrapings zu lernen und die Inhalte der Seite sehr genau zu erfassen.
  2. Die offizielle Hacker News Firebase API — greift direkt auf JSON-Endpunkte zu, ganz ohne HTML-Parsing. Besser für robuste Datenpipelines, Kommentare und historische Daten.

Hier ein direkter Vergleich, damit du leichter entscheiden kannst, was zu deinem Bedarf passt:

KriteriumHTML-Scraping (requests + BS4)HN Firebase APIThunderbit (No-Code)
EinrichtungsaufwandMittel (HTML-Selektoren parsen)Niedrig (JSON-Endpunkte)Keiner (Chrome-Erweiterung in 2 Klicks)
Aktualität der DatenEchtzeit-StartseiteEchtzeit (jedes Item per ID)Echtzeit
Risiko durch Rate LimitsMittel (robots.txt nennt 30 Sekunden Crawl-Delay)Niedrig (offiziell, großzügig)Von Thunderbit verwaltet
Zugriff auf KommentareSchwer (verschachteltes HTML)Einfach (rekursive Item-IDs)Subpage-Scraping-Funktion
Historische DatenBegrenztÜber die Algolia Search APIN/A
Am besten geeignet fürScraping-Grundlagen lernenZuverlässige DatenpipelinesNicht-Entwickler, schnelle Exporte

Beide Methoden enthalten vollständigen, ausführbaren Python-Code. Und wenn du einfach nur die Daten willst, ohne überhaupt Code zu schreiben, zeige ich dir auch dafür eine Lösung.

Bevor du startest

  • Schwierigkeitsgrad: Anfänger bis Fortgeschrittene
  • Benötigte Zeit: ca. 15–20 Minuten pro Methode
  • Was du brauchst:
    • Python 3.11+ installiert
    • Ein Terminal oder Code-Editor
    • Chrome-Browser (wenn du HNs HTML ansehen oder die No-Code-Option ausprobieren möchtest)
    • Thunderbit Chrome Extension (optional, für die No-Code-Methode)

scrape-hacker-news-methods.webp

Python-Umgebung einrichten

Bevor wir uns an HN-Daten machen, richten wir die Umgebung ein. Ich empfehle eine virtuelle Umgebung, damit die Abhängigkeiten sauber getrennt bleiben.

# Virtuelle Umgebung erstellen und aktivieren
python3 -m venv hn-scraper
# macOS/Linux:
source hn-scraper/bin/activate
# Windows:
hn-scraper\Scripts\activate

# Benötigte Pakete für beide Methoden installieren
pip install requests==2.33.1 beautifulsoup4==4.14.3 pandas==3.0.2 openpyxl==3.1.5

Für die späteren Produktionsmuster (Caching, Retries) brauchst du außerdem:

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

Keine API-Keys, keine Authentifizierungstokens. Die HN-Daten sind frei zugänglich.

Methode 1: Hacker News mit Python und BeautifulSoup scrapen

Das ist der klassische Weg — HTML abrufen, parsen und die gewünschten Daten herausziehen. So lernen die meisten Menschen Web Scraping, und das tabellenbasierte HN-Layout ist dafür ein gutes Übungsfeld.

Schritt 1: Die Hacker-News-Startseite abrufen

Öffne deinen Editor und erstelle eine Datei namens scrape_hn_bs4.py. Hier ist der Startcode:

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}, Seitenlänge: {len(response.text)} Zeichen")

Führe das Skript aus. Du solltest Status: 200 und eine Seitenlänge von ungefähr 40.000–50.000 Zeichen sehen. Das ist das rohe HTML der HN-Startseite, das nun im Speicher liegt und geparst werden kann.

Schritt 2: Die HTML-Struktur verstehen

HN nutzt ein tabellenbasiertes Layout — kein modernes CSS Grid oder Flexbox. Jede Story auf der Seite besteht aus zwei wichtigen <tr>-Zeilen:

  • Die Story-Zeile (<tr class="athing submission">): enthält Rang, Titel und Link
  • Die Metadaten-Zeile (die nächste <tr>): enthält Punkte, Autor, Zeitpunkt und Kommentaranzahl

Die wichtigsten Selektoren:

  • span.titleline > a — Titel und URL der Story
  • span.score — die Punktzahl (z. B. "118 points")
  • a.hnuser — der Benutzername des Autors
  • span.age — der Veröffentlichungszeitpunkt
  • Das letzte <a> in .subtext mit "comment" im Text — die Kommentaranzahl

Wenn du in Chrome auf einen Story-Titel rechtsklickst und "Untersuchen" wählst, siehst du etwa Folgendes:

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

Und darunter die Metadaten-Zeile:

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

Diese Selektoren zu verstehen ist entscheidend — wenn HN sein Markup ändert, musst du sie anpassen. (Spoiler: Die API-Methode umgeht dieses Problem komplett.)

Schritt 3: Titel, Links und Scores extrahieren

Jetzt kommt der eigentliche Teil. Wir gehen jede Story-Zeile durch, holen Titel und Link aus der Story-Zeile und lesen dann den Score aus der direkt darunterliegenden Metadaten-Zeile aus.

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:
    # Titel und URL aus der Story-Zeile
    title_tag = row.select_one("span.titleline > a")
    if not title_tag:
        continue
    title = title_tag.get_text()
    link = title_tag.get("href", "")

    # Metadaten aus der nächsten Zeile
    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()
        # Kommentaranzahl: letztes <a> mit "comment" im Text
        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,
    })

# Stories mit 50+ Punkten filtern und nach Score sortieren
top_stories = sorted(
    [s for s in stories if s["score"] >= 50],
    key=lambda x: x["score"],
    reverse=True,
)

pprint(top_stories[:10])

Ein paar Hinweise zum Code:

  • Der Walrus-Operator (:=) funktioniert ab Python 3.8. Damit kannst du zuweisen und prüfen zugleich — praktisch für optionale Elemente wie span.score, die nicht in jeder Zeile existieren (z. B. bei Job-Posts ohne Punkte).
  • HN verwendet \xa0 (geschütztes Leerzeichen) zwischen Zahl und "comments", deshalb teilen wir an dieser Stelle.
  • Stories, die auf andere HN-Seiten verlinken (z. B. "Ask HN"-Beiträge), haben relative URLs, die mit item?id= beginnen. Dafür kannst du bei Bedarf https://news.ycombinator.com/ voranstellen.

Schritt 4: Ausführen und Ergebnisse ansehen

Speichere und führe aus:

python scrape_hn_bs4.py

Du solltest eine Ausgabe wie diese sehen:

[{'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/...'},
 ...]

Das sind 30 Stories von Seite 1. Hacker News hat aber zu jedem Zeitpunkt Hunderte aktive Stories. Pagination behandeln wir weiter unten.

Methode 2: Hacker News mit Python über die offizielle API scrapen

Die HN Firebase API ist der offiziell unterstützte Weg, um auf Hacker-News-Daten zuzugreifen. Keine Authentifizierung, keine API-Keys, kein HTML-Parsing. Du erhältst saubere JSON-Antworten. Ich nutze diese Methode immer dann, wenn etwas zuverlässig in Produktion laufen muss.

Wichtige API-Endpunkte, die du kennen solltest

Die Basis-URL lautet https://hacker-news.firebaseio.com/v0/. Diese Endpunkte sind relevant:

EndpunktLiefertBeispiel
/v0/topstories.jsonArray mit bis zu 500 Top-Story-IDs[47788542, 47787901, ...]
/v0/newstories.jsonBis zu 500 neueste Story-IDsGleiches Format
/v0/beststories.jsonBis zu 500 beste Story-IDsGleiches Format
/v0/askstories.jsonBis zu 200 "Ask HN"-Story-IDsGleiches Format
/v0/showstories.jsonBis zu 200 "Show HN"-Story-IDsGleiches Format
/v0/jobstories.jsonBis zu 200 Job-Story-IDsGleiches Format
/v0/item/{id}.jsonVollständige Details zu jedem Item (Story, Kommentar, Poll)JSON-Objekt
/v0/user/{username}.jsonBenutzerprofilJSON-Objekt
/v0/maxitem.jsonAktuelle höchste Item-IDInteger (z. B. 47789427)

Ein Story-Objekt sieht so aus:

{
  "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"
}

Das Feld kids enthält die IDs der direkten Unterkommentare. Jeder Kommentar ist wiederum ein eigenes Item, das ebenfalls kids haben kann — so ist der Kommentarbaum aufgebaut.

Schritt 1: Top-Story-IDs abrufen

Erstelle eine Datei namens scrape_hn_api.py:

import requests
import time
from pprint import pprint

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

# Top-Story-IDs abrufen
response = requests.get(f"{API_BASE}/topstories.json")
story_ids = response.json()

print(f"{len(story_ids)} Top-Story-IDs erhalten")
# Ausgabe: 500 Top-Story-IDs

500 Story-IDs in einer einzigen Anfrage — kein Parsen, keine Selektoren, nur ein JSON-Array.

Schritt 2: Story-Details per ID abrufen

Jetzt brauchen wir die eigentlichen Story-Daten. Hier zeigt sich das Fan-out-Problem: 500 Stories bedeuten 500 einzelne API-Aufrufe. In meinen Tests dauert jede Item-Anfrage nacheinander ungefähr 1,2 Sekunden. Bei 500 Stories sind das rund 10 Minuten.

Für die meisten Anwendungsfälle brauchst du ohnehin nicht alle 500. Hier ist Code, der die Top 30 holt:

def fetch_story(story_id):
    """Ruft die Details einer einzelnen Story über die HN-API ab."""
    resp = requests.get(f"{API_BASE}/item/{story_id}.json")
    return resp.json()

# Details für die Top 30 Stories abrufen
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)  # Höflich bleiben — kleine Pause zwischen den Anfragen

# Nach Score sortieren, Top 10 anzeigen
top = sorted(stories, key=lambda x: x["score"], reverse=True)[:10]
pprint(top)

time.sleep(0.1) sorgt für eine kleine Pause. Die Firebase API nennt zwar kein explizites Rate Limit, aber jede API ohne Pausen zu belasten ist keine gute Praxis.

Schritt 3: Kommentare scrapen (rekursiver Baumdurchlauf)

Hier spielt die API ihren größten Vorteil gegenüber HTML-Scraping aus. Kommentare auf HN sind tief verschachtelt — Antworten auf Antworten auf Antworten. Im HTML bedeutet das, komplexe verschachtelte Tabellen zu parsen. Über die API liefert das kids-Feld jeder Kommentar-ID einfach die Kind-IDs, und du läufst rekursiv durch den Baum.

def fetch_comments(item_id, depth=0, max_depth=3):
    """Ruft Kommentare rekursiv bis max_depth ab."""
    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", "[gelöscht]"),
        "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

# Beispiel: Kommentare für die Top-Story abrufen
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"\nKommentare zu: {top_story['title']}")
        all_comments = []
        for kid_id in top_story_full["kids"][:5]:  # Erste 5 Top-Level-Kommentare
            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 "[kein Text]"
            print(f"{indent}[{c['author']}] {preview}...")

Dieser rekursive Ansatz ist deutlich einfacher, als verschachtelte Kommentar-Threads im HTML zu parsen. Wenn du vollständige Kommentarbäume brauchst, ist die API der richtige Weg.

Schritt 4: Ausführen und Ergebnisse ansehen

python scrape_hn_api.py

Du siehst strukturierte Story-Daten und darunter eine verschachtelte Kommentarvorschau. Die Daten sind sauberer, der Kommentarzugriff ist trivial, und du läufst nicht Gefahr, dass dein Scraper scheitert, nur weil HN eine CSS-Klasse umbenannt hat.

Mehr als nur Seite 1: Pagination und historische Daten

Die meisten HN-Scraping-Tutorials hören nach Seite 1 auf — also nach 30 Stories. Für einen schnellen Demo-Case reicht das, aber echte Anwendungsfälle brauchen oft mehr Tiefe.

Mehrere Seiten mit BeautifulSoup scrapen

Die Pagination von HN nutzt ein einfaches URL-Muster: ?p=2, ?p=3 usw. Jede Seite liefert 30 Stories, und die Seite stellt ungefähr bis Seite 20 Inhalte bereit (insgesamt rund 600 Stories). Danach kommen leere Seiten.

import time

def scrape_hn_pages(num_pages=5):
    """Mehrere Seiten der HN-Startseite scrapen."""
    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"Seite {page}: keine Stories gefunden, Abbruch.")
            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"Seite {page}: {len(story_rows)} Stories gescraped")

        # robots.txt-Crawl-Delay von 30 Sekunden respektieren
        if page < num_pages:
            time.sleep(30)

    return all_stories

stories = scrape_hn_pages(5)
print(f"\nInsgesamt gescrapete Stories: {len(stories)}")

time.sleep(30) ist wichtig. HNs robots.txt verlangt ausdrücklich ein Crawl-Delay von 30 Sekunden. Wer das ignoriert, riskiert Rate Limits (HTTP 429) oder eine vorübergehende Sperre. Fünf Seiten mit 30-Sekunden-Abständen dauern also etwa 2,5 Minuten — nicht blitzschnell, aber fair.

Wer die Pagination nicht selbst programmieren will, kann mit Thunderbit klickbasierte und Infinite-Scroll-Pagination automatisch verarbeiten. Das Tool klickt den "More"-Button am Seitenende ohne jede Konfiguration.

Hacker-News-Seiten mit KI scrapen

Historische Hacker-News-Daten mit der Algolia API abrufen

Die Firebase API liefert aktuelle Daten. Für historische Analysen — "Welche Python-Storys waren 2023 am wichtigsten?" oder "Wie hat sich die AI-Berichterstattung in den letzten 5 Jahren verändert?" — brauchst du die 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):
    """Durchsucht HN über die 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()

# Beispiel: Python-Scraping-Stories mit 10+ Punkten seit Januar 2024 finden
results = search_hn(
    query="python scraping",
    tags="story",
)
print(f"Insgesamt {results['nbHits']} Ergebnisse gefunden")

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

Für datumsbasierte Filter nutze numericFilters:

import calendar, datetime

# Stories seit dem 1. Januar 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"Seit 2024 mit >10 Punkten {data['nbHits']} Stories über Python Web Scraping gefunden")

Die Algolia API ist schnell (5–9 ms Server-Verarbeitungszeit), braucht keinen API-Key und unterstützt Pagination bis zu 500 Seiten. Für umfangreiche historische Analysen ist sie die beste verfügbare Option.

Gescrapete Hacker-News-Daten nach CSV, Excel und Google Sheets exportieren

Jedes HN-Scraping-Tutorial, das ich gesehen habe, endet mit pprint()-Ausgabe im Terminal. Zum Debuggen ist das okay, aber wenn du einen täglichen Digest baust oder Trends analysierst, brauchst du die Daten in einer Datei. So bekommst du sie dorthin.

Export nach CSV mit Python

import csv

def export_to_csv(stories, filename="hn_stories.csv"):
    """Gescrapte Stories in eine CSV-Datei schreiben."""
    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"{len(stories)} Stories in {filename} gespeichert")

export_to_csv(stories)

Export nach Excel mit Python

import pandas as pd

def export_to_excel(stories, filename="hn_stories.xlsx"):
    """Gescrapte Stories in eine Excel-Datei schreiben."""
    df = pd.DataFrame(stories)
    df.to_excel(filename, index=False, engine="openpyxl")
    print(f"{len(stories)} Stories in {filename} gespeichert")

export_to_excel(stories)

Stelle sicher, dass openpyxl installiert ist — pandas nutzt es als Excel-Engine. Fehlt es, bekommst du einen ImportError.

Optional: In Google Sheets übertragen

Für automatisierte Workflows möchtest du die Daten vielleicht direkt mit der gspread-Bibliothek in Google Sheets schreiben. Dafür musst du einmalig einen Google-Cloud-Service-Account einrichten:

import gspread

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

# Stories in Zeilen umwandeln
header = list(stories[0].keys())
rows = [list(s.values()) for s in stories]

worksheet.clear()
worksheet.update([header] + rows)
print("In Google Sheets übertragen")

Die No-Code-Export-Alternative

Wenn das Einrichten von Service Accounts und Export-Code mehr Aufwand klingt als das eigentliche Scraping, kann ich das gut nachvollziehen. Bei Thunderbit haben wir einen kostenlosen Datenexport entwickelt, mit dem du gescrapte Daten direkt nach Excel, Google Sheets, Airtable oder Notion schicken kannst — ohne Code, ohne Zugangsdaten, ohne Wartungsaufwand. Für einen einmaligen Datenabruf ist das tatsächlich schneller. Mehr dazu weiter unten.

Deinen Scraper produktionsreif machen: Fehlerbehandlung, Caching und Scheduling

Wenn du ein Skript nur einmal zum Spaß laufen lässt, reicht der Code oben völlig aus. Wenn es aber täglich Teil eines Workflows sein soll, brauchst du noch ein paar Bausteine.

Fehlerbehandlung und Retry-Logik

Netzwerke fallen aus. Server drosseln Anfragen. Eine einzelne fehlerhafte Anfrage sollte nicht deinen gesamten Scrape zu Fall bringen. Hier ist eine Retry-Funktion mit exponentiellem Backoff:

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):
    """Lädt eine URL mit automatischen Retries und exponentiellem Backoff."""
    response = requests.get(url, timeout=10)
    response.raise_for_status()
    return response

# Verwendung:
try:
    resp = fetch_with_retry("https://hacker-news.firebaseio.com/v0/topstories.json")
    story_ids = resp.json()
except Exception as e:
    print(f"Nach Retries fehlgeschlagen: {e}")

Die Bibliothek tenacity übernimmt die Retry-Logik sauber. Sie versucht es bis zu 5-mal mit zufälligem exponentiellem Backoff — beginnend bei 1 Sekunde, maximal 60 Sekunden. Das hilft bei HTTP 429 (Rate Limit), 503 (Service nicht verfügbar) und vorübergehenden Netzwerkfehlern.

Antworten cachen, um erneutes Crawlen zu vermeiden

In der Entwicklung führst du dein Skript oft mehrfach aus, während du die Parsing-Logik anpasst. Ohne Caching wird bei jedem Lauf HN erneut für dieselben Daten angefragt. Die Bibliothek requests-cache löst das in zwei Zeilen:

import requests_cache

requests_cache.install_cache("hn_cache", expire_after=3600)  # 1 Stunde Cache

Nach diesen Zeilen am Anfang deines Skripts werden alle requests.get()-Aufrufe automatisch in einer lokalen SQLite-Datenbank gecacht. Wenn du dein Skript innerhalb einer Stunde zehnmal startest, trifft nur der erste Lauf tatsächlich das Netzwerk. Das ist ein Tool, das Forum-Nutzer häufig empfehlen — und das aus gutem Grund.

Crawling und Parsing trennen

Ein Muster, auf das erfahrene Scraper schwören: zuerst die Rohdaten herunterladen, danach parsen. So kannst du, falls die Parsing-Logik einen Fehler hat, nur den Parser korrigieren und die Daten erneut verarbeiten, ohne alles neu abzurufen.

import os, json

def crawl_and_save(story_ids, output_dir="raw_data"):
    """Story-Daten abrufen und als rohes JSON auf der Festplatte speichern."""
    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  # Bereits abgerufene Items überspringen
        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"):
    """Gespeicherte JSON-Dateien in eine strukturierte Story-Liste umwandeln."""
    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

Dieser Zweiphasen-Ansatz ist besonders wertvoll, wenn du Hunderte Items scrapen und die Verarbeitung schnell iterieren möchtest.

Deinen Scraper nach Zeitplan automatisieren

Für einen täglichen HN-Digest soll dein Scraper automatisch laufen. Zwei gängige Optionen:

Option 1: cron (Linux/Mac)

# Jeden Tag um 8:30 Uhr UTC ausführen
30 8 * * * /usr/bin/python3 /home/user/scrape_hn.py >> /home/user/scrape.log 2>&1

Option 2: GitHub Actions (kostenlos, kein Server nötig)

name: Scrape Hacker News

on:
  schedule:
    - cron: '30 8 * * *'  # Täglich um 8:30 Uhr UTC
  workflow_dispatch:        # Manueller Start-Button

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

Ein paar Stolpersteine bei GitHub-Actions-Schedules: Alle Cron-Zeiten sind in UTC, Verzögerungen von 15–60 Minuten sind normal (nutze also Zeiten wie :30 statt :00), und GitHub kann geplante Workflows in Repos ohne Aktivität für 60 Tage deaktivieren. Füge immer workflow_dispatch hinzu, damit du für Tests manuell starten kannst.

Für eine einfachere Lösung lässt sich mit Thunderbits Scheduled Scraper ein Zeitplan in normaler Sprache beschreiben — etwa "jeden Morgen um 8 Uhr scrapen" — ganz ohne Server oder Cron-Setup.

Wenn Python überdimensioniert ist: Der No-Code-Weg für Hacker News

Ich bin hier ehrlich, auch wenn ich Python mag und mein Team Entwickler-Tools baut. Wenn du nur die heutigen Top 100 HN-Storys einmalig und sofort in einer Tabelle brauchst, ist ein Python-Skript oft unnötiger Aufwand. Schon das Setup — virtuelle Umgebung, Pakete installieren, Selektoren herausfinden — dauert länger als das eigentliche Sammeln der Daten.

Hier kommt Thunderbit ins Spiel. So funktioniert der Ablauf:

  1. Öffne news.ycombinator.com in Chrome
  2. Klicke auf das Thunderbit-Icon und dann auf "AI Suggest Fields"
  3. Die KI liest die Seite und schlägt Spalten vor: Title, URL, Score, Author, Comment Count, Time Posted
  4. Passe die Felder bei Bedarf an (umbenennen, entfernen oder eigene hinzufügen — du kannst sogar einen KI-Prompt ergänzen wie "Als AI/DevTools/Web/Other kategorisieren")
  5. Klicke auf "Scrape" — die Daten erscheinen als strukturierte Tabelle
  6. Exportiere nach Excel, Google Sheets, Airtable oder Notion

Zwei Klicks bis zu strukturierten Daten. Keine Selektoren, kein Code, keine Wartung.

Ein echter Vorteil: Thunderbits KI passt sich automatisch an Layout-Änderungen an. Klassische Scraper mit CSS-Selektoren brechen, wenn sich das Markup einer Seite ändert — und obwohl HNs HTML recht stabil ist, hat es sich bereits geändert (class="athing submission" wurde angepasst, span.titleline ersetzte das ältere a.storylink). Ein KI-gestützter Scraper liest die Seite jedes Mal neu und ist daher unempfindlich gegenüber geänderten Klassennamen.

python-vs-thunderbit-comparison.webp

Thunderbit übernimmt außerdem Pagination (klickt den "More"-Button auf HN automatisch) und das Scrapen von Unterseiten (öffnet die Kommentarseite jeder Story, um Diskussionsdaten zu holen). Für den Anwendungsfall Kommentar-Anreicherung entspricht das dem rekursiven API-Code aus Methode 2 — nur eben ohne eine einzige Zeile zu schreiben.

Die Abwägung ist simpel: Python ist die richtige Wahl, wenn du eigene Logik, komplexe Transformationen, automatisierte Pipeline-Prozesse oder Lernziele hast. Thunderbit ist die richtige Wahl, wenn du schnell Daten brauchst, keinen Code warten willst oder kein Entwickler bist. Nimm das Werkzeug, das zu deiner Situation passt.

Python vs. API vs. No-Code: Welche Methode solltest du wählen?

Hier ist die komplette Entscheidungsübersicht:

KriteriumBeautifulSoup (HTML)Firebase APIAlgolia APIThunderbit (No-Code)
Benötigtes technisches WissenPython auf mittlerem NiveauPython für AnfängerPython für AnfängerKeines
Einrichtungszeit10–15 Min.5–10 Min.5–10 Min.2 Min.
WartungsaufwandMittel (Selektoren können brechen)Niedrig (stabiles JSON)Niedrig (stabiles JSON)Keiner
DatentiefeNur StartseiteJedes Item, NutzerSuche + HistorieStartseite + Unterseiten
KommentareSchwerEinfach (rekursiv)Einfach (verschachtelter Baum)Subpage-Scraping
Historische DatenNeinNeinJa (vollständiges Archiv)Nein
ExportoptionenSelbst programmierenSelbst programmierenSelbst programmierenIntegriert (Excel, Sheets usw.)
Schedulingcron / GitHub Actionscron / GitHub Actionscron / GitHub ActionsIntegrierter Scheduler
Am besten fürScraping lernenZuverlässige PipelinesRecherche & AnalyseSchnelle Datenzüge

Wenn du Python lernst oder etwas Eigenes baust, nimm Methode 1 oder 2. Wenn du historische Analysen brauchst, ergänze die Algolia API. Wenn du einfach nur die Daten ohne Code willst, probier Thunderbit aus.

Thunderbit für Hacker-News-Scraping testen

Fazit und wichtigste Erkenntnisse

Jetzt hast du in deinem Werkzeugkasten:

  • Zwei vollständige Python-Methoden zum Scrapen von Hacker News — BeautifulSoup für HTML-Parsing und die Firebase API für saubere JSON-Daten
  • Pagination-Techniken für mehr als Seite 1, inklusive der Algolia API für historische Daten bis zurück ins Jahr 2007
  • Export-Code für CSV, Excel und Google Sheets — denn Daten im Terminal helfen sonst niemandem im Team
  • Produktionsmuster — Retry-Logik, Caching, Trennung von Crawling und Parsing sowie geplante Automatisierung per cron oder GitHub Actions
  • Eine No-Code-Alternative für den Fall, dass Python mehr Werkzeug ist, als du gerade brauchst

Meine Empfehlung: Starte für die meisten Fälle mit der Firebase API (Methode 2). Sie ist sauberer, zuverlässiger und bietet Kommentarzugriff, ohne dass du verschachteltes HTML mühsam parsen musst. Ergänze die Algolia API, wenn du historische Daten brauchst. Und behalte Thunderbit als Lesezeichen, wenn du nur schnell eine Tabelle brauchst und kein komplettes Python-Projekt aufsetzen willst.

Wenn du tiefer einsteigen willst, versuche HN-Kommentare für Sentiment-Analyse zu scrapen, baue mit GitHub Actions eine tägliche Digest-Pipeline oder nutze die Algolia API, um zu verfolgen, wie sich Technologietrends im letzten Jahrzehnt verändert haben.

Thunderbit für schnelles Hacker-News-Scraping testen Get Started Free

FAQs

Ist es legal, Hacker News zu scrapen?

HN-Daten sind öffentlich zugänglich, und Y Combinator stellt sogar eine offizielle API für den programmgesteuerten Zugriff bereit. Die robots.txt der Seite erlaubt das Scrapen von lesbaren Inhalten (Startseite, Item-Seiten, Benutzerseiten), verlangt aber ein Crawl-Delay von 30 Sekunden. Wenn du diese Pause respektierst und keine interaktiven Endpunkte (Voting, Login) abfragst, bist du auf der sicheren Seite. Mehr zu den rechtlichen Aspekten findest du in unserem Leitfaden zu den rechtlichen Implikationen von Web Scraping.

Hat Hacker News eine offizielle API?

Ja. Die HN Firebase API unter hacker-news.firebaseio.com/v0/ ist kostenlos, erfordert keine Authentifizierung und bietet Zugriff auf Stories, Kommentare, Nutzerprofile und alle Feed-Typen (Top, New, Best, Ask, Show, Jobs). Sie liefert sauberes JSON und hat kein ausdrücklich genanntes Rate Limit, obwohl ein höflicher Umgang mit der Anfragedichte immer empfehlenswert ist.

Wie scrape ich Hacker-News-Kommentare mit Python?

Mit der Firebase API rufst du ein Story-Item ab und erhältst sein kids-Feld (ein Array der IDs der Top-Level-Kommentare). Jeder Kommentar ist wiederum ein Item mit eigenem kids-Feld für Antworten. Laufe den Baum rekursiv mit einer Funktion durch, die jeden Kommentar und seine Kinder abruft. Im Abschnitt "Kommentare scrapen (rekursiver Baumdurchlauf)" oben findest du den vollständigen Code. Alternativ liefert der Algolia-API-Endpunkt /items/<id> den gesamten verschachtelten Kommentarbaum in einer einzigen Anfrage — deutlich schneller bei kommentarstarken Stories.

Kann ich Hacker News auch ohne Code scrapen?

Ja. Thunderbits KI-Webscraper funktioniert als Chrome-Erweiterung — öffne HN, klicke auf "AI Suggest Fields", und das Tool erkennt automatisch Spalten wie Titel, URL, Score und Autor. Klicke auf "Scrape" und exportiere direkt nach Excel, Google Sheets, Airtable oder Notion. Es unterstützt Pagination und kann sogar Unterseiten besuchen, um Kommentardaten zu holen. Kein Python, keine Selektoren, keine Wartung.

Wie bekomme ich historische Hacker-News-Daten?

Die HN Algolia Search API ist dafür das beste Werkzeug. Verwende den Endpunkt search_by_date mit numericFilters=created_at_i>TIMESTAMP, um nach Zeitraum zu filtern. Du kannst nach Stichwort suchen, nach Story-Typ filtern und durch bis zu 500 Ergebnisseiten blättern. Für umfangreiche historische Analysen sind außerdem öffentliche Datensätze verfügbar auf Google BigQuery (vollständiges Archiv), ClickHouse (28 Millionen Datensätze) und Hugging Face (4 Millionen Stories).

Mehr erfahren

Shuai Guan
Shuai Guan
CEO bei Thunderbit | Experte für KI-gestützte Datenautomatisierung Shuai Guan ist CEO von Thunderbit und Absolvent der University of Michigan im Bereich Engineering. Mit fast zehn Jahren Erfahrung in Tech und SaaS-Architektur hat er sich darauf spezialisiert, komplexe KI-Modelle in praxisnahe No-Code-Tools zur Datenextraktion zu verwandeln. In diesem Blog teilt er ungefilterte, in der Praxis bewährte Einblicke in Web-Scraping- und Automatisierungsstrategien, damit Sie intelligentere, datengetriebene Workflows aufbauen können. Wenn er gerade keine Datenprozesse optimiert, widmet er dieselbe Liebe zum Detail seiner Leidenschaft für die Fotografie.
Inhaltsverzeichnis

Eine Webseite einfach per Anfrage scrapen

Sag einfach in normalem Deutsch, was du brauchst. Oder noch besser: sag gar nichts.

Thunderbit ausprobieren kostenlos
Daten mit KI extrahieren
Daten einfach zu Google Sheets, Airtable oder Notion übertragen
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week