幾個月前,我想替 Thunderbit 團隊做一份每天更新的 Hacker News 熱門故事摘要。剛開始,我本能地想說:先把網站加入書籤,然後每天早上看一下就好。結果撐了大概三天,我就發現自己每天都要花 20 分鐘,只是在看標題,還得把連結一條一條複製到試算表裡。
Hacker News 是網路上最精煉、也最有價值的科技情報來源之一——每月大約有 ,每天約有 1,300 則新故事被提交,並產生大約 13,000 則留言。無論你是想追蹤新興技術趨勢、監測品牌聲量、從「Who’s Hiring」討論串建立招募名單,還是單純想掌握開發者社群在關注什麼,光靠人工追蹤幾乎是不可能的任務。
好消息是:用 Python 抓取 Hacker News 其實比想像中簡單很多。這篇指南會帶你走過兩種完整方法——使用 BeautifulSoup 做 HTML 抓取,以及使用官方 HN Firebase API——另外也會涵蓋分頁、資料匯出、適合正式環境的做法,還有一個當你覺得 Python 有點大材小用時,可以直接上手的免寫程式替代方案。
為什麼要用 Python 抓取 Hacker News?
Hacker News 不只是另一個連結聚合站。它是一個由社群共同篩選的資訊流,最有意思的科技故事會透過投票與熱烈討論一路浮上檯面。使用者輪廓很明顯偏向科技專業人士(約 ),而網站有 66% 的直接流量,也說明這是一群忠誠、習慣回訪的讀者,而不是隨便路過看看的人。
以下是大家會去抓取 HN 資料的原因:
| 使用情境 | 你能拿到什麼 |
|---|---|
| 每日科技摘要 | 把熱門故事、分數與連結送到你的信箱或 Slack |
| 品牌/競品監測 | 當你的公司或產品被提及時即時提醒 |
| 趨勢分析 | 追蹤哪些技術、語言或主題正在累積熱度 |
| 招募 | 從「Who’s Hiring」討論串中整理職缺、技術棧與薪資訊號 |
| 內容研究 | 找出表現好的主題,作為寫作或分享的方向 |
| 情緒分析 | 判斷社群對產品、發表或產業變化的看法 |
像 Stripe、Dropbox、Airbnb 這些合計市值超過 4,000 億美元的公司,都曾把 Hacker News 視為早期回饋與使用者的重要來源。Drew Houston 曾在 2007 年 4 月把 Dropbox demo 發到 HN,結果直接衝上榜首,beta 等候名單在一天內從 5,000 人暴增到 75,000 人。HN 資料不只是有趣,還有很明確的商業價值。
這些資料雖然是公開的,但網站結構讓人工蒐集非常費時。用 Python 自動化,才是最實際的做法。
用 Python 抓取 Hacker News 的兩種方式:總覽
本指南會介紹兩種可以直接執行的完整方法:
- 使用
requests+ BeautifulSoup 做 HTML 抓取——抓取 news.ycombinator.com 的原始 HTML,解析後萃取故事資料。很適合學習抓取基礎,也適合精準取得頁面上顯示的內容。 - 使用官方 Hacker News Firebase API——直接呼叫 JSON 端點,不需要解析 HTML。這種方式更適合穩定的資料管線、留言抓取與歷史資料分析。
下面這張比較表能幫你判斷哪種方式更適合你的需求:
| 比較項目 | HTML 抓取(requests + BS4) | HN Firebase API | Thunderbit(免寫程式) |
|---|---|---|---|
| 設定難度 | 中等(需解析 HTML 選擇器) | 低(JSON 端點) | 幾乎沒有(2 步 Chrome 擴充功能) |
| 資料即時性 | 即時首頁資料 | 即時(可依 ID 取得任何項目) | 即時 |
| 速率限制風險 | 中等(robots.txt 要求 30 秒抓取延遲) | 低(官方、限制寬鬆) | 由 Thunderbit 管理 |
| 留言抓取 | 困難(巢狀 HTML) | 容易(遞迴項目 ID) | 透過子頁面抓取功能 |
| 歷史資料 | 有限 | 可透過 Algolia Search API | 不適用 |
| 最適合 | 學習抓取基礎 | 穩定的資料管線 | 非工程師、快速匯出 |
兩種方法都附有完整、可執行的 Python 程式碼。如果你只是想拿到資料,不想自己寫任何程式,這篇也會一起教你。
開始前的準備
- 難度: 初學到中級
- 所需時間: 每種方法約 15–20 分鐘
- 你需要準備:
- 已安裝 Python 3.11+
- 終端機或程式碼編輯器
- Chrome 瀏覽器(如果你想檢查 HN 的 HTML,或試試免寫程式方案)
- (可選,用於免寫程式方法)

