SKILL.md
唯讀
名稱
data-extractor
描述
>
版本
1.0
資料擷取技能
概述
此技能可從任何文件格式中擷取結構化資料,使用 unstructured 這個統一函式庫來處理 PDF、Word 文件、電子郵件、HTML 等。無論輸入格式為何,都能獲得一致的結構化輸出。
使用方式
- 提供要處理的文件
- 可選地指定擷取選項
- 我將擷取結構化元素及其元資料
範例提示:
- 「從這個 PDF 中擷取所有文字和表格」
- 「解析這封郵件,取得內文、附件和元資料」
- 「將這個 HTML 頁面轉換為結構化元素」
- 「從這些混合格式的文件中擷取資料」
領域知識
unstructured 基礎
from unstructured.partition.auto import partition
# 自動偵測並處理任何文件
elements = partition("document.pdf")
# 存取擷取的元素
for element in elements:
print(f"類型: {type(element).__name__}")
print(f"文字: {element.text}")
print(f"元資料: {element.metadata}")
支援的格式
| 格式 | 函式 | 備註 |
|---|---|---|
partition_pdf |
原生 + 掃描 | |
| Word | partition_docx |
完整結構 |
| PowerPoint | partition_pptx |
投影片與備註 |
| Excel | partition_xlsx |
工作表與表格 |
| 電子郵件 | partition_email |
內文與附件 |
| HTML | partition_html |
保留標籤 |
| Markdown | partition_md |
保留結構 |
| 純文字 | partition_text |
基本解析 |
| 圖片 | partition_image |
OCR 擷取 |
元素類型
from unstructured.documents.elements import (
Title,
NarrativeText,
Text,
ListItem,
Table,
Image,
Header,
Footer,
PageBreak,
Address,
EmailAddress,
)
# 元素具有一致的結構
element.text # 原始文字內容
element.metadata # 豐富的元資料
element.category # 元素類型
element.id # 唯一識別碼
自動分割
from unstructured.partition.auto import partition
# 處理任何檔案類型
elements = partition(
filename="document.pdf",
strategy="auto", # 或 "fast", "hi_res", "ocr_only"
include_metadata=True,
include_page_breaks=True,
)
# 依類型篩選
titles = [e for e in elements if isinstance(e, Title)]
tables = [e for e in elements if isinstance(e, Table)]
特定格式分割
# PDF 搭配選項
from unstructured.partition.pdf import partition_pdf
elements = partition_pdf(
filename="document.pdf",
strategy="hi_res", # 高品質擷取
infer_table_structure=True, # 偵測表格
include_page_breaks=True,
languages=["en"], # OCR 語言
)
# Word 文件
from unstructured.partition.docx import partition_docx
elements = partition_docx(
filename="document.docx",
include_metadata=True,
)
# HTML
from unstructured.partition.html import partition_html
elements = partition_html(
filename="page.html",
include_metadata=True,
)
處理表格
from unstructured.partition.auto import partition
elements = partition("report.pdf", infer_table_structure=True)
# 擷取表格
for element in elements:
if element.category == "Table":
print("找到表格:")
print(element.text)
# 存取結構化表格資料
if hasattr(element, 'metadata') and element.metadata.text_as_html:
print("HTML:", element.metadata.text_as_html)
存取元資料
from unstructured.partition.auto import partition
elements = partition("document.pdf")
for element in elements:
meta = element.metadata
# 常見元資料欄位
print(f"頁碼:{meta.page_number}")
print(f"檔名:{meta.filename}")
print(f"檔案類型:{meta.filetype}")
print(f"座標:{meta.coordinates}")
print(f"語言:{meta.languages}")
為 AI/RAG 進行分塊
from unstructured.partition.auto import partition
from unstructured.chunking.title import chunk_by_title
from unstructured.chunking.basic import chunk_elements
# 分割文件
elements = partition("document.pdf")
# 依標題分塊(語意分塊)
chunks = chunk_by_title(
elements,
max_characters=1000,
combine_text_under_n_chars=200,
)
# 或基本分塊
chunks = chunk_elements(
elements,
max_characters=500,
overlap=50,
)
for chunk in chunks:
print(f"區塊({len(chunk.text)} 字元):")
print(chunk.text[:100] + "...")
批次處理
from unstructured.partition.auto import partition
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
def process_document(file_path):
"""處理單一文件。"""
try:
elements = partition(str(file_path))
return {
'file': str(file_path),
'status': 'success',
'elements': len(elements),
'text': '\n\n'.join([e.text for e in elements])
}
except Exception as e:
return {
'file': str(file_path),
'status': 'error',
'error': str(e)
}
def batch_process(input_dir, max_workers=4):
"""處理目錄中的所有文件。"""
input_path = Path(input_dir)
files = list(input_path.glob('*'))
with ThreadPoolExecutor(max_workers=max_workers) as executor:
results = list(executor.map(process_document, files))
return results
匯出格式
from unstructured.partition.auto import partition
from unstructured.staging.base import elements_to_json, elements_to_dicts
elements = partition("document.pdf")
# 轉為 JSON 字串
json_str = elements_to_json(elements)
# 轉為字典列表
dicts = elements_to_dicts(elements)
# 轉為 DataFrame
import pandas as pd
df = pd.DataFrame(dicts)
最佳實務
- 謹慎選擇策略:"fast" 追求速度,"hi_res" 追求準確度
- 啟用表格偵測:適用於含表格的文件
- 指定語言:非英文文件可獲得更好的 OCR 效果
- 為 RAG 分塊:AI 應用請使用語意分塊
- 處理錯誤:某些格式可能需優雅降級
常見模式
文件轉 JSON
def document_to_json(file_path, output_path=None):
"""將文件轉換為結構化 JSON。"""
from unstructured.partition.auto import partition
from unstructured.staging.base import elements_to_json
import json
elements = partition(file_path)
# 建立結構化輸出
output = {
'source': file_path,
'elements': []
}
for element in elements:
output['elements'].append({
'type': type(element).__name__,
'text': element.text,
'metadata': {
'page': element.metadata.page_number,
'coordinates': element.metadata.coordinates.to_dict() if element.metadata.coordinates else None
}
})
if output_path:
with open(output_path, 'w') as f:
json.dump(output, f, indent=2)
return output
郵件解析器
from unstructured.partition.email import partition_email
def parse_email(email_path):
"""從郵件中擷取結構化資料。"""
elements = partition_email(email_path)
email_data = {
'subject': None,
'from': None,
'to': [],
'date': None,
'body': [],
'attachments': []
}
for element in elements:
meta = element.metadata
# 從元資料中擷取標頭
if meta.subject:
email_data['subject'] = meta.subject
if meta.sent_from:
email_data['from'] = meta.sent_from
if meta.sent_to:
email_data['to'] = meta.sent_to
# 內文內容
email_data['body'].append({
'type': type(element).__name__,
'text': element.text
})
return email_data
範例
範例 1:研究論文擷取
from unstructured.partition.pdf import partition_pdf
from unstructured.chunking.title import chunk_by_title
def extract_paper(pdf_path):
"""從研究論文中擷取結構化資料。"""
elements = partition_pdf(
filename=pdf_path,
strategy="hi_res",
infer_table_structure=True,
include_page_breaks=True
)
paper = {
'title': None,
'abstract': None,
'sections': [],
'tables': [],
'references': []
}
# 尋找標題(通常是第一個 Title 元素)
for element in elements:
if element.category == "Title" and not paper['title']:
paper['title'] = element.text
break
# 擷取表格
for element in elements:
if element.category == "Table":
paper['tables'].append({
'page': element.metadata.page_number,
'content': element.text,
'html': element.metadata.text_as_html if hasattr(element.metadata, 'text_as_html') else None
})
# 依章節分塊
chunks = chunk_by_title(elements, max_characters=2000)
current_section = None
for chunk in chunks:
if chunk.category == "Title":
paper['sections'].append({
'title': chunk.text,
'content': ''
})
elif paper['sections']:
paper['sections'][-1]['content'] += chunk.text + '\n'
return paper
paper = extract_paper('research_paper.pdf')
print(f"標題:{paper['title']}")
print(f"表格數:{len(paper['tables'])}")
print(f"章節數:{len(paper['sections'])}")
範例 2:發票資料擷取
from unstructured.partition.auto import partition
import re
def extract_invoice_data(file_path):
"""從發票中擷取關鍵資料。"""
elements = partition(file_path, strategy="hi_res")
# 合併所有文字
full_text = '\n'.join([e.text for e in elements])
invoice = {
'invoice_number': None,
'date': None,
'total': None,
'vendor': None,
'line_items': [],
'tables': []
}
# 擷取模式
inv_match = re.search(r'發票\s*#?\s*:?\s*(\w+[-\w]*)', full_text, re.I)
if inv_match:
invoice['invoice_number'] = inv_match.group(1)
date_match = re.search(r'日期\s*:?\s*(\d{1,2}[-/]\d{1,2}[-/]\d{2,4})', full_text, re.I)
if date_match:
invoice['date'] = date_match.group(1)
total_match = re.search(r'總計\s*:?\s*\$?([\d,]+\.?\d*)', full_text, re.I)
if total_match:
invoice['total'] = float(total_match.group(1).replace(',', ''))
# 擷取表格
for element in elements:
if element.category == "Table":
invoice['tables'].append(element.text)
return invoice
invoice = extract_invoice_data('invoice.pdf')
print(f"發票號碼:{invoice['invoice_number']}")
print(f"總計:${invoice['total']}")
範例 3:文件語料庫建置器
from unstructured.partition.auto import partition
from unstructured.chunking.title import chunk_by_title
from pathlib import Path
import json
def build_corpus(input_dir, output_path):
"""從文件集合中建立可搜尋的語料庫。"""
input_path = Path(input_dir)
corpus = []
# 支援多種格式
patterns = ['*.pdf', '*.docx', '*.html', '*.txt', '*.md']
files = []
for pattern in patterns:
files.extend(input_path.glob(pattern))
for file in files:
print(f"處理中:{file.name}")
try:
elements = partition(str(file))
chunks = chunk_by_title(elements, max_characters=1000)
for i, chunk in enumerate(chunks):
corpus.append({
'id': f"{file.stem}_{i}",
'source': str(file),
'type': type(chunk).__name__,
'text': chunk.text,
'page': chunk.metadata.page_number if chunk.metadata.page_number else None
})
except Exception as e:
print(f" 錯誤:{e}")
# 儲存語料庫
with open(output_path, 'w') as f:
json.dump(corpus, f, indent=2)
print(f"語料庫建立完成:來自 {len(files)} 個檔案的 {len(corpus)} 個區塊")
return corpus
corpus = build_corpus('./documents', 'corpus.json')
限制
- 複雜版面可能需要人工檢視
- OCR 品質取決於圖片品質
- 大型檔案可能需要分塊處理
- 部分專有格式不受支援
- 雲端處理有 API 速率限制
安裝
# 基本安裝
pip install unstructured
# 包含所有相依套件
pip install "unstructured[all-docs]"
# 用於 PDF 處理
pip install "unstructured[pdf]"
# 用於特定格式
pip install "unstructured[docx,pptx,xlsx]"






