table-extractor by claude-office-skills/skills
npx skills add https://github.com/claude-office-skills/skills --skill table-extractor此技能使用 camelot(PDF表格提取的黄金标准)实现从PDF文档中精确提取表格。能够高精度处理包含合并单元格的复杂表格、无边框表格以及多页布局。
示例提示:
import camelot
# 从PDF提取表格
tables = camelot.read_pdf('document.pdf')
# 访问结果
print(f"Found {len(tables)} tables")
# 获取第一个表格作为DataFrame
df = tables[0].df
print(df)
| 方法 | 使用场景 | 描述 |
|---|---|---|
lattice | 有边框表格 | 通过线条/边框检测表格 |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
stream | 无边框表格 | 使用文本定位 |
# Lattice方法(默认)- 用于有可见边框的表格
tables = camelot.read_pdf('document.pdf', flavor='lattice')
# Stream方法 - 用于无边框表格
tables = camelot.read_pdf('document.pdf', flavor='stream')
# 单页
tables = camelot.read_pdf('document.pdf', pages='1')
# 多页
tables = camelot.read_pdf('document.pdf', pages='1,3,5')
# 页面范围
tables = camelot.read_pdf('document.pdf', pages='1-5')
# 所有页面
tables = camelot.read_pdf('document.pdf', pages='all')
tables = camelot.read_pdf(
'document.pdf',
flavor='lattice',
line_scale=40, # 线条检测灵敏度
copy_text=['h', 'v'], # 跨合并单元格复制文本
shift_text=['l', 't'], # 文本对齐偏移
split_text=True, # 在换行处拆分文本
flag_size=True, # 标记上标/下标
strip_text='\n', # 要剥离的字符
process_background=False, # 处理背景线条
)
tables = camelot.read_pdf(
'document.pdf',
flavor='stream',
edge_tol=500, # 边缘容差
row_tol=10, # 行容差
column_tol=0, # 列容差
strip_text='\n', # 要剥离的字符
)
# 从特定区域提取(x1, y1, x2, y2)
# 坐标从左下角开始,以PDF点为单位(72点 = 1英寸)
tables = camelot.read_pdf(
'document.pdf',
table_areas=['72,720,540,400'], # 一个区域
)
# 多个区域
tables = camelot.read_pdf(
'document.pdf',
table_areas=['72,720,540,400', '72,380,540,200'],
)
# 手动指定列位置(用于stream方法)
tables = camelot.read_pdf(
'document.pdf',
flavor='stream',
columns=['100,200,300,400'], # 列分隔符的X位置
)
import camelot
tables = camelot.read_pdf('document.pdf')
for i, table in enumerate(tables):
# 访问DataFrame
df = table.df
# 表格元数据
print(f"Table {i+1}:")
print(f" Page: {table.page}")
print(f" Accuracy: {table.accuracy}")
print(f" Whitespace: {table.whitespace}")
print(f" Order: {table.order}")
print(f" Shape: {df.shape}")
# 解析报告
report = table.parsing_report
print(f" Report: {report}")
import camelot
tables = camelot.read_pdf('document.pdf')
# 导出为CSV
tables[0].to_csv('table.csv')
# 导出为Excel
tables[0].to_excel('table.xlsx')
# 导出为JSON
tables[0].to_json('table.json')
# 导出为HTML
tables[0].to_html('table.html')
# 导出所有表格
for i, table in enumerate(tables):
table.to_excel(f'table_{i+1}.xlsx')
import camelot
# 启用可视化调试
tables = camelot.read_pdf('document.pdf')
# 绘制检测到的表格区域
camelot.plot(tables[0], kind='contour').show()
# 绘制表格上的文本
camelot.plot(tables[0], kind='text').show()
# 绘制检测到的线条(仅限lattice)
camelot.plot(tables[0], kind='joint').show()
camelot.plot(tables[0], kind='line').show()
# 保存绘图
fig = camelot.plot(tables[0])
fig.savefig('debug.png')
import camelot
import pandas as pd
def extract_multipage_table(pdf_path, pages='all'):
"""提取并合并跨越多页的表格。"""
tables = camelot.read_pdf(pdf_path, pages=pages)
# 按相似结构(列)分组表格
table_groups = {}
for table in tables:
cols = tuple(table.df.columns)
if cols not in table_groups:
table_groups[cols] = []
table_groups[cols].append(table.df)
# 合并相似表格
combined = []
for cols, dfs in table_groups.items():
if len(dfs) > 1:
# 合并并去重标题行
combined_df = pd.concat(dfs, ignore_index=True)
combined.append(combined_df)
else:
combined.append(dfs[0])
return combined
import camelot
from pathlib import Path
import pandas as pd
def batch_extract_tables(input_dir, output_dir):
"""从目录中的所有PDF提取表格。"""
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(exist_ok=True)
results = []
for pdf_file in input_path.glob('*.pdf'):
try:
tables = camelot.read_pdf(str(pdf_file), pages='all')
for i, table in enumerate(tables):
# 跳过低准确度表格
if table.accuracy < 80:
continue
output_file = output_path / f"{pdf_file.stem}_table_{i+1}.xlsx"
table.to_excel(str(output_file))
results.append({
'source': str(pdf_file),
'table': i + 1,
'page': table.page,
'accuracy': table.accuracy,
'output': str(output_file)
})
except Exception as e:
results.append({
'source': str(pdf_file),
'error': str(e)
})
return results
import camelot
def smart_extract_tables(pdf_path, pages='1'):
"""尝试两种方法并返回最佳结果。"""
# 先尝试lattice
lattice_tables = camelot.read_pdf(pdf_path, pages=pages, flavor='lattice')
# 尝试stream
stream_tables = camelot.read_pdf(pdf_path, pages=pages, flavor='stream')
# 比较并返回最佳
results = []
if lattice_tables and lattice_tables[0].accuracy > 70:
results.extend(lattice_tables)
elif stream_tables:
results.extend(stream_tables)
return results
import camelot
import pandas as pd
def extract_financial_tables(pdf_path):
"""从年度报告中提取财务报表。"""
# 提取所有表格
tables = camelot.read_pdf(pdf_path, pages='all', flavor='lattice')
financial_data = {
'income_statement': None,
'balance_sheet': None,
'cash_flow': None,
'other_tables': []
}
for table in tables:
df = table.df
text = df.to_string().lower()
# 识别表格类型
if 'revenue' in text or 'sales' in text:
if 'operating income' in text or 'net income' in text:
financial_data['income_statement'] = df
elif 'asset' in text and 'liabilities' in text:
financial_data['balance_sheet'] = df
elif 'cash flow' in text or 'operating activities' in text:
financial_data['cash_flow'] = df
else:
financial_data['other_tables'].append({
'page': table.page,
'data': df,
'accuracy': table.accuracy
})
return financial_data
financials = extract_financial_tables('annual_report.pdf')
if financials['income_statement'] is not None:
print("Income Statement found:")
print(financials['income_statement'])
import camelot
import pandas as pd
def extract_research_data(pdf_path, pages='all'):
"""从研究论文中提取数据表格。"""
# 尝试lattice处理有边框表格
tables = camelot.read_pdf(pdf_path, pages=pages, flavor='lattice')
if not tables or all(t.accuracy < 70 for t in tables):
# 回退到stream处理无边框表格
tables = camelot.read_pdf(pdf_path, pages=pages, flavor='stream')
extracted_data = []
for table in tables:
df = table.df
# 清理DataFrame
# 如果第一行看起来像表头,则将其设为表头
if not df.iloc[0].str.contains(r'\d').any():
df.columns = df.iloc[0]
df = df[1:]
df = df.reset_index(drop=True)
extracted_data.append({
'page': table.page,
'accuracy': table.accuracy,
'data': df
})
return extracted_data
data = extract_research_data('research_paper.pdf')
for i, item in enumerate(data):
print(f"Table {i+1} (Page {item['page']}, Accuracy: {item['accuracy']}%):")
print(item['data'].head())
import camelot
def extract_invoice_items(pdf_path):
"""从发票中提取行项目。"""
# 通常发票有边框表格
tables = camelot.read_pdf(pdf_path, flavor='lattice')
line_items = []
for table in tables:
df = table.df
# 查找典型的发票列
header_text = ' '.join(df.iloc[0].astype(str)).lower()
if any(term in header_text for term in ['quantity', 'qty', 'amount', 'price', 'description']):
# 这看起来像行项目表格
df.columns = df.iloc[0]
df = df[1:]
for _, row in df.iterrows():
item = {}
for col in df.columns:
col_lower = str(col).lower()
value = row[col]
if 'desc' in col_lower or 'item' in col_lower:
item['description'] = value
elif 'qty' in col_lower or 'quantity' in col_lower:
item['quantity'] = value
elif 'price' in col_lower or 'rate' in col_lower:
item['unit_price'] = value
elif 'amount' in col_lower or 'total' in col_lower:
item['amount'] = value
if item:
line_items.append(item)
return line_items
items = extract_invoice_items('invoice.pdf')
for item in items:
print(item)
import camelot
import pandas as pd
def compare_pdf_tables(pdf1_path, pdf2_path):
"""比较两个PDF版本之间的表格。"""
tables1 = camelot.read_pdf(pdf1_path)
tables2 = camelot.read_pdf(pdf2_path)
comparisons = []
# 按形状和位置匹配表格
for t1 in tables1:
best_match = None
best_score = 0
for t2 in tables2:
if t1.df.shape == t2.df.shape:
# 计算相似度
try:
similarity = (t1.df == t2.df).mean().mean()
if similarity > best_score:
best_score = similarity
best_match = t2
except:
pass
if best_match:
comparisons.append({
'page1': t1.page,
'page2': best_match.page,
'similarity': best_score,
'identical': best_score == 1.0,
'diff': pd.DataFrame(t1.df != best_match.df)
})
return comparisons
comparison = compare_pdf_tables('report_v1.pdf', 'report_v2.pdf')
pip install camelot-py[cv]
# 额外依赖
# macOS
brew install ghostscript tcl-tk
# Ubuntu
apt-get install ghostscript python3-tk
每周安装数
20
仓库
GitHub星标数
5
首次出现
1天前
安全审计
安装于
claude-code18
opencode4
gemini-cli4
github-copilot4
codex4
amp4
This skill enables precise extraction of tables from PDF documents using camelot - the gold standard for PDF table extraction. Handle complex tables with merged cells, borderless tables, and multi-page layouts with high accuracy.
Example prompts:
import camelot
# Extract tables from PDF
tables = camelot.read_pdf('document.pdf')
# Access results
print(f"Found {len(tables)} tables")
# Get first table as DataFrame
df = tables[0].df
print(df)
| Method | Use Case | Description |
|---|---|---|
lattice | Bordered tables | Detects table by lines/borders |
stream | Borderless tables | Uses text positioning |
# Lattice method (default) - for tables with visible borders
tables = camelot.read_pdf('document.pdf', flavor='lattice')
# Stream method - for borderless tables
tables = camelot.read_pdf('document.pdf', flavor='stream')
# Single page
tables = camelot.read_pdf('document.pdf', pages='1')
# Multiple pages
tables = camelot.read_pdf('document.pdf', pages='1,3,5')
# Page range
tables = camelot.read_pdf('document.pdf', pages='1-5')
# All pages
tables = camelot.read_pdf('document.pdf', pages='all')
tables = camelot.read_pdf(
'document.pdf',
flavor='lattice',
line_scale=40, # Line detection sensitivity
copy_text=['h', 'v'], # Copy text across merged cells
shift_text=['l', 't'], # Shift text alignment
split_text=True, # Split text at newlines
flag_size=True, # Flag super/subscripts
strip_text='\n', # Characters to strip
process_background=False, # Process background lines
)
tables = camelot.read_pdf(
'document.pdf',
flavor='stream',
edge_tol=500, # Edge tolerance
row_tol=10, # Row tolerance
column_tol=0, # Column tolerance
strip_text='\n', # Characters to strip
)
# Extract from specific area (x1, y1, x2, y2)
# Coordinates from bottom-left, in PDF points (72 points = 1 inch)
tables = camelot.read_pdf(
'document.pdf',
table_areas=['72,720,540,400'], # One area
)
# Multiple areas
tables = camelot.read_pdf(
'document.pdf',
table_areas=['72,720,540,400', '72,380,540,200'],
)
# Manually specify column positions (for stream method)
tables = camelot.read_pdf(
'document.pdf',
flavor='stream',
columns=['100,200,300,400'], # X positions of column separators
)
import camelot
tables = camelot.read_pdf('document.pdf')
for i, table in enumerate(tables):
# Access DataFrame
df = table.df
# Table metadata
print(f"Table {i+1}:")
print(f" Page: {table.page}")
print(f" Accuracy: {table.accuracy}")
print(f" Whitespace: {table.whitespace}")
print(f" Order: {table.order}")
print(f" Shape: {df.shape}")
# Parsing report
report = table.parsing_report
print(f" Report: {report}")
import camelot
tables = camelot.read_pdf('document.pdf')
# Export to CSV
tables[0].to_csv('table.csv')
# Export to Excel
tables[0].to_excel('table.xlsx')
# Export to JSON
tables[0].to_json('table.json')
# Export to HTML
tables[0].to_html('table.html')
# Export all tables
for i, table in enumerate(tables):
table.to_excel(f'table_{i+1}.xlsx')
import camelot
# Enable visual debugging
tables = camelot.read_pdf('document.pdf')
# Plot detected table areas
camelot.plot(tables[0], kind='contour').show()
# Plot text on table
camelot.plot(tables[0], kind='text').show()
# Plot detected lines (lattice only)
camelot.plot(tables[0], kind='joint').show()
camelot.plot(tables[0], kind='line').show()
# Save plot
fig = camelot.plot(tables[0])
fig.savefig('debug.png')
import camelot
import pandas as pd
def extract_multipage_table(pdf_path, pages='all'):
"""Extract and combine tables that span multiple pages."""
tables = camelot.read_pdf(pdf_path, pages=pages)
# Group tables by similar structure (columns)
table_groups = {}
for table in tables:
cols = tuple(table.df.columns)
if cols not in table_groups:
table_groups[cols] = []
table_groups[cols].append(table.df)
# Combine similar tables
combined = []
for cols, dfs in table_groups.items():
if len(dfs) > 1:
# Combine and deduplicate header rows
combined_df = pd.concat(dfs, ignore_index=True)
combined.append(combined_df)
else:
combined.append(dfs[0])
return combined
import camelot
from pathlib import Path
import pandas as pd
def batch_extract_tables(input_dir, output_dir):
"""Extract tables from all PDFs in directory."""
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(exist_ok=True)
results = []
for pdf_file in input_path.glob('*.pdf'):
try:
tables = camelot.read_pdf(str(pdf_file), pages='all')
for i, table in enumerate(tables):
# Skip low accuracy tables
if table.accuracy < 80:
continue
output_file = output_path / f"{pdf_file.stem}_table_{i+1}.xlsx"
table.to_excel(str(output_file))
results.append({
'source': str(pdf_file),
'table': i + 1,
'page': table.page,
'accuracy': table.accuracy,
'output': str(output_file)
})
except Exception as e:
results.append({
'source': str(pdf_file),
'error': str(e)
})
return results
import camelot
def smart_extract_tables(pdf_path, pages='1'):
"""Try both methods and return best results."""
# Try lattice first
lattice_tables = camelot.read_pdf(pdf_path, pages=pages, flavor='lattice')
# Try stream
stream_tables = camelot.read_pdf(pdf_path, pages=pages, flavor='stream')
# Compare and return best
results = []
if lattice_tables and lattice_tables[0].accuracy > 70:
results.extend(lattice_tables)
elif stream_tables:
results.extend(stream_tables)
return results
import camelot
import pandas as pd
def extract_financial_tables(pdf_path):
"""Extract financial tables from annual report."""
# Extract all tables
tables = camelot.read_pdf(pdf_path, pages='all', flavor='lattice')
financial_data = {
'income_statement': None,
'balance_sheet': None,
'cash_flow': None,
'other_tables': []
}
for table in tables:
df = table.df
text = df.to_string().lower()
# Identify table type
if 'revenue' in text or 'sales' in text:
if 'operating income' in text or 'net income' in text:
financial_data['income_statement'] = df
elif 'asset' in text and 'liabilities' in text:
financial_data['balance_sheet'] = df
elif 'cash flow' in text or 'operating activities' in text:
financial_data['cash_flow'] = df
else:
financial_data['other_tables'].append({
'page': table.page,
'data': df,
'accuracy': table.accuracy
})
return financial_data
financials = extract_financial_tables('annual_report.pdf')
if financials['income_statement'] is not None:
print("Income Statement found:")
print(financials['income_statement'])
import camelot
import pandas as pd
def extract_research_data(pdf_path, pages='all'):
"""Extract data tables from research paper."""
# Try lattice for bordered tables
tables = camelot.read_pdf(pdf_path, pages=pages, flavor='lattice')
if not tables or all(t.accuracy < 70 for t in tables):
# Fall back to stream for borderless
tables = camelot.read_pdf(pdf_path, pages=pages, flavor='stream')
extracted_data = []
for table in tables:
df = table.df
# Clean up the DataFrame
# Set first row as header if it looks like one
if not df.iloc[0].str.contains(r'\d').any():
df.columns = df.iloc[0]
df = df[1:]
df = df.reset_index(drop=True)
extracted_data.append({
'page': table.page,
'accuracy': table.accuracy,
'data': df
})
return extracted_data
data = extract_research_data('research_paper.pdf')
for i, item in enumerate(data):
print(f"Table {i+1} (Page {item['page']}, Accuracy: {item['accuracy']}%):")
print(item['data'].head())
import camelot
def extract_invoice_items(pdf_path):
"""Extract line items from invoice."""
# Usually invoices have bordered tables
tables = camelot.read_pdf(pdf_path, flavor='lattice')
line_items = []
for table in tables:
df = table.df
# Look for table with typical invoice columns
header_text = ' '.join(df.iloc[0].astype(str)).lower()
if any(term in header_text for term in ['quantity', 'qty', 'amount', 'price', 'description']):
# This looks like a line items table
df.columns = df.iloc[0]
df = df[1:]
for _, row in df.iterrows():
item = {}
for col in df.columns:
col_lower = str(col).lower()
value = row[col]
if 'desc' in col_lower or 'item' in col_lower:
item['description'] = value
elif 'qty' in col_lower or 'quantity' in col_lower:
item['quantity'] = value
elif 'price' in col_lower or 'rate' in col_lower:
item['unit_price'] = value
elif 'amount' in col_lower or 'total' in col_lower:
item['amount'] = value
if item:
line_items.append(item)
return line_items
items = extract_invoice_items('invoice.pdf')
for item in items:
print(item)
import camelot
import pandas as pd
def compare_pdf_tables(pdf1_path, pdf2_path):
"""Compare tables between two PDF versions."""
tables1 = camelot.read_pdf(pdf1_path)
tables2 = camelot.read_pdf(pdf2_path)
comparisons = []
# Match tables by shape and position
for t1 in tables1:
best_match = None
best_score = 0
for t2 in tables2:
if t1.df.shape == t2.df.shape:
# Calculate similarity
try:
similarity = (t1.df == t2.df).mean().mean()
if similarity > best_score:
best_score = similarity
best_match = t2
except:
pass
if best_match:
comparisons.append({
'page1': t1.page,
'page2': best_match.page,
'similarity': best_score,
'identical': best_score == 1.0,
'diff': pd.DataFrame(t1.df != best_match.df)
})
return comparisons
comparison = compare_pdf_tables('report_v1.pdf', 'report_v2.pdf')
pip install camelot-py[cv]
# Additional dependencies
# macOS
brew install ghostscript tcl-tk
# Ubuntu
apt-get install ghostscript python3-tk
Weekly Installs
20
Repository
GitHub Stars
5
First Seen
1 day ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
claude-code18
opencode4
gemini-cli4
github-copilot4
codex4
amp4
Python PDF处理教程:合并拆分、提取文本表格、创建PDF文件
55,400 周安装