本文 AI 產出,尚未審核

LangChain 教學:文件載入器(Loader)— Unstructured 與 PlaywrightLoader


簡介

在使用 LangChain 建構聊天機器人或資訊檢索系統時,最關鍵的第一步往往是把原始資料轉換成 Document 物件,讓後續的向量化、檢索與生成流程得以順利進行。
現實世界的資料來源多樣:PDF 報告、網頁、電子郵件、甚至是動態渲染的單頁應用(SPA)。如果只能手動複製貼上,既耗時又容易遺漏關鍵資訊。

本篇將聚焦於兩個強大且彈性的 Loader

  1. Unstructured — 透過 unstructured 套件自動解析各種非結構化檔案(PDF、DOCX、HTML、圖片等)。
  2. PlaywrightLoader — 利用 Microsoft Playwright 瀏覽器自動化技術,抓取需要 JavaScript 渲染的網頁內容。

掌握這兩個工具,你就能快速把 多樣化的原始文件 轉成 LangChain 可直接使用的 Document,為後續的檢索與生成奠定堅實基礎。


核心概念

1. 為什麼需要 Loader?

  • 抽象化:LangChain 把所有資料抽象為 Document(包含 page_contentmetadata),統一介面讓後續的向量化、分割、檢索都能無縫接軌。
  • 自動化:手動整理文件既繁瑣又容易出錯。Loader 能自動辨識檔案格式、解析文字、保留重要的 meta 資訊(檔名、來源 URL、頁碼等)。
  • 可擴充:LangChain 本身提供多種內建 Loader,開發者也可以自行繼承 BaseLoader 來實作自訂的載入邏輯。

2. Unstructured Loader

unstructured 是一個專門處理 非結構化檔案 的 Python 套件,支援 PDF、Word、PowerPoint、HTML、圖片(OCR)等。LangChain 內建 UnstructuredFileLoader,只要傳入檔案路徑或檔案類型,即可得到 Document

2.1 基本使用方式

from langchain.document_loaders import UnstructuredFileLoader

# 讀取本機 PDF
loader = UnstructuredFileLoader("data/report.pdf")
documents = loader.load()
print(f"共抓到 {len(documents)} 個 Document")
print(documents[0].page_content[:200])   # 顯示前 200 個字
  • load() 會回傳 list[Document]
  • 預設會把整個檔案視為單一 Document,若想依頁分割,可搭配 RecursiveCharacterTextSplitter

2.2 多檔案批次載入

from pathlib import Path
from langchain.document_loaders import UnstructuredFileLoader

folder = Path("data/multi/")
all_docs = []

for file_path in folder.glob("*.*"):   # 支援任意副檔名
    loader = UnstructuredFileLoader(str(file_path))
    docs = loader.load()
    # 為每份文件加入檔名作為 metadata
    for d in docs:
        d.metadata["source"] = file_path.name
    all_docs.extend(docs)

print(f"總共載入 {len(all_docs)} 份文件")

2.3 使用 OCR 解析圖片或掃描 PDF

from langchain.document_loaders import UnstructuredFileLoader

# 需要安裝 tesseract & pytesseract
loader = UnstructuredFileLoader(
    "data/scanned_invoice.png",
    strategy="ocr_only",          # 只走 OCR
    ocr_languages=["eng", "chi_tra"]  # 支援英文與繁體中文
)
doc = loader.load()[0]
print(doc.page_content[:300])

小技巧:若 OCR 效能不佳,可先調整 ocr_kwargs(如 DPI、預處理參數),或使用 pdfminer 先嘗試文字抽取,失敗再回退 OCR。

3. PlaywrightLoader

許多現代網站採用 SPA(Single Page Application) 或大量 JavaScript 動態渲染,傳統的 requests 抓取方式只能拿到原始 HTML,無法取得最終呈現的內容。Playwright 是微軟開源的跨瀏覽器自動化框架,支援 Chrome、Firefox、WebKit,且可在無頭(headless)模式下執行。

LangChain 的 PlaywrightLoader 包裝了 Playwright 的基本操作,讓開發者只需要提供目標 URL,即可得到渲染後的文字。

3.1 安裝與基本設定

pip install playwright langchain[all]   # 安裝 Playwright 與 LangChain
playwright install                     # 下載瀏覽器二進位

3.2 讀取單一網頁

from langchain.document_loaders import PlaywrightLoader

url = "https://www.ptt.cc/bbs/Tech_Job/M.1698421234.A.1B8.html"
loader = PlaywrightLoader(url)

# 預設會等到 networkidle,確保大部分資源載入完成
doc = loader.load()[0]
print(f"來源: {doc.metadata['source']}")
print(doc.page_content[:400])
  • metadata["source"] 會自動記錄 URL。
  • 可透過 wait_until="load"wait_for_selector 等參數自訂等待條件。

3.3 抓取需要登入的網站

from langchain.document_loaders import PlaywrightLoader
from playwright.sync_api import sync_playwright

