SKILL.md
唯讀
名稱
doc-parser
描述
使用 IBM 最先進的文件理解函式庫 **docling** 進行進階文件解析。解析複雜的 PDF、Word 文件和圖片,同時保留結構、擷取表格、圖形,並處理多欄佈局。
版本
1.0
文件解析技能
概述
本技能使用 docling(IBM 最先進的文件理解函式庫)進行進階文件解析。可解析複雜的 PDF、Word 文件和圖片,同時保留結構、擷取表格、圖形,並處理多欄佈局。
使用方式
- 提供要解析的文件
- 指定要擷取的內容(文字、表格、圖形等)
- 我將解析並回傳結構化資料
範例提示:
- "解析這份 PDF 並擷取所有表格"
- "將這篇學術論文轉換為結構化的 Markdown"
- "從這份文件中擷取圖形與標題"
- "解析這份報告並保留文件結構"
領域知識
docling 基礎
from docling.document_converter import DocumentConverter
# 初始化轉換器
converter = DocumentConverter()
# 轉換文件
result = converter.convert("document.pdf")
# 存取解析內容
doc = result.document
print(doc.export_to_markdown())
支援格式
| 格式 | 副檔名 | 備註 |
|---|---|---|
| 原生與掃描 | ||
| Word | .docx | 完整保留結構 |
| PowerPoint | .pptx | 投影片作為章節 |
| 圖片 | .png, .jpg | OCR + 版面分析 |
| HTML | .html | 保留結構 |
基本用法
from docling.document_converter import DocumentConverter
# 建立轉換器
converter = DocumentConverter()
# 轉換單一文件
result = converter.convert("report.pdf")
# 存取文件
doc = result.document
# 匯出選項
markdown = doc.export_to_markdown()
text = doc.export_to_text()
json_doc = doc.export_to_dict()
進階設定
from docling.document_converter import DocumentConverter
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import PdfPipelineOptions
# 設定管線
pipeline_options = PdfPipelineOptions()
pipeline_options.do_ocr = True
pipeline_options.do_table_structure = True
pipeline_options.table_structure_options.do_cell_matching = True
# 建立含選項的轉換器
converter = DocumentConverter(
allowed_formats=[InputFormat.PDF, InputFormat.DOCX],
pdf_backend_options=pipeline_options
)
result = converter.convert("document.pdf")
文件結構
# 文件階層
doc = result.document
# 存取元資料
print(doc.name)
print(doc.origin)
# 遍歷內容
for element in doc.iterate_items():
print(f"類型: {element.type}")
print(f"文字: {element.text}")
if element.type == "table":
print(f"列數: {len(element.data.table_cells)}")
擷取表格
from docling.document_converter import DocumentConverter
import pandas as pd
def extract_tables(doc_path):
"""從文件中擷取所有表格。"""
converter = DocumentConverter()
result = converter.convert(doc_path)
doc = result.document
tables = []
for element in doc.iterate_items():
if element.type == "table":
# 取得表格資料
table_data = element.export_to_dataframe()
tables.append({
'page': element.prov[0].page_no if element.prov else None,
'dataframe': table_data
})
return tables
# 使用方式
tables = extract_tables("report.pdf")
for i, table in enumerate(tables):
print(f"表格 {i+1} 位於第 {table['page']} 頁:")
print(table['dataframe'])
擷取圖形
def extract_figures(doc_path, output_dir):
"""擷取圖形與標題。"""
import os
converter = DocumentConverter()
result = converter.convert(doc_path)
doc = result.document
figures = []
os.makedirs(output_dir, exist_ok=True)
for element in doc.iterate_items():
if element.type == "picture":
figure_info = {
'caption': element.caption if hasattr(element, 'caption') else None,
'page': element.prov[0].page_no if element.prov else None,
}
# 若有圖片則儲存
if hasattr(element, 'image'):
img_path = os.path.join(output_dir, f"figure_{len(figures)+1}.png")
element.image.save(img_path)
figure_info['path'] = img_path
figures.append(figure_info)
return figures
處理多欄佈局
from docling.document_converter import DocumentConverter
def parse_multicolumn(doc_path):
"""解析多欄佈局的文件。"""
converter = DocumentConverter()
result = converter.convert(doc_path)
doc = result.document
# docling 自動處理欄位偵測
# 文字以閱讀順序回傳
structured_content = []
for element in doc.iterate_items():
content_item = {
'type': element.type,
'text': element.text if hasattr(element, 'text') else None,
'level': element.level if hasattr(element, 'level') else None,
}
# 若有邊界框則加入
if element.prov:
content_item['bbox'] = element.prov[0].bbox
content_item['page'] = element.prov[0].page_no
structured_content.append(content_item)
return structured_content
匯出格式
from docling.document_converter import DocumentConverter
converter = DocumentConverter()
result = converter.convert("document.pdf")
doc = result.document
# Markdown 匯出
markdown = doc.export_to_markdown()
with open("output.md", "w") as f:
f.write(markdown)
# 純文字
text = doc.export_to_text()
# JSON/dict 格式
json_doc = doc.export_to_dict()
# HTML 格式(若支援)
# html = doc.export_to_html()
批次處理
from docling.document_converter import DocumentConverter
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
def batch_parse(input_dir, output_dir, max_workers=4):
"""並行解析多份文件。"""
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(exist_ok=True)
converter = DocumentConverter()
def process_single(doc_path):
try:
result = converter.convert(str(doc_path))
md = result.document.export_to_markdown()
out_file = output_path / f"{doc_path.stem}.md"
with open(out_file, 'w') as f:
f.write(md)
return {'file': str(doc_path), 'status': 'success'}
except Exception as e:
return {'file': str(doc_path), 'status': 'error', 'error': str(e)}
docs = list(input_path.glob('*.pdf')) + list(input_path.glob('*.docx'))
with ThreadPoolExecutor(max_workers=max_workers) as executor:
results = list(executor.map(process_single, docs))
return results
最佳實務
- 使用適當管線:根據文件類型設定
- 處理大型文件:必要時分段處理
- 驗證表格擷取:複雜表格可能需要檢查
- 檢查 OCR 品質:掃描文件請啟用 OCR
- 快取結果:儲存解析後的文件以便重複使用
常見模式
學術論文解析器
def parse_academic_paper(pdf_path):
"""解析學術論文結構。"""
converter = DocumentConverter()
result = converter.convert(pdf_path)
doc = result.document
paper = {
'title': None,
'abstract': None,
'sections': [],
'references': [],
'tables': [],
'figures': []
}
current_section = None
for element in doc.iterate_items():
text = element.text if hasattr(element, 'text') else ''
if element.type == 'title':
paper['title'] = text
elif element.type == 'heading':
if 'abstract' in text.lower():
current_section = 'abstract'
elif 'reference' in text.lower():
current_section = 'references'
else:
paper['sections'].append({
'title': text,
'content': ''
})
current_section = 'section'
elif element.type == 'paragraph':
if current_section == 'abstract':
paper['abstract'] = text
elif current_section == 'section' and paper['sections']:
paper['sections'][-1]['content'] += text + '\n'
elif element.type == 'table':
paper['tables'].append({
'caption': element.caption if hasattr(element, 'caption') else None,
'data': element.export_to_dataframe() if hasattr(element, 'export_to_dataframe') else None
})
return paper
報告轉結構化資料
def parse_business_report(doc_path):
"""將商業報告解析為結構化格式。"""
converter = DocumentConverter()
result = converter.convert(doc_path)
doc = result.document
report = {
'metadata': {
'title': None,
'date': None,
'author': None
},
'executive_summary': None,
'sections': [],
'key_metrics': [],
'recommendations': []
}
# 解析文件結構
for element in doc.iterate_items():
# 根據文件結構實作解析邏輯
pass
return report
範例
範例 1:解析財務報告
from docling.document_converter import DocumentConverter
def parse_financial_report(pdf_path):
"""從財務報告中擷取結構化資料。"""
converter = DocumentConverter()
result = converter.convert(pdf_path)
doc = result.document
financial_data = {
'income_statement': None,
'balance_sheet': None,
'cash_flow': None,
'notes': []
}
# 擷取表格
tables = []
for element in doc.iterate_items():
if element.type == 'table':
table_df = element.export_to_dataframe()
# 識別表格類型
if 'revenue' in str(table_df).lower() or 'income' in str(table_df).lower():
financial_data['income_statement'] = table_df
elif 'asset' in str(table_df).lower() or 'liabilities' in str(table_df).lower():
financial_data['balance_sheet'] = table_df
elif 'cash' in str(table_df).lower():
financial_data['cash_flow'] = table_df
else:
tables.append(table_df)
# 擷取備註的 Markdown
financial_data['markdown'] = doc.export_to_markdown()
return financial_data
report = parse_financial_report('annual_report.pdf')
print("損益表:")
print(report['income_statement'])
範例 2:技術文件解析器
from docling.document_converter import DocumentConverter
def parse_technical_docs(doc_path):
"""解析技術文件。"""
converter = DocumentConverter()
result = converter.convert(doc_path)
doc = result.document
documentation = {
'title': None,
'version': None,
'sections': [],
'code_blocks': [],
'diagrams': []
}
current_section = None
for element in doc.iterate_items():
if element.type == 'title':
documentation['title'] = element.text
elif element.type == 'heading':
current_section = {
'title': element.text,
'level': element.level if hasattr(element, 'level') else 1,
'content': []
}
documentation['sections'].append(current_section)
elif element.type == 'code':
if current_section:
current_section['content'].append({
'type': 'code',
'content': element.text
})
documentation['code_blocks'].append(element.text)
elif element.type == 'picture':
documentation['diagrams'].append({
'page': element.prov[0].page_no if element.prov else None,
'caption': element.caption if hasattr(element, 'caption') else None
})
return documentation
docs = parse_technical_docs('api_documentation.pdf')
print(f"標題:{docs['title']}")
print(f"章節數:{len(docs['sections'])}")
範例 3:合約分析
from docling.document_converter import DocumentConverter
def analyze_contract(pdf_path):
"""解析合約文件以擷取關鍵條款。"""
converter = DocumentConverter()
result = converter.convert(pdf_path)
doc = result.document
contract = {
'parties': [],
'clauses': [],
'dates': [],
'amounts': [],
'full_text': doc.export_to_text()
}
import re
# 擷取日期
date_pattern = r'\b\d{1,2}[/-]\d{1,2}[/-]\d{2,4}\b|\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]* \d{1,2},? \d{4}\b'
contract['dates'] = re.findall(date_pattern, contract['full_text'], re.IGNORECASE)
# 擷取金額
amount_pattern = r'\$[\d,]+(?:\.\d{2})?|\b\d+(?:,\d{3})*(?:\.\d{2})?\s*(?:USD|dollars)\b'
contract['amounts'] = re.findall(amount_pattern, contract['full_text'], re.IGNORECASE)
# 將章節解析為條款
for element in doc.iterate_items():
if element.type == 'heading':
contract['clauses'].append({
'title': element.text,
'content': ''
})
elif element.type == 'paragraph' and contract['clauses']:
contract['clauses'][-1]['content'] += element.text + '\n'
return contract
contract_data = analyze_contract('agreement.pdf')
print(f"關鍵日期:{contract_data['dates']}")
print(f"金額:{contract_data['amounts']}")
限制
- 非常大的文件可能需要分段處理
- 手寫內容需要 OCR 前處理
- 複雜的巢狀表格可能需要手動檢查
- 某些 PDF 類型(如加密)不支援
- 建議使用 GPU 以獲得最佳效能
安裝
pip install docling
# 完整功能
pip install docling[all]
# OCR 支援
pip install docling[ocr]






