跳至主要內容
問題與解答
資料抓取與 API 串接的實務

資料抓取與 API 串接的實務

問:
可以抓取別人網站的資料嗎? robots.txt 要怎麼檢查? 遇到 429 錯誤怎麼處理? 內容要執行 JS 才出現怎麼抓?
答:

先確認可不可以抓

技術上做得到,不代表可以做。抓取他人網站的資料前,應該先確認三件事:

  1. 對方的使用條款是否允許
  2. robots.txt 的規範
  3. 抓取的內容是否涉及著作權或個資

幾個明確的界線

  • 不要抓取個人資料——姓名、聯絡方式、帳號等,即使是公開顯示的
  • 不要整批複製他人的內容用於自己的網站——這是著作權問題
  • 不要繞過登入或付費機制
  • 不要造成對方伺服器的負擔

著作權的相關說明見別人的內容可以用嗎

合理的使用情境

  • 抓取自己網站的資料做檢查或搬遷
  • 使用對方正式提供的 API
  • 取得公開資料集或有明確授權的資料
  • 經對方同意的資料交換

尊重 robots.txt

from urllib.robotparser import RobotFileParser
from urllib.parse import urljoin

def can_fetch(base_url, path, agent='MyBot'):
    rp = RobotFileParser()
    rp.set_url(urljoin(base_url, '/robots.txt'))
    try:
        rp.read()
    except Exception:
        return False   # 讀不到就保守處理
    return rp.can_fetch(agent, urljoin(base_url, path))

讀不到 robots.txt 時建議保守處理,而不是預設為允許。

基本的請求設定

import requests

session = requests.Session()
session.headers.update({
    'User-Agent': 'MyCompanyBot/1.0 (+https://example.com/bot)',
})

resp = session.get(url, timeout=(5, 30))
resp.raise_for_status()

三個必要的設定

  • 明確的 User-Agent——包含聯絡方式或說明頁,讓對方知道是誰在抓,有問題時能聯繫
  • 逾時設定——(連線逾時, 讀取逾時)不設逾時是常見的錯誤,對方無回應時程式會永遠卡住
  • raise_for_status()——讓錯誤的狀態碼拋出例外,不要靜默繼續

控制頻率

import time, random

for url in urls:
    fetch(url)
    time.sleep(random.uniform(1.0, 2.5))

不要用固定的極短間隔連續請求。 這既是禮貌,也是自保——過度頻繁的請求可能被封鎖,甚至被視為攻擊行為。

建議的原則:把對方的伺服器當成你自己的網站來對待。

重試機制

from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

retry = Retry(
    total=3,
    backoff_factor=1.0,
    status_forcelist=[429, 500, 502, 503, 504],
    allowed_methods=['GET', 'HEAD'],
)
session.mount('https://', HTTPAdapter(max_retries=retry))

重要的注意事項

  • 429 代表請求過於頻繁——收到時應該放慢,而不是立刻重試
  • backoff 讓每次重試的間隔逐次拉長,避免持續衝擊
  • 只對讀取類的請求自動重試——寫入類的重試可能造成重複

解析 HTML

from bs4 import BeautifulSoup

soup = BeautifulSoup(resp.text, 'html.parser')

title = soup.select_one('h1')
title_text = title.get_text(strip=True) if title else ''

for a in soup.select('article a[href]'):
    print(a['href'], a.get_text(strip=True))

兩個實務提醒

  • 取值前先確認元素存在——網頁結構會變,直接取值容易拋出例外
  • 編碼問題——若出現亂碼,可嘗試指定 resp.encoding 或使用 resp.apparent_encoding

內容由前端程式產生的情況

如果目標頁面的內容需要執行 JavaScript 才會出現,用一般的請求抓不到。

兩種處理方向

  1. 找出資料的實際來源——多數情況前端是呼叫某個 API 取得資料,直接取用該來源更穩定也更輕量
  2. 使用瀏覽器自動化工具——資源消耗大得多,是最後手段

優先找第一種。 用瀏覽器開發者工具的網路分頁,通常能看到實際的資料請求。

串接正式 API 的實務

def call_api(session, url, params=None):
    resp = session.get(url, params=params, timeout=(5, 30))

    if resp.status_code == 429:
        wait = int(resp.headers.get('Retry-After', 60))
        logging.warning(f'頻率限制,等待 {wait} 秒')
        time.sleep(wait)
        return call_api(session, url, params)

    resp.raise_for_status()
    return resp.json()

要注意的四件事

  • 金鑰不要寫在程式碼中——用環境變數
  • 注意頻率限制——查閱對方文件的規範
  • 處理分頁——大量資料通常需要逐頁取得
  • 記錄失敗的項目——之後可以只重試失敗的部分

串接的評估與維護見API 串接前要確認什麼

自己網站的檢查腳本

這是最沒有爭議、也最實用的應用。

檢查連結是否失效

def check_links(urls, session):
    broken = []
    for u in urls:
        try:
            r = session.head(u, timeout=10, allow_redirects=True)
            if r.status_code >= 400:
                broken.append((u, r.status_code))
        except Exception as e:
            broken.append((u, str(e)))
        time.sleep(0.5)
    return broken

用 HEAD 而非 GET——只要狀態碼的話不必下載內容。但部分伺服器不支援 HEAD,失敗時可退回 GET。

其他實用的檢查

  • 所有頁面是否都有標題與描述
  • 圖片是否都有替代文字
  • 是否有混合內容(頁面是 https 但資源是 http)
  • 網站地圖中的網址是否都能正常開啟

技術檢查的項目見技術 SEO 的常見問題排查

資料的儲存與去重

import json
from pathlib import Path

def save_progress(data, path):
    tmp = Path(path).with_suffix('.tmp')
    with open(tmp, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    tmp.replace(path)     # 原子性寫入

長時間執行的抓取要能中斷後續跑——定期存檔進度,並記錄已處理的項目,避免重複。

四個自我約束

  1. 只抓需要的資料,不要整站複製
  2. 控制頻率,不造成對方負擔
  3. 標明身分,讓對方能聯繫你
  4. 收到停止的要求就停止

優先使用對方提供的 API 或資料集——那才是對方希望你使用的方式,也最穩定。

本文的範例以 Python 3 為例,實際的套件版本與 API 可能隨版本更新而異。在正式環境執行任何批次處理前,請先以少量資料測試並確實備份。

發表於2026-08-05   更新於2026-08-24
免費諮詢 · 1 個工作天內回覆

準備好讓網站 開始幫你帶生意了嗎?

不論是要做新網站、救舊網站,還是只想先聊聊方向——先諮詢,不用先付錢,我們照實給你建議。

1 個工作天回覆免費諮詢與報價費用白紙黑字26 年找得到人
免費諮詢
免費諮詢 LINE諮詢 03-4020420 臉書傳訊
免費諮詢 LINE諮詢 03-4020420 臉書傳訊
免費諮詢
免費諮詢 LINE諮詢 03-4020420 臉書傳訊
免費諮詢 LINE諮詢 03-4020420 臉書傳訊