For noen måneder siden ville jeg lage en daglig oversikt over de viktigste Hacker News-artiklene for teamet vårt i Thunderbit. Den første tanken min var bare å bokmerke siden og skrolle gjennom den hver morgen. Det holdt i omtrent tre dager, før jeg skjønte at jeg brukte 20 minutter om dagen på å lese overskrifter og kopiere lenker inn i et regneark.
Hacker News er en av de mest verdifulle og konsentrerte kildene til teknologiinformasjon på internett — rundt , cirka 1 300 nye innlegg hver dag og om lag 13 000 kommentarer daglig. Enten du følger nye teknologitrender, overvåker merkevaren din, bygger en rekrutteringspipeline fra «Who's Hiring»-tråder, eller bare prøver å holde deg oppdatert på hva utviklermiljøet bryr seg om, blir det en tapt kamp å følge med manuelt.
Den gode nyheten er at det er overraskende enkelt å scrape Hacker News med Python, og i denne guiden viser jeg deg to komplette metoder — HTML-scraping med BeautifulSoup og den offisielle HN Firebase API-en — sammen med paginering, dataeksport, produksjonsklare mønstre og en no-code-snarvei for når Python føles som overkill.
Hvorfor scrape Hacker News med Python?
Hacker News er ikke bare enda en lenkeaggregator. Det er en kuratert, fellesskapsdrevet feed der de mest interessante teknologihistoriene løftes fram gjennom oppstemmer og aktiv diskusjon. Publikum består i stor grad av teknologifolk (omtrent ), og nettstedets 66 % direkte trafikk viser at dette er en lojal, vaneorientert leserskare — ikke tilfeldige besøkende.
Her er noen grunner til at folk scraper HN-data:
| Bruksområde | Hva du får |
|---|---|
| Daglige teknologinyheter | Toppartikler, poeng og lenker sendt til innboksen eller Slack |
| Overvåking av merkevare/konkurrenter | Varsler når firmaet eller produktet ditt blir nevnt |
| Trendanalyse | Følg hvilke teknologier, språk eller temaer som får mer oppmerksomhet over tid |
| Rekruttering | Plukk ut stillingsannonser, tech stack og lønnssignaler fra «Who's Hiring»-tråder |
| Innholdsresearch | Finn temaer som gjør det bra og skriv eller del innhold rundt dem |
| Sentimentanalyse | Mål hva fellesskapet mener om produkter, lanseringer eller endringer i bransjen |
Selskaper med en samlet verdi på over 400 milliarder dollar — Stripe, Dropbox, Airbnb — tilskriver Hacker News viktig tidlig tilbakemelding og brukere. Drew Houston la ut Dropbox-demoen på HN i april 2007, den nådde #1, og betaversjonslisten eksploderte fra 5 000 til 75 000 brukere på én dag. HN-data er ikke bare interessante — de har også kommersiell verdi.
Dataene er offentlig tilgjengelige, men strukturen på nettstedet gjør manuell innsamling tungvint. Automatisering med Python er den praktiske løsningen.
To måter å scrape Hacker News med Python: oversikt
Denne guiden dekker to komplette, kjørbare tilnærminger:
- HTML-scraping med
requests+ BeautifulSoup — henter rå HTML fra news.ycombinator.com og parser den for å trekke ut historiedata. Flott for å lære grunnleggende scraping og hente akkurat det som ligger på siden. - Den offisielle Hacker News Firebase API-en — leser JSON-endepunkter direkte, uten behov for HTML-parsing. Bedre for pålitelige datapipelines, kommentarer og historiske data.
Her er en side-ved-side-sammenligning som hjelper deg å velge det som passer best:
| Kriterium | HTML-scraping (requests + BS4) | HN Firebase API | Thunderbit (no-code) |
|---|---|---|---|
| Oppsettkompleksitet | Middels (HTML-selektorer må parses) | Lav (JSON-endepunkter) | Ingen (2-klikk Chrome-utvidelse) |
| Datanyhet | Sanntid på forsiden | Sanntid (valgfri item etter ID) | Sanntid |
| Risiko for rate limit | Middels (robots.txt sier 30 s crawl-delay) | Lav (offisiell, generøs) | Håndteres av Thunderbit |
| Tilgang til kommentarer | Vanskelig (nestet HTML) | Enkelt (rekursiv gjennomgang av item-ID-er) | Scraping av undersider |
| Historiske data | Begrenset | Via Algolia Search API | Ikke relevant |
| Best for | Lære scraping-grunnprinsipper | Pålitelige datapipelines | Ikke-utviklere, raske eksportjobber |
Begge metodene inkluderer full, kjørbar Python-kode. Og hvis du bare vil ha dataene uten å skrive noe kode i det hele tatt, går jeg også gjennom det.
Før du starter
- Vanskelighetsgrad: Nybegynner til middels
- Tidsbruk: Ca. 15–20 minutter per metode
- Dette trenger du:
- Python 3.11+ installert
- En terminal eller kodeeditor
- Chrome-nettleser (hvis du vil inspisere HN sin HTML eller teste no-code-alternativet)
- (valgfritt, for no-code-metoden)

