iT邦幫忙

2025 iThome 鐵人賽

DAY 15
0
Modern Web

每天一點 API:打造我的生活小工具系列 第 15

Day15 — 從巢狀到平面:新聞 API 資料整理練習

  • 分享至 

  • xImage
  •  

API 回來的 JSON 常常不是平面的表格,而是巢狀結構。

因此今天我要來學習如何解析並整理成清單或 CSV。

為什麼要學巢狀 JSON?

  1. API 回傳的資料結構常常很複雜

不只是簡單的「id」或「name」欄位,還會有子物件或清單的結構。

  1. 分析前必須做扁平化

巢狀資料不方便直接查詢或輸出成報表,因此需要把它攤平成一層,像是把 address.city 變成 city

  1. 扁平化讓資料更容易轉換格式

扁平化後的資料,可以存成 CSV、Excel 等格式,讓分析或分享更加方便。

JSON 巢狀結構範例說明

下面是新聞 API 回傳的 JSON 範例,結果很常見到有巢狀資料結構:

{
  "count": 1234,
  "next": "https://.../?page=2",
  "previous": null,
  "results": [
    {
      "id": 1001,
      "title": "SpaceX launches...",
      "url": "https://example.com/article-1001",
      "image_url": "https://example.com/img.jpg",
      "news_site": "SpaceNews",
      "summary": "A short summary...",
      "published_at": "2025-09-20T12:34:56Z",
      "launches": [{"provider": "SpaceX"}],
      "events": [{"provider": "NASA"}]
    }
  ]
}

最外層有以下這幾個欄位:

count:新聞總數

next:下一頁的網址

previous:上一頁,這裡是 null 表示沒有上一頁

results:一個清單,裡面放著多篇新聞文章

results 是一個清單,每一項都是一篇文章的資料

每篇文章裡面還有更多巢狀子物件:

launches 是一個清單,裡面有提供者的資料

events 也是清單,裡面有活動提供者的資料

小實作:解析新聞 API 的巢狀 JSON

步驟 1:呼叫 API

  • 使用一個免費的新聞 API,Spaceflight News API,不需要金鑰。

  • limit=10 抓取最新的前 10 筆新聞文章資料。

  • 若成功回應,從 results(或 articles)取出清單。

import csv
import requests

API = "https://api.spaceflightnewsapi.net/v4/articles/"  # 免金鑰

def fetch_articles(limit=10, timeout=10):
    # 呼叫 API,拿回多筆文章。
    # 該 API 支援 ?limit= 參數
    r = requests.get(API, params={"limit": limit}, timeout=timeout)
    r.raise_for_status()
    data = r.json()
    # 常見清單 key:results 或 articles;都找看看(增加適配性)
    items = data.get("results") or data.get("articles") or data
    # 確保是清單
    return items if isinstance(items, list) else []

步驟 2:扁平化資料

  • API 回傳的資料裡有巢狀結構,像 source.name 要取成單一的 source 字串。

  • launchesevents 是清單,要把裡面的 provider 資訊用字串連接起來(例如用逗號分隔)。

  • 注意欄位名稱有時不一樣,例如有的用 publishedAt,有的用 published_at,要處理好對應。

def flatten_article(a: dict) -> dict:
    # 把一篇文章的巢狀欄位攤平成一層字典,方便後續列印/存檔。
    # 有些 API 欄位名稱不同,盡量相容(右邊是替代名稱)
    title = a.get("title") or a.get("headline") or ""
    url = a.get("url") or a.get("link") or ""
    img = a.get("image_url") or a.get("urlToImage") or ""
    summary = a.get("summary") or a.get("description") or ""
    published = a.get("published_at") or a.get("publishedAt") or ""
    # 來源:有些在 source.name、有些在 news_site
    source = ""
    if isinstance(a.get("source"), dict):
        source = a["source"].get("name") or ""
    source = source or a.get("news_site") or ""

    # 巢狀清單(launches/events)→ 取 provider 欄位後用逗號串起來
    launches = ", ".join(
        x.get("provider") for x in (a.get("launches") or []) if isinstance(x, dict) and x.get("provider")
    )
    events = ", ".join(
        x.get("provider") or x.get("name", "") for x in (a.get("events") or []) if isinstance(x, dict)
    )

    return {
        "title": title,
        "source": source,
        "published": published,
        "url": url,
        "image": img,
        "summary": summary,
        "launches": launches,
        "events": events,
    }

步驟 3:整理清單輸出

  • 在終端機(命令列視窗)印出整理後的清單,格式是「序號、標題、來源、發佈時間」,方便快速查看。
def print_list(articles):
    # 把多筆文章印成清單(終端機好閱讀版本)。
    if not articles: # 沒資料就提示「沒有資料」。
        print("(沒有資料)")
        return
    for i, a in enumerate(articles, 1):
        line = f"{i}. {a['title']} — {a['source']} — {a['published']}"
        print(line)

步驟 4:存成 CSV

  • 用 Python 的 csv.DictWriter 把整理完成的資料寫入articles.csv檔案。

  • 這個 CSV 檔案可以直接用 Excel 打開檢查。

def save_csv(articles, path="articles.csv"):
    # 把整理好的多筆資料存成 CSV。
    if not articles:
        return
    fields = ["title", "source", "published", "url", "image", "summary", "launches", "events"] # 指定要輸出的欄位順序 fields。
    with open(path, "w", newline="", encoding="utf-8-sig") as f:
        w = csv.DictWriter(f, fieldnames=fields)
        w.writeheader()
        w.writerows(articles)
    print(f"已輸出 CSV:{path}({len(articles)} 筆)")

def main():
    try:
        raw_items = fetch_articles(limit=10)
    except requests.exceptions.RequestException as e:
        print("API 錯誤:", e)
        return

    # 把抓到的每一筆文章用 flatten_article() 轉成扁平化格式。
    flat = [flatten_article(x) for x in raw_items]

    # 終端機清單,先印在終端機上面看一眼。
    print_list(flat)

    # 存成 CSV,方便 Excel 與 分析
    save_csv(flat, "articles.csv")

if __name__ == "__main__":
    main()

執行結果:

今日總結

  • 學會處理 JSON 的巢狀結構

  • 練習扁平化巢狀欄位(子物件、清單到單一欄位)

  • 把資料整理成清單,並成功輸出成 CSV


上一篇
Day14 — API 資料清理:打理資料的第一步
下一篇
Day16 — API 資料轉換:JSON、CSV、Excel 一次搞懂
系列文
每天一點 API:打造我的生活小工具17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言