設定 Python 環境
在碰 HN 資料之前,先把開發環境準備好。我建議建立虛擬環境,讓專案依賴保持乾淨。
1# 建立並啟用虛擬環境
2python3 -m venv hn-scraper
3# macOS/Linux:
4source hn-scraper/bin/activate
5# Windows:
6hn-scraper\Scripts\activate
7# 安裝兩種方法都會用到的套件
8pip install requests==2.33.1 beautifulsoup4==4.14.3 pandas==3.0.2 openpyxl==3.1.5
如果之後要做正式環境常見的處理(快取、重試),也建議一起安裝:
1pip install requests-cache==1.3.1 tenacity==9.1.4
不需要特別的 API 金鑰,也不需要驗證權杖。HN 資料是公開的。
方法 1:用 BeautifulSoup 搭配 Python 抓取 Hacker News
這是最經典的做法——先抓 HTML,再解析並取出你要的資料。這也是大多數人學網頁爬蟲的起點,而 HN 的表格式結構非常簡單,很適合拿來練手。
步驟 1:抓取 Hacker News 首頁
打開編輯器,建立一個名為 scrape_hn_bs4.py 的檔案。先寫入以下程式:
1import requests
2from bs4 import BeautifulSoup
3> This paragraph contains content that cannot be parsed and has been skipped.
4print(f"Status: {response.status_code}, Page length: {len(response.text)} chars")
執行後,你應該會看到 Status: 200,以及大約 40,000–50,000 字元的頁面長度。這代表 HN 首頁的原始 HTML 已經載入到記憶體中,準備好讓你解析了。
步驟 2:理解 HTML 結構
HN 採用的是表格式排版——沒有現代 CSS grid 或 flexbox。每則故事都由兩個關鍵的 <tr> 列組成:
- 故事列(
<tr class="athing submission">):包含排名、標題與連結 - 資訊列(下一個
<tr>):包含分數、作者、時間與留言數
重要的選擇器如下:
span.titleline > a—— 故事標題與 URLspan.score—— 投票數(例如「118 points」)a.hnuser—— 作者帳號span.age—— 發文時間.subtext中最後一個包含「comment」字樣的<a>—— 留言數
如果你在 Chrome 上對任一故事標題按右鍵並選擇「Inspect(檢查)」,你會看到類似這樣的 HTML:
1<span class="titleline">
2 <a href="https://darkbloom.dev">Darkbloom – Private inference on idle Macs</a>
3</span>
下面的資訊列則可能像這樣:
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>
理解這些選擇器非常重要——如果 HN 之後改了標記結構,你就需要更新它們。(小劇透:使用 API 的方法可以避開這個問題。)
步驟 3:擷取標題、連結與分數
現在進入重點。我們會逐一遍歷每個故事列,先從故事列中抓標題與連結,再從它下方的資訊列抓分數。
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 # 從故事列取得標題與 URL
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 # 從下一列取得資訊
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# 篩選出 50 分以上的故事,並依分數排序
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])
幾個重點說明:
- 海象運算子(
:=)是 Python 3.8 以上才有的語法。它能讓你在同一行中完成指定與判斷,對像span.score這種不一定存在的元素特別方便,例如職缺貼文通常就沒有分數。 - HN 在「留言數」與數字之間使用
\xa0(不換行空白),因此要用這個字元來分割。 - 連到 HN 其他頁面的故事(例如「Ask HN」)會使用
item?id=開頭的相對網址。你可能會想在前面補上https://news.ycombinator.com/。
步驟 4:執行並查看結果
儲存後執行:
1python scrape_hn_bs4.py
你應該會看到類似以下的輸出:
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 ...]
這就是第 1 頁的 30 則故事。不過 HN 在任何時間點其實都有數百則活躍故事。我們會在後面介紹分頁處理。
方法 2:使用官方 API 搭配 Python 抓取 Hacker News
HN Firebase API 是官方認可的 Hacker News 資料存取方式。沒有驗證、沒有 API 金鑰、也不需要解析 HTML。你會直接拿到乾淨的 JSON 回應。我在需要穩定跑在正式環境的情境下,通常都會用這個方法。
你需要知道的核心 API 端點
基礎網址是 https://hacker-news.firebaseio.com/v0/。以下是最重要的端點:
This paragraph contains content that cannot be parsed and has been skipped.
一則故事項目大致會長這樣:
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}
kids 欄位包含直接子留言的 ID。每則留言本身也是一個 item,並且可能還有自己的 kids——這就是留言樹的結構。
步驟 1:抓取熱門故事 ID
建立一個名為 scrape_hn_api.py 的檔案:
1import requests
2import time
3from pprint import pprint
4API_BASE = "https://hacker-news.firebaseio.com/v0"
5# 抓取熱門故事 ID
6response = requests.get(f"{API_BASE}/topstories.json")
7story_ids = response.json()
8print(f"Got {len(story_ids)} top story IDs")
9# Output: Got 500 top story IDs
一次請求就拿到 500 個故事 ID——不需要解析,不需要選擇器,直接就是一個 JSON 陣列。
步驟 2:依 ID 抓取故事詳情
接著我們需要實際的故事資料。這時會遇到 fan-out 問題:500 則故事就代表要發出 500 次 API 呼叫。根據我的測試,每次 item 請求連續執行時大約要 1.2 秒。500 則故事大概要 10 分鐘。
多數情境根本不需要全部 500 則。下面的程式會抓取前 30 則:
1def fetch_story(story_id):
2 """從 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# 依分數排序,顯示前 10 筆
7top = sorted(stories, key=lambda x: x["score"], reverse=True)[:10]
8pprint(top)
time.sleep(0.1) 是一個小小的禮貌延遲。Firebase API 沒有明確公告速率限制,但對任何 API 連續猛打、不留緩衝都不是好習慣。
步驟 3:抓取留言(遞迴樹狀走訪)
這就是 API 相較於 HTML 抓取特別有優勢的地方。HN 的留言結構非常深,會有回覆的回覆、回覆的回覆的回覆。若用 HTML,得處理非常複雜的巢狀表格結構;但用 API 時,每則留言的 kids 欄位都會告訴你它的子留言 ID,你只要遞迴地走訪整棵樹就好。
1def fetch_comments(item_id, depth=0, max_depth=3):
2 """以遞迴方式抓取留言,最多到 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# 範例:抓取熱門故事的留言
13if stories:
14 top_story = stories[0]
15 top_story_full = requests.get(f"{API_BASE}/item/{top_story['id']}.json").json()
16 if top_story_full.get("kids"):
17 print(f"\nComments for: {top_story['title']}")
18 all_comments = []
19 for kid_id in top_story_full["kids"][:5]: # 前 5 則頂層留言
20 all_comments.extend(fetch_comments(kid_id, depth=0, max_depth=2))
21 time.sleep(0.1)
22 for c in all_comments[:15]:
23 indent = " " * c["depth"]
24 preview = c["text"][:80].replace("\n", " ") if c["text"] else "[no text]"
25 print(f"{indent}[{c['author']}] {preview}...")
這種遞迴做法,遠比解析巢狀 HTML 留言串容易。如果你需要完整留言樹,API 就是首選。
步驟 4:執行並查看結果
1python scrape_hn_api.py
你會看到結構化的故事資料,後面接著巢狀留言預覽。資料更乾淨、留言更容易取得,而且不用擔心 HN 只是改了一個 CSS class 就讓你的爬蟲壞掉。
超越第 1 頁:分頁與歷史資料
大多數 HN 抓取教學都只做到第 1 頁——也就是 30 則故事。這對快速示範夠用,但真正的情境通常需要更深入的資料。
使用 BeautifulSoup 抓取多個頁面
HN 的分頁網址很簡單:?p=2、?p=3 以此類推。每頁會有 30 則故事,而網站最多大約提供到第 20 頁(總共約 600 則故事)。再往後就會是空頁。
1import time
2def scrape_hn_pages(num_pages=5):
3 """抓取 Hacker News 首頁的多個頁面。"""
4 all_stories = []
5 for page in range(1, num_pages + 1):
6 url = f"https://news.ycombinator.com/news?p={page}"
7 response = requests.get(url, headers=headers)
8 soup = BeautifulSoup(response.text, "html.parser")
9 story_rows = soup.select("tr.athing")
10 if not story_rows:
11 print(f"Page {page}: no stories found, stopping.")
12 break
13 for row in story_rows:
14 title_tag = row.select_one("span.titleline > a")
15 if not title_tag:
16 continue
17 meta_row = row.find_next_sibling("tr")
18 score = 0
19 if meta_row and (score_tag := meta_row.select_one("span.score")):
20 score = int(score_tag.get_text().replace(" points", ""))
21> This paragraph contains content that cannot be parsed and has been skipped.
22 print(f"Page {page}: scraped {len(story_rows)} stories")
23 # 尊重 robots.txt 規定的 30 秒抓取延遲
24 if page < num_pages:
25 time.sleep(30)
26 return all_stories
27stories = scrape_hn_pages(5)
28print(f"\nTotal stories scraped: {len(stories)}")
time.sleep(30) 非常重要。HN 的 明確要求 30 秒抓取延遲。若忽略這個規定,可能會被限流(HTTP 429)或暫時封鎖。五個頁面每 30 秒抓一次,總共大約要 2.5 分鐘——不算快,但很有禮貌。
如果你不想自己處理分頁程式碼, 可以自動處理點擊式與無限滾動分頁。它會自動點 HN 頁面底部的「More」按鈕,不需要任何額外設定。
用 Algolia API 取得 Hacker News 歷史資料
Firebase API 提供的是目前資料。如果你要做歷史分析——例如「2023 年最熱門的 Python 故事是什麼?」或「過去 5 年 AI 相關內容的變化趨勢如何?」——你就需要 。
1import requests
2ALGOLIA_BASE = "https://hn.algolia.com/api/v1"
3> This paragraph contains content that cannot be parsed and has been skipped.
4# 範例:找出 2024 年 1 月以來、分數 10 分以上的 Python 抓取故事
5results = search_hn(
6 query="python scraping",
7 tags="story",
8)
9print(f"Found {results['nbHits']} total results")
10for hit in results["hits"][:5]:
11 print(f" [{hit.get('points', 0)} pts] {hit['title']}")
若要依日期篩選,使用 numericFilters:
1import calendar, datetime
2# 2024 年 1 月 1 日之後的故事
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 速度很快(伺服器處理時間約 5–9 毫秒)、不需要 API 金鑰,且支援最多 500 頁分頁。若要做大量歷史分析,這是最理想的方案。
7## 將抓到的 Hacker News 資料匯出成 CSV、Excel 與 Google Sheets
8我看過的每一篇 HN 抓取教學,最後通常都只在終端機印出 `pprint()` 的結果。這對除錯很好,但如果你要做每日摘要或趨勢分析,資料還是要放進檔案裡。以下教你怎麼做。
9### 使用 Python 匯出 CSV
10```python
11import csv
12def export_to_csv(stories, filename="hn_stories.csv"):
13 """把抓到的故事儲存成 CSV 檔。"""
14 fieldnames = ["title", "url", "score", "author", "comments"]
15 with open(filename, "w", newline="", encoding="utf-8") as f:
16 writer = csv.DictWriter(f, fieldnames=fieldnames)
17 writer.writeheader()
18 writer.writerows(stories)
19 print(f"Saved {len(stories)} stories to {filename}")
20export_to_csv(stories)
使用 Python 匯出 Excel
1import pandas as pd
2def export_to_excel(stories, filename="hn_stories.xlsx"):
3 """把抓到的故事儲存成 Excel 檔。"""
4 df = pd.DataFrame(stories)
5 df.to_excel(filename, index=False, engine="openpyxl")
6 print(f"Saved {len(stories)} stories to {filename}")
7export_to_excel(stories)
記得要先安裝 openpyxl,因為 pandas 會把它當成 Excel 引擎。如果沒裝,執行時就會出現 ImportError。
推送到 Google Sheets(可選)
如果你想做自動化流程,可以用 gspread 直接把資料送到 Google Sheets。不過這需要先設定 Google Cloud service account(一次性流程):
1import gspread
2gc = gspread.service_account(filename="service_account.json")
3sh = gc.open("HN Daily Digest")
4worksheet = sh.sheet1
5# 把 stories 轉成列資料
6header = list(stories[0].keys())
7rows = [list(s.values()) for s in stories]
8worksheet.clear()
9worksheet.update([header] + rows)
10print("Pushed to Google Sheets")
免寫程式的匯出替代方案
如果光是設定 service account 和寫匯出程式,就比抓資料本身還麻煩,我完全懂。在 Thunderbit,我們做了免費的資料匯出功能,能把抓好的資料直接送到 Excel、Google Sheets、Airtable 或 Notion——不用寫程式、不用憑證、也不用維護管線。若只是單次抓取,這真的會快很多。下面還會再多說一些。
讓爬蟲更接近正式環境:錯誤處理、快取與排程
如果你只是玩一次,前面的程式已經夠用;但如果你要把它每天放進工作流程,就還需要幾個關鍵元件。
錯誤處理與重試邏輯
網路會失敗,伺服器會限流,單次錯誤不應該讓整個抓取流程整個垮掉。以下是一個帶有指數退避的重試函式:
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 """自動重試並採用指數退避來抓取網址。"""
6 response = requests.get(url, timeout=10)
7 response.raise_for_status()
8 return response
9# 用法:
10try:
11 resp = fetch_with_retry("https://hacker-news.firebaseio.com/v0/topstories.json")
12 story_ids = resp.json()
13except Exception as e:
14 print(f"Failed after retries: {e}")
tenacity 會把重試邏輯整理得很乾淨。它最多會重試 5 次,並使用帶抖動的指數退避——從 1 秒開始,最多到 60 秒。這可以比較優雅地處理 HTTP 429(速率限制)、503(服務不可用)與暫時性的網路錯誤。
快取回應,避免重複抓取
在開發時,你會一再執行爬蟲,調整解析邏輯。如果沒有快取,每次執行都會重新向 HN 伺服器請求相同資料。requests-cache 只要兩行就能解決:
1import requests_cache
2requests_cache.install_cache("hn_cache", expire_after=3600) # 快取 1 小時
把這兩行加到腳本最前面後,所有 requests.get() 呼叫都會自動快取到本機 SQLite 資料庫裡。你在一小時內重跑 10 次,真正打到網路的只會是第一次。這也是論壇使用者常常推薦的工具,而且真的很有道理。
把抓取與解析分開
有經驗的爬蟲工程師很推的一個做法:先下載原始資料,再進行解析。這樣一來,如果解析邏輯有 bug,你可以修正後直接重新解析,不必重抓資料。
1import os, json
2def crawl_and_save(story_ids, output_dir="raw_data"):
3 """抓取故事資料並把原始 JSON 存到磁碟。"""
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 # 跳過已抓取項目
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.
13這種「先抓後解析」的兩階段流程,特別適合你要處理數百筆資料、又想快速迭代資料處理邏輯的情境。
14### 把爬蟲排程化
15如果你要做每日 HN 摘要,就需要讓爬蟲自動執行。常見做法有兩種:
16**方案 1:cron(Linux / Mac)**
17```bash
18# 每天 UTC 早上 8:30 執行
1930 8 * * * /usr/bin/python3 /home/user/scrape_hn.py >> /home/user/scrape.log 2>&1
方案 2:GitHub Actions(免費,不需要自己的伺服器)
1name: Scrape Hacker News
2on:
3 schedule:
4 - cron: '30 8 * * *' # 每天 UTC 8:30
5 workflow_dispatch: # 手動觸發按鈕
6jobs:
7 scrape:
8 runs-on: ubuntu-latest
9 steps:
10 - uses: actions/checkout@v4
11 - uses: actions/setup-python@v6
12 with:
13 python-version: '3.12'
14 - run: pip install requests beautifulsoup4 pandas openpyxl
15 - run: python scrape_hn.py
16 - run: |
17 git config user.name "GitHub Actions Bot"
18 git config user.email "actions@github.com"
19 git add -A
20 git diff --staged --quiet || git commit -m "Update HN data $(date -u +%Y-%m-%dT%H:%M:%SZ)"
21 git push
使用 GitHub Actions 排程時有幾個小提醒:所有 cron 時間都是 UTC,常見會有 15–60 分鐘延遲(所以像 :30 這種非整點時間通常比 :00 更穩),而且 GitHub 可能會停用 60 天沒有活動的專案之排程工作流程。務必加入 workflow_dispatch,這樣你測試時才能手動觸發。
如果你想要更簡單的方式,Thunderbit 的 Scheduled Scraper 功能可以直接用自然語言描述排程,例如「每天早上 8 點抓一次」,完全不需要自己架伺服器或設定 cron。
當 Python 太重時:免寫程式抓取 Hacker News 的方式
老實說,就算我是 Python 愛好者,而且我們團隊也在做開發者工具,如果你只是想把今天前 100 則 HN 熱門故事匯出到試算表,而且只做一次,那用 Python 其實有點多此一舉。光是環境設定(虛擬環境、安裝套件、找選擇器)就比真正抓資料還花時間。
這就是 的用武之地。流程大概是這樣:
- 在 Chrome 打開
news.ycombinator.com - 點 Thunderbit 擴充功能圖示,然後選「AI Suggest Fields」
- AI 會自動讀取頁面並建議欄位:Title、URL、Score、Author、Comment Count、Time Posted
- 你可以自行調整欄位(重新命名、刪除或新增自訂欄位——甚至可以加上像「Categorize as AI/DevTools/Web/Other」這樣的 AI 提示詞)
- 點「Scrape」——資料就會變成結構化表格
- 匯出到 Excel、Google Sheets、Airtable 或 Notion
兩次點擊就能拿到結構化資料。沒有選擇器、沒有程式碼、沒有維護成本。
這裡真正的優勢是:Thunderbit 的 AI 會自動適應版面變動。傳統的 CSS 選擇器爬蟲,一旦網站改了標記就很容易壞掉——雖然 HN 的 HTML 相對穩定,但它確實改過(像 class="athing submission" 有更新,span.titleline 也取代了舊的 a.storylink)。AI 爬蟲每次都會重新讀頁面,所以不會被 class 名稱改動影響。

Thunderbit 也能處理分頁(自動點擊 HN 的「More」按鈕)與子頁面抓取(逐一進入每篇故事的留言頁,抓取討論資料)。如果是 這類情境,它其實就相當於方法 2 的遞迴 API 程式碼,只是你不用寫任何一行。
取捨很直接:當你需要自訂邏輯、複雜資料轉換、排程化自動管線,或你本來就在學寫程式時,Python 是正確選擇;當你需要快速拿資料、不想維護程式,或者你不是開發者時,Thunderbit 會更適合。選擇最符合你情境的工具就好。
Python vs. API vs. 免寫程式:你該選哪一種?
下面是完整的決策表:
| 比較項目 | BeautifulSoup(HTML) | Firebase API | Algolia API | Thunderbit(免寫程式) |
|---|---|---|---|---|
| 所需技術能力 | 中級 Python | 初階 Python | 初階 Python | 不需要 |
| 設定時間 | 10–15 分鐘 | 5–10 分鐘 | 5–10 分鐘 | 2 分鐘 |
| 維護成本 | 中等(選擇器可能失效) | 低(穩定 JSON) | 低(穩定 JSON) | 幾乎沒有 |
| 資料深度 | 只有首頁 | 任意項目、使用者 | 搜尋 + 歷史資料 | 首頁 + 子頁面 |
| 留言 | 困難 | 容易(遞迴) | 容易(巢狀樹) | 子頁面抓取 |
| 歷史資料 | 否 | 否 | 是(完整封存) | 否 |
| 匯出選項 | 自己寫程式 | 自己寫程式 | 自己寫程式 | 內建(Excel、Sheets 等) |
| 排程 | cron / GitHub Actions | cron / GitHub Actions | cron / GitHub Actions | 內建排程器 |
| 最適合 | 學習爬蟲 | 穩定資料管線 | 研究與分析 | 快速抓資料 |
如果你在學 Python,或是在做客製化工具,就選方法 1 或 2;如果你要做歷史分析,再加上 Algolia API;如果你只是想直接拿資料、不想寫程式,試試 。
結論與重點整理
現在你手上已經有這些工具:
- 兩種完整的 Python 方法來抓取 Hacker News——用 BeautifulSoup 解析 HTML,或用 Firebase API 取得乾淨的 JSON 資料
- 分頁技巧,可以抓超過第 1 頁,還能透過 Algolia API 往回分析 2007 年以來的歷史資料
- 匯出程式碼,可輸出成 CSV、Excel 與 Google Sheets——因為資料只待在終端機裡,對團隊其他人沒什麼幫助
- 正式環境做法——重試邏輯、快取、抓取/解析分離,以及透過 cron 或 GitHub Actions 排程自動化
- 免寫程式替代方案,當 Python 對你的需求來說太重時可直接使用
我的建議是:多數情況先從 Firebase API(方法 2)開始。它更乾淨、更穩定,而且可以直接抓留言,不必費力解析巢狀 HTML。當你需要歷史資料時,再加入 Algolia API。至於 ,建議先收藏起來,當你只想快速拿一份試算表、又不想啟動整個 Python 專案時,它會非常好用。
如果你想更進一步,可以試著抓 HN 留言做 ,用 GitHub Actions 建立每日摘要管線,或研究 Algolia API,追蹤過去十年間科技趨勢如何變化。
常見問題
抓取 Hacker News 合法嗎?
HN 的資料是公開可存取的,而且 Y Combinator 也提供了官方 API,專門用於程式化存取。網站的 允許抓取只讀內容(首頁、項目頁、使用者頁),但要求 30 秒的抓取延遲。只要你尊重這個延遲、不抓互動式端點(投票、登入),基本上就沒問題。若想進一步了解抓取倫理,可參考我們的 指南。
Hacker News 有官方 API 嗎?
有。 位於 hacker-news.firebaseio.com/v0/,免費、無須驗證,可存取故事、留言、使用者個人資料,以及所有 feed 類型(top、new、best、ask、show、jobs)。它回傳乾淨的 JSON,而且沒有明示的速率限制,但仍建議以禮貌的頻率發送請求。
我要怎麼用 Python 抓取 Hacker News 留言?
使用 Firebase API 時,先抓故事項目取得它的 kids 欄位(也就是頂層留言 ID 陣列)。每則留言本身也是一個 item,且有自己的 kids 欄位代表回覆。你可以寫一個函式,以遞迴方式抓取每則留言與其子留言。上面的「抓取留言(遞迴樹狀走訪)」章節有完整範例。或者,你也可以用 一次取得完整的巢狀留言樹,處理留言很多的文章會快非常多。
不寫程式也能抓 Hacker News 嗎?
可以。 是 Chrome 擴充功能:打開 HN,點「AI Suggest Fields」,它會自動辨識標題、URL、分數、作者等欄位。按下「Scrape」後,就能直接匯出到 Excel、Google Sheets、Airtable 或 Notion。它還能處理分頁,甚至能進入子頁面抓取留言資料。完全不用 Python、不用選擇器,也不用維護。
我要怎麼取得 Hacker News 的歷史資料?
是這個需求的最佳工具。使用 search_by_date 端點,搭配 numericFilters=created_at_i>TIMESTAMP 就能依日期區間篩選。你可以依關鍵字搜尋、依故事類型過濾,並在最多 500 頁結果中分頁查找。若要做大量歷史分析,也可使用 (完整封存)、(2,800 萬筆紀錄)與 (400 萬則故事)的公開資料集。
延伸閱讀