Slik setter du opp Python-miljøet
Før vi går løs på HN-dataene, la oss rydde opp i miljøet først. Jeg anbefaler å opprette et virtuelt miljø, så prosjektavhengighetene holder seg ryddige.
1# Opprett og aktiver et virtuelt miljø
2python3 -m venv hn-scraper
3# macOS/Linux:
4source hn-scraper/bin/activate
5# Windows:
6hn-scraper\Scripts\activate
7# Installer pakkene vi trenger for begge metodene
8pip install requests==2.33.1 beautifulsoup4==4.14.3 pandas==3.0.2 openpyxl==3.1.5
For produksjonsmønstre senere (cache og retry) trenger du også:
1pip install requests-cache==1.3.1 tenacity==9.1.4
Ingen spesielle API-nøkler, ingen autentiseringstokener. HN-dataene er åpne.
Metode 1: Scrape Hacker News med Python ved hjelp av BeautifulSoup
Dette er den klassiske tilnærmingen — hent HTML-en, parser den og plukk ut dataene du trenger. Det er slik de fleste lærer web scraping, og HNs enkle tabellbaserte layout gjør siden til et godt øvingsfelt.
Steg 1: Hent forsiden til Hacker News
Åpne editoren din og opprett en fil som heter scrape_hn_bs4.py. Her er startkoden:
1import requests
2from bs4 import BeautifulSoup
3> This paragraph contains content that cannot be parsed and has been skipped.
4print(f"Status: {response.status_code}, Sidestørrelse: {len(response.text)} tegn")
Kjør den. Du bør se Status: 200 og en sidelengde på rundt 40 000–50 000 tegn. Det er den rå HTML-en fra HNs forside, klar til å parses.
Steg 2: Forstå HTML-strukturen
HN bruker en tabellbasert layout — ingen moderne CSS grid eller flexbox. Hver historie på siden består av to viktige <tr>-rader:
- Historieraden (
<tr class="athing submission">): inneholder plassering, tittel og lenke - Metadata-raden (den neste
<tr>): inneholder poeng, forfatter, tidspunkt og antall kommentarer
De viktigste selektorene:
span.titleline > a— tittelen og URL-en til historienspan.score— stemmeantallet (for eksempel «118 points»)a.hnuser— brukernavnet til forfatterenspan.age— når innlegget ble publisert- Den siste
<a>i.subtextmed ordet «comment» i teksten — antall kommentarer
Hvis du høyreklikker på en hvilken som helst historietittel i Chrome og velger «Inspect», ser du noe slikt:
1<span class="titleline">
2 <a href="https://darkbloom.dev">Darkbloom – Private inference on idle Macs</a>
3</span>
Og metadata-raden under:
1<span class="score" id="score_47788542">118 points</span>
2by <a href="user?id=twapi" class="hnuser">twapi</a>
3<span class="age" title="2026-04-16T04:06:39 1776312399">
4 <a href="item?id=47788542">2 hours ago</a>
5</span>
6| <a href="item?id=47788542">65 comments</a>
Det er avgjørende å forstå disse selektorene — hvis HN noen gang endrer markupen sin, må du oppdatere dem. (Spoiler: API-metoden slipper dette problemet helt.)
Steg 3: Trekk ut titler, lenker og poeng
Nå kommer selve jobben. Vi går gjennom hver historiesrad, henter tittel og lenke fra historieraden, og plukker deretter poeng fra metadata-raden rett under.
1import requests
2from bs4 import BeautifulSoup
3from pprint import pprint
4> This paragraph contains content that cannot be parsed and has been skipped.
5stories = []
6story_rows = soup.select("tr.athing")
7for row in story_rows:
8 # Tittel og URL fra historieraden
9 title_tag = row.select_one("span.titleline > a")
10 if not title_tag:
11 continue
12 title = title_tag.get_text()
13 link = title_tag.get("href", "")
14 # Metadata fra neste rad
15 meta_row = row.find_next_sibling("tr")
16 score = 0
17 author = ""
18 comments = 0
19> This paragraph contains content that cannot be parsed and has been skipped.
20> This paragraph contains content that cannot be parsed and has been skipped.
21# Filtrer til historier med 50+ poeng, sortert etter score
22top_stories = sorted(
23 [s for s in stories if s["score"] >= 50],
24 key=lambda x: x["score"],
25 reverse=True,
26)
27pprint(top_stories[:10])
Noen korte kommentarer til koden:
- Walrus-operatoren (
:=) fungerer i Python 3.8+. Den lar oss tildele og sjekke samtidig — praktisk for valgfrie elementer somspan.score, som ikke finnes på alle rader (for eksempel har jobbinnlegg ingen score). - HN bruker
\xa0(ikke-brytende mellomrom) mellom tallet og ordet «comments», så vi splitter på det. - Historier som lenker til andre HN-sider (som «Ask HN»-innlegg) har relative URL-er som starter med
item?id=. Du vil kanskje legge tilhttps://news.ycombinator.com/foran disse.
Steg 4: Kjør og se resultatet
Lagre og kjør:
1python scrape_hn_bs4.py
Du bør se et resultat som dette:
1[{'author': 'twapi',
2 'comments': 65,
3 'score': 118,
4 'title': 'Darkbloom – Private inference on idle Macs',
5 'url': 'https://darkbloom.dev'},
6 {'author': 'sebg',
7 'comments': 203,
8 'score': 247,
9 'title': 'Show HN: I built an open-source Perplexity alternative',
10 'url': 'https://github.com/...'},
11 ...]
Det er 30 historier fra side 1. Men HN har hundrevis av aktive historier til enhver tid. Vi kommer tilbake til paginering i en senere del.
Metode 2: Scrape Hacker News med Python ved hjelp av den offisielle API-en
HN Firebase API er den offisielle og godkjente måten å hente data fra Hacker News på. Ingen autentisering, ingen API-nøkler, ingen HTML-parsing. Du får rene JSON-svar. Jeg bruker denne metoden for alt som må kjøre stabilt i produksjon.
Viktige API-endepunkter du bør kjenne til
Base-URL-en er https://hacker-news.firebaseio.com/v0/. Her er endepunktene som betyr noe:
This paragraph contains content that cannot be parsed and has been skipped.
Et story-item ser slik ut:
1{
2 "by": "twapi",
3 "descendants": 65,
4 "id": 47788542,
5 "kids": [47789171, 47788769, 47788762],
6 "score": 118,
7 "time": 1776312399,
8 "title": "Darkbloom – Private inference on idle Macs",
9 "type": "story",
10 "url": "https://darkbloom.dev"
11}
Feltet kids inneholder ID-ene til de direkte underkommentarene. Hver kommentar er selv et item som kan ha egne kids — slik er kommentar-treet bygget opp.
Steg 1: Hent ID-er for topphistorier
Opprett en fil som heter scrape_hn_api.py:
1import requests
2import time
3from pprint import pprint
4API_BASE = "https://hacker-news.firebaseio.com/v0"
5# Hent ID-er for topphistorier
6response = requests.get(f"{API_BASE}/topstories.json")
7story_ids = response.json()
8print(f"Fant {len(story_ids)} ID-er for topphistorier")
9# Output: Fant 500 ID-er for topphistorier
500 historie-ID-er i én forespørsel — ingen parsing, ingen selektorer, bare et JSON-array.
Steg 2: Hent historiedetaljer per ID
Nå trenger vi selve historiedataene. Her dukker fan-out-problemet opp: 500 historier betyr 500 separate API-kall. I min måling tar hvert item-kall omtrent 1,2 sekunder sekvensielt. For 500 historier blir det rundt 10 minutter.
For de fleste bruksområder trenger du ikke alle 500. Her er kode for å hente de 30 øverste:
1def fetch_story(story_id):
2 """Hent detaljene for én historie fra HN API."""
3 resp = requests.get(f"{API_BASE}/item/{story_id}.json")
4 return resp.json()
5> This paragraph contains content that cannot be parsed and has been skipped.
6# Sorter etter score, vis topp 10
7top = sorted(stories, key=lambda x: x["score"], reverse=True)[:10]
8pprint(top)
time.sleep(0.1) legger inn en liten høflig pause. Firebase API-et har ikke en oppgitt rate limit, men det er dårlig praksis å hamre løs på et API uten pauser.
Steg 3: Scrape kommentarer (rekursiv tre-gjennomgang)
Det er her API-et virkelig skinner sammenlignet med HTML-scraping. Kommentarer på HN er dypt nestet — svar på svar på svar. I HTML betyr det at du må parse kompliserte, nestede tabellstrukturer. Med API-et får hver kommentar et kids-felt med ID-ene til barna sine, og du kan bare gå gjennom treet rekursivt.
1def fetch_comments(item_id, depth=0, max_depth=3):
2 """Hent kommentarer rekursivt opp til max_depth."""
3 item = requests.get(f"{API_BASE}/item/{item_id}.json").json()
4 if not item or item.get("type") != "comment":
5 return []
6> This paragraph contains content that cannot be parsed and has been skipped.
7 if depth < max_depth and item.get("kids"):
8 for kid_id in item["kids"]:
9 comments.extend(fetch_comments(kid_id, depth + 1, max_depth))
10 time.sleep(0.05)
11 return comments
12# Eksempel: hent kommentarer til topphistorien
13if stories:
14 top_story = stories[0]
15 top_story_full = requests.get(f"{API_BASE}/item/{top_story['id']}.json").json()
16 if top_story_full.get("kids"):
17 print(f"\nKommentarer for: {top_story['title']}")
18 all_comments = []
19 for kid_id in top_story_full["kids"][:5]: # Første 5 toppnivåkommentarer
20 all_comments.extend(fetch_comments(kid_id, depth=0, max_depth=2))
21 time.sleep(0.1)
22 for c in all_comments[:15]:
23 indent = " " * c["depth"]
24 preview = c["text"][:80].replace("\n", " ") if c["text"] else "[ingen tekst]"
25 print(f"{indent}[{c['author']}] {preview}...")
Denne rekursive tilnærmingen er betydelig enklere enn å prøve å parse nestede HTML-kommentartråder. Hvis du trenger komplette kommentartre, er API-et veien å gå.
Steg 4: Kjør og se resultatet
1python scrape_hn_api.py
Du vil se strukturert historiedata etterfulgt av et nestet kommentarglimt. Dataene er renere, kommentarene er enkle å hente, og du slipper risikoen for at scraperen din ryker fordi HN endret et CSS-klassenavn.
Gå videre enn side 1: paginering og historiske data
De fleste HN-scraping-guider stopper ved side 1 — 30 historier. Det er greit for en rask demo, men reelle bruksområder trenger ofte mer dybde.
Scrape flere sider med BeautifulSoup
HN bruker et enkelt URL-mønster for paginering: ?p=2, ?p=3, osv. Hver side returnerer 30 historier, og nettstedet serverer opptil omtrent side 20 (rundt 600 historier totalt). Etter det får du tomme sider.
1import time
2def scrape_hn_pages(num_pages=5):
3 """Scrape flere sider med historier fra HN-forsiden."""
4 all_stories = []
5 for page in range(1, num_pages + 1):
6 url = f"https://news.ycombinator.com/news?p={page}"
7 response = requests.get(url, headers=headers)
8 soup = BeautifulSoup(response.text, "html.parser")
9 story_rows = soup.select("tr.athing")
10 if not story_rows:
11 print(f"Side {page}: fant ingen historier, stopper.")
12 break
13 for row in story_rows:
14 title_tag = row.select_one("span.titleline > a")
15 if not title_tag:
16 continue
17 meta_row = row.find_next_sibling("tr")
18 score = 0
19 if meta_row and (score_tag := meta_row.select_one("span.score")):
20 score = int(score_tag.get_text().replace(" points", ""))
21> This paragraph contains content that cannot be parsed and has been skipped.
22 print(f"Side {page}: hentet {len(story_rows)} historier")
23 # Respekter robots.txt sitt crawl-delay på 30 sekunder
24 if page < num_pages:
25 time.sleep(30)
26 return all_stories
27stories = scrape_hn_pages(5)
28print(f"\nTotalt antall historier hentet: {len(stories)}")
time.sleep(30) er viktig. HNs ber uttrykkelig om 30 sekunders crawl-delay. Ignorerer du det, kan du bli rate-limited (HTTP 429) eller midlertidig blokkert. Fem sider med 30 sekunders intervaller tar omtrent 2,5 minutter — ikke øyeblikkelig, men respektfullt.
For brukere som ikke vil håndtere pagineringskode selv, tar seg av klikkbasert paginering og infinite scroll automatisk. Den klikker «More»-knappen nederst på HN-sidene uten at du trenger å konfigurere noe.
Hent historiske Hacker News-data med Algolia API
Firebase API-et gir deg nåværende data. For historisk analyse — «Hva var de viktigste Python-artiklene i 2023?» eller «Hvordan har AI-dekningen endret seg de siste 5 årene?» — trenger du .
1import requests
2ALGOLIA_BASE = "https://hn.algolia.com/api/v1"
3> This paragraph contains content that cannot be parsed and has been skipped.
4# Eksempel: finn Python-scraping-historier med 10+ poeng siden januar 2024
5results = search_hn(
6 query="python scraping",
7 tags="story",
8)
9print(f"Fant {results['nbHits']} treff totalt")
10for hit in results["hits"][:5]:
11 print(f" [{hit.get('points', 0)} poeng] {hit['title']}")
For datofiltrerte søk bruker du numericFilters:
1import calendar, datetime
2# Historier siden 1. januar 2024
3start_date = datetime.datetime(2024, 1, 1)
4start_ts = int(calendar.timegm(start_date.timetuple()))
5> This paragraph contains content that cannot be parsed and has been skipped.
6Algolia API-et er raskt (5–9 ms serverbehandlingstid), krever ingen API-nøkkel og støtter paginering opptil 500 sider. For stor historisk analyse er det det beste alternativet.
7## Eksport av scraped Hacker News-data til CSV, Excel og Google Sheets
8Hver HN-scraping-guide jeg har sett, ender med `pprint()` i terminalen. Det er greit for feilsøking, men hvis du bygger en daglig oversikt eller gjør trendanalyse, trenger du dataene i en fil. Her er hvordan du får det til.
9### Eksporter til CSV med Python
10```python
11import csv
12def export_to_csv(stories, filename="hn_stories.csv"):
13 """Lagre scrape-de historier til en CSV-fil."""
14 fieldnames = ["title", "url", "score", "author", "comments"]
15 with open(filename, "w", newline="", encoding="utf-8") as f:
16 writer = csv.DictWriter(f, fieldnames=fieldnames)
17 writer.writeheader()
18 writer.writerows(stories)
19 print(f"Laget {len(stories)} historier i {filename}")
20export_to_csv(stories)
Eksporter til Excel med Python
1import pandas as pd
2def export_to_excel(stories, filename="hn_stories.xlsx"):
3 """Lagre scrape-de historier til en Excel-fil."""
4 df = pd.DataFrame(stories)
5 df.to_excel(filename, index=False, engine="openpyxl")
6 print(f"Laget {len(stories)} historier i {filename}")
7export_to_excel(stories)
Sørg for at openpyxl er installert — pandas bruker den som Excel-motor. Hvis den mangler, får du en ImportError.
Send til Google Sheets (valgfritt)
For automatiserte arbeidsflyter kan det være nyttig å sende data direkte til Google Sheets med gspread-biblioteket. Dette krever oppsett av en Google Cloud service account (en engangsprosess):
1import gspread
2gc = gspread.service_account(filename="service_account.json")
3sh = gc.open("HN Daily Digest")
4worksheet = sh.sheet1
5# Gjør stories om til rader
6header = list(stories[0].keys())
7rows = [list(s.values()) for s in stories]
8worksheet.clear()
9worksheet.update([header] + rows)
10print("Sendt til Google Sheets")
No-code-alternativet for eksport
Hvis oppsett av service accounts og eksportkode føles som mer jobb enn selve scrapingen, skjønner jeg det. Hos Thunderbit bygde vi gratis dataeksport som lar deg sende data rett til Excel, Google Sheets, Airtable eller Notion — uten kode, uten credentials og uten en pipeline du må vedlikeholde. For en enkelt datauthenting er det faktisk raskere. Mer om det under.
Gjør scraperen produksjonsklar: feilhåndtering, caching og planlegging
Hvis du bare kjører en scraper én gang for moro skyld, er koden over helt fin. Hvis du kjører den daglig som del av en arbeidsflyt, trenger du et par ting til.
Feilhåndtering og retry-logikk
Nettverk feiler. Servere struper trafikk. Én dårlig forespørsel bør ikke velte hele scrapingen. Her er en retry-funksjon med eksponentiell backoff:
1from tenacity import retry, stop_after_attempt, wait_exponential_jitter
2import requests
3@retry(stop=stop_after_attempt(5), wait=wait_exponential_jitter(initial=1, max=60))
4def fetch_with_retry(url):
5 """Hent en URL med automatisk retry og eksponentiell backoff."""
6 response = requests.get(url, timeout=10)
7 response.raise_for_status()
8 return response
9# Bruk:
10try:
11 resp = fetch_with_retry("https://hacker-news.firebaseio.com/v0/topstories.json")
12 story_ids = resp.json()
13except Exception as e:
14 print(f"Feilet etter retries: {e}")
Biblioteket tenacity håndterer retry-logikken ryddig. Det prøver opptil 5 ganger med jitter-basert eksponentiell backoff — starter på 1 sekund og går opp til maks 60 sekunder. Dette håndterer HTTP 429 (rate limit), 503 (tjenesten er utilgjengelig) og midlertidige nettverksfeil på en god måte.
Cache svar for å slippe å crawl på nytt
Under utvikling kjører du scraperen mange ganger mens du justerer parserlogikken. Uten cache treffer hver kjøring HN-serverne på nytt for de samme dataene. Biblioteket requests-cache fikser dette med to linjer:
1import requests_cache
2requests_cache.install_cache("hn_cache", expire_after=3600) # Cache i 1 time
Etter at du har lagt disse linjene øverst i skriptet, blir alle requests.get()-kall automatisk cached i en lokal SQLite-database. Kjør skriptet 10 ganger i løpet av en time, og bare første kjøring går faktisk ut på nett. Dette er et verktøy , og med god grunn.
Skill crawling fra parsing
Et mønster erfarne scrapers sverger til: last ned rådata først, parse dem etterpå. Da kan du fikse parserfeil og parse på nytt uten å hente dataene igjen.
1import os, json
2def crawl_and_save(story_ids, output_dir="raw_data"):
3 """Hent historiedata og lagre rå JSON på disk."""
4 os.makedirs(output_dir, exist_ok=True)
5 for sid in story_ids:
6 filepath = os.path.join(output_dir, f"{sid}.json")
7 if os.path.exists(filepath):
8 continue # Hopp over elementer som allerede er hentet
9 resp = fetch_with_retry(f"{API_BASE}/item/{sid}.json")
10 with open(filepath, "w") as f:
11 json.dump(resp.json(), f)
12> This paragraph contains content that cannot be parsed and has been skipped.
13Denne totrinnsmodellen er spesielt nyttig når du scraper hundrevis av elementer og vil iterere raskt på hvordan du behandler dataene.
14### Automatiser scraperen på en tidsplan
15For en daglig HN-oversikt må scraperen kjøre automatisk. To vanlige alternativer:
16**Alternativ 1: cron (Linux/Mac)**
17```bash
18# Kjør hver dag kl. 08:30 UTC
1930 8 * * * /usr/bin/python3 /home/user/scrape_hn.py >> /home/user/scrape.log 2>&1
Alternativ 2: GitHub Actions (gratis, ingen server nødvendig)
1name: Scrape Hacker News
2on:
3 schedule:
4 - cron: '30 8 * * *' # Daglig kl. 08:30 UTC
5 workflow_dispatch: # Manuell startknapp
6jobs:
7 scrape:
8 runs-on: ubuntu-latest
9 steps:
10 - uses: actions/checkout@v4
11 - uses: actions/setup-python@v6
12 with:
13 python-version: '3.12'
14 - run: pip install requests beautifulsoup4 pandas openpyxl
15 - run: python scrape_hn.py
16 - run: |
17 git config user.name "GitHub Actions Bot"
18 git config user.email "actions@github.com"
19 git add -A
20 git diff --staged --quiet || git commit -m "Oppdater HN-data $(date -u +%Y-%m-%dT%H:%M:%SZ)"
21 git push
Noen fallgruver med planlegging i GitHub Actions: all cron-timing er i UTC, forsinkelser på 15–60 minutter er vanlige (bruk tider som :30 i stedet for :00), og GitHub kan deaktivere planlagte workflows i repos uten aktivitet i 60 dager. Inkluder alltid workflow_dispatch slik at du kan trigge manuelt under testing.
For et enklere alternativ kan Thunderbits Scheduled Scraper-funksjon la deg beskrive planen i vanlig språk — noe som «scrape hver morgen kl. 8» — uten server eller cron-oppsett.
Når Python er overkill: no-code-måten å scrape Hacker News på
Jeg skal være ærlig her, selv om jeg er Python-entusiast og teamet mitt bygger utviklerverktøy. Hvis du bare trenger dagens topp 100 HN-historier i et regneark — akkurat nå, én gang — er det unødvendig mye arbeid å skrive, feilsøke og kjøre et Python-skript. Bare oppsettet (virtuelt miljø, installasjon av pakker, finne selektorer) tar lenger tid enn selve datainnhentingen.
Det er her passer inn. Slik ser arbeidsflyten ut:
- Åpne
news.ycombinator.comi Chrome - Klikk på Thunderbit-utvidelsen, deretter «AI Suggest Fields»
- AI-en leser siden og foreslår kolonner: Title, URL, Score, Author, Comment Count, Time Posted
- Juster feltene om du vil (gi dem nytt navn, fjern noen eller legg til egne — du kan til og med legge inn en AI-prompt som «Kategoriser som AI/DevTools/Web/Other»)
- Klikk «Scrape» — dataene vises i en strukturert tabell
- Eksporter til Excel, Google Sheets, Airtable eller Notion
To klikk til strukturerte data. Ingen selektorer, ingen kode, ingen vedlikehold.
En reell fordel her er at Thunderbits AI tilpasser seg layoutendringer automatisk. Tradisjonelle scrapers som bruker CSS-selektorer ryker når et nettsted endrer markup — og selv om HNs HTML er ganske stabil, har den endret seg (klassen class="athing submission" ble oppdatert, og span.titleline erstattet den eldre a.storylink). En AI-drevet scraper leser siden på nytt hver gang, så den bryr seg ikke om klasseendringer.

Thunderbit håndterer også paginering (ved å klikke HNs «More»-knapp automatisk) og scraping av undersider (ved å besøke kommentarsiden til hver historie og hente inn diskusjonsdata). For brukstilfellet tilsvarer det den rekursive API-koden i Metode 2 — bare uten én eneste linje å skrive.
Avveiningene er ganske enkle: Python er riktig valg når du trenger egendefinert logikk, komplekse datatransformasjoner, planlagte automasjonsflyter eller vil lære å kode. Thunderbit er riktig valg når du trenger data raskt, ikke vil vedlikeholde kode, eller ikke er utvikler. Velg verktøyet som passer situasjonen din.
Python vs. API vs. no-code: hvilken metode bør du velge?
Her er hele beslutningsrammeverket:
| Kriterium | BeautifulSoup (HTML) | Firebase API | Algolia API | Thunderbit (no-code) |
|---|---|---|---|---|
| Teknisk nivå som kreves | Middels Python | Nybegynner-Python | Nybegynner-Python | Ingen |
| Oppsettstid | 10–15 min | 5–10 min | 5–10 min | 2 min |
| Vedlikeholdsbyrde | Middels (selektorer kan ryke) | Lav (stabil JSON) | Lav (stabil JSON) | Ingen |
| Dybde i data | Bare forsiden | Hvilket som helst item, brukere | Søk + historikk | Forside + undersider |
| Kommentarer | Vanskelig | Enkelt (rekursivt) | Enkelt (nestet tre) | Scraping av undersider |
| Historiske data | Nei | Nei | Ja (fullt arkiv) | Nei |
| Eksportalternativer | Du koder det selv | Du koder det selv | Du koder det selv | Innebygd (Excel, Sheets osv.) |
| Planlegging | cron / GitHub Actions | cron / GitHub Actions | cron / GitHub Actions | Innebygd scheduler |
| Best for | Lære scraping | Pålitelige pipelines | Forskning og analyse | Raske datauthentinger |
Hvis du lærer Python eller bygger noe skreddersydd, velg Metode 1 eller 2. Hvis du trenger historisk analyse, legg til Algolia API-et. Hvis du bare vil ha dataene uten koden, .
Konklusjon og viktigste læringspunkter
Dette har du nå i verktøykassen:
- To komplette Python-metoder for å scrape Hacker News — BeautifulSoup for HTML-parsing og Firebase API for rene JSON-data
- Teknikker for paginering slik at du kan scrape mer enn side 1, inkludert Algolia API for historiske data tilbake til 2007
- Eksportkode for CSV, Excel og Google Sheets — fordi data i terminalen ikke hjelper resten av teamet ditt
- Produksjonsmønstre — retry-logikk, caching, deling mellom crawling og parsing, og planlagt automatisering via cron eller GitHub Actions
- Et no-code-alternativ for når Python er mer verktøy enn du egentlig trenger
Min anbefaling er å starte med Firebase API-et (Metode 2) for de fleste bruksområder. Det er renere, mer pålitelig og gir deg tilgang til kommentarer uten bryet med å parse nestet HTML. Legg til Algolia API-et når du trenger historiske data. Og ha bokmerket for de gangene du bare trenger et raskt regneark og ikke vil starte et helt Python-prosjekt.
Hvis du vil gå dypere, kan du prøve å scrape HN-kommentarer for , bygge en daglig oversiktspipeline med GitHub Actions, eller utforske Algolia API-et for å se hvordan teknologitrender har endret seg det siste tiåret.
Vanlige spørsmål
Er det lov å scrape Hacker News?
HN-dataene er offentlig tilgjengelige, og Y Combinator tilbyr en offisiell API nettopp for programmatisk tilgang. Nettstedets tillater scraping av skrivebeskyttet innhold (forside, itemsider, brukersider), men ber om 30 sekunders crawl-delay. Følg denne pausen, ikke scrape interaktive endepunkter (stemming, innlogging), så er du på trygg grunn. For mer om scraping og etikk, se guiden vår om .
Har Hacker News en offisiell API?
Ja. på hacker-news.firebaseio.com/v0/ er gratis, krever ingen autentisering og gir tilgang til historier, kommentarer, brukerprofiler og alle feed-typer (top, new, best, ask, show, jobs). Den returnerer ren JSON og har ingen oppgitt rate limit, selv om det alltid anbefales å være hensynsfull med forespørsler.
Hvordan scraper jeg Hacker News-kommentarer med Python?
Ved hjelp av Firebase API-et henter du et story-item for å få kids-feltet (en array med ID-er til toppnivåkommentarer). Hver kommentar er selv et item med eget kids-felt for svar. Gå gjennom treet rekursivt med en funksjon som henter hver kommentar og barna dens. Se delen «Scrape kommentarer (rekursiv tre-gjennomgang)» over for komplett kode. Alternativt returnerer hele det nestede kommentartreet i én forespørsel — mye raskere for historier med mange kommentarer.
Kan jeg scrape Hacker News uten å skrive kode?
Ja. fungerer som en Chrome-utvidelse — åpne HN, klikk «AI Suggest Fields», og den identifiserer automatisk kolonner som tittel, URL, score og forfatter. Klikk «Scrape» og eksporter direkte til Excel, Google Sheets, Airtable eller Notion. Den håndterer paginering og kan til og med besøke undersider for å hente kommentar-data. Ingen Python, ingen selektorer, ingen vedlikehold.
Hvordan får jeg historiske Hacker News-data?
er det beste verktøyet for dette. Bruk search_by_date-endepunktet med numericFilters=created_at_i>TIMESTAMP for å filtrere på datointervall. Du kan søke med nøkkelord, filtrere på type historie og paginere gjennom opptil 500 sider med resultater. For større historiske analyser finnes det også offentlige datasett på (fullt arkiv), (28 millioner poster) og (4 millioner historier).
Les mer