def login_and_load(url, username, password):
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        page.goto("https://example.com/login")
        page.fill('input[name="user"]', username)
        page.fill('input[name="pass"]', password)
        page.click('button[type="submit"]')
        page.wait_for_load_state("networkidle")
        # 登入成功後再載入目標頁面
        page.goto(url, wait_until="networkidle")
        content = page.content()
        browser.close()
        return content

# 使用 PlaywrightLoader 直接傳入 HTML 文字
html = login_and_load(
    "https://example.com/secure/report",
    "my_user",
    "my_pass"
)

loader = PlaywrightLoader.from_html(html, source_url="https://example.com/secure/report")
doc = loader.load()[0]
print(doc.page_content[:200])

重點:對於必須先登入、點擊或滾動才能看到內容的網站,自行控制 Playwright 流程 再交給 PlaywrightLoader.from_html 能取得最完整的文字。

3.4 大量抓取(爬蟲)

from langchain.document_loaders import PlaywrightLoader
from tqdm import tqdm   # 進度條

urls = [
    "https://news.ycombinator.com/item?id=35000000",
    "https://news.ycombinator.com/item?id=35000123",
    # ... 更多 URL
]

all_docs = []
for link in tqdm(urls, desc="抓取 Hacker News"):
    loader = PlaywrightLoader(link, wait_until="networkidle")
    docs = loader.load()
    for d in docs:
        d.metadata["source"] = link
    all_docs.extend(docs)

print(f"共抓到 {len(all_docs)} 篇文章")
  • tqdm 只是一個小幫手,正式爬蟲時請務必遵守 robots.txt 與網站的使用條款。

常見陷阱與最佳實踐

陷阱 說明 解法 / 最佳實踐
檔案過大 單次 load() 會一次把整個檔案讀入記憶體,易造成 OOM。 使用 UnstructuredFileLoader 搭配 chunk_size 或先手動分割檔案(如 PDF 每 10 頁切一次)。
OCR 效能低 影像解析非常耗時,尤其大量掃描 PDF。 先使用 strategy="auto",讓套件先嘗試文字抽取,失敗才走 OCR;或使用多執行緒/分散式處理。
動態網頁未完整渲染 Playwright 只等 load,但某些 AJAX 仍在背景執行。 改用 wait_until="networkidle",或自行 page.wait_for_selector() 等特定元素出現。
被網站封鎖 大量請求會觸發 Cloudflare、Rate‑limit 等防爬機制。 加入 隨機延遲User‑Agent 變換,或使用 代理服務
metadata 缺失 從多檔案載入時,若未自行加入檔名或 URL,後續追蹤來源困難。 統一在 load 後補上 metadata["source"],例如檔名、頁碼、URL。
編碼問題 某些 PDF/HTML 內部編碼非 UTF‑8,導致亂碼。 UnstructuredFileLoader 中使用 encoding="utf-8" 或適當的 encoding 參數;若仍有問題,可先用 chardet 檢測。

小技巧

  1. 結合 TextSplitter

    from langchain.text_splitter import RecursiveCharacterTextSplitter
    splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
    chunks = splitter.split_documents(documents)
    

    這樣可以在向量化前把長文件切成適當大小,提升檢索品質。

  2. Cache Loader 結果
    若同一份文件會被多次載入,建議將 Document 物件序列化(pickle、json)後快取,減少重複解析時間。

  3. 使用環境變數管理 Playwright 設定

    import os
    os.environ["PLAYWRIGHT_HEADLESS"] = "1"   # CI/CD 時必須 headless
    

實際應用場景

場景 使用 Loader 為何適合
企業內部文件搜尋 UnstructuredFileLoader(PDF、Word、PPT) 能一次處理多種辦公檔案,且支援 OCR,適合掃描合約、報告等。
即時新聞摘要 PlaywrightLoader 抓取新聞網站 新聞網站多採用動態渲染,Playwright 能取得完整文章內容,配合 LLM 產生摘要。
法規條文檢索 UnstructuredFileLoader + OCR 法規 PDF 常為掃描檔,OCR 讓文字可被向量化。
產品說明書自動問答 結合兩者:先用 Playwright 抓取線上說明書(SPA),再用 Unstructured 處理 PDF 手冊 能同時涵蓋線上與離線資源,提供完整的知識庫。
教育平台課程筆記 PlaywrightLoader 抓取課程網頁 + UnstructuredFileLoader 處理 PDF 講義 統一輸入格式,讓學生可透過聊天機器人快速查找課程重點。

總結

  • Loader 是 LangChain 資料流的入口,負責把各式非結構化檔案或動態網頁轉為統一的 Document
  • Unstructured 提供了跨檔案類型的文字抽取能力,尤其在處理 PDF、Word、圖片(OCR)時表現穩定。
  • PlaywrightLoader 則是面對現代 JavaScript‑heavy 網站的最佳選擇,能自動等待渲染完成、支援登入與互動。
  • 透過 適當的切分、快取與 meta 資訊補齊,可以大幅提升後續向量化與檢索的效率與準確度。

掌握這兩個 Loader 後,你就能輕鬆構建 從文件到對話 的完整管線,讓 LLM 真正成為企業或個人知識的「智慧門戶」。祝開發順利,期待看到你把這些技巧應用在各種有趣的實務案例中!