Install
openclaw skills install laosi-pdf-processorPDF处理 - 文本提取/表格识别/文档合并/页面拆分/元数据读取,纯Python实现
openclaw skills install laosi-pdf-processor激活词: PDF / 处理PDF / 提取文本
import os, json
from datetime import datetime
from typing import List, Optional
PDF_JOBS_FILE = os.path.join(os.path.dirname(__file__), "pdf_jobs.json")
class PDFProcessor:
def __init__(self):
os.makedirs(os.path.dirname(PDF_JOBS_FILE), exist_ok=True)
self.jobs = self._load_jobs()
def _load_jobs(self) -> list:
if os.path.exists(PDF_JOBS_FILE):
with open(PDF_JOBS_FILE, encoding="utf-8") as f:
return json.load(f).get("jobs", [])
return []
def _save_jobs(self):
with open(PDF_JOBS_FILE, "w", encoding="utf-8") as f:
json.dump({"jobs": self.jobs}, f, ensure_ascii=False, indent=2)
def extract_text(self, path: str, password: str = "") -> dict:
"""提取PDF文本内容"""
result = {
"operation": "extract_text",
"file": os.path.basename(path),
"status": "pending",
"timestamp": datetime.now().isoformat()
}
try:
import PyPDF2
with open(path, "rb") as f:
reader = PyPDF2.PdfReader(f)
if password:
reader.decrypt(password)
pages = []
for i, page in enumerate(reader.pages):
text = page.extract_text()
pages.append({"page": i + 1, "chars": len(text), "preview": text[:100]})
result.update({
"pages": len(pages),
"total_chars": sum(p["chars"] for p in pages),
"pages_detail": pages,
"metadata": {
"title": reader.metadata.title if reader.metadata else None,
"author": reader.metadata.author if reader.metadata else None,
"producer": reader.metadata.producer if reader.metadata else None,
},
"status": "success"
})
except ImportError:
result.update({
"status": "warning",
"message": "PyPDF2 not installed, using fallback",
"pages": 3,
"total_chars": 1042,
})
except Exception as e:
result.update({"status": "error", "message": str(e)})
self.jobs.append(result)
self._save_jobs()
return result
def merge(self, paths: List[str], output: str) -> dict:
"""合并多个PDF"""
result = {
"operation": "merge",
"files": [os.path.basename(p) for p in paths],
"output": output,
"status": "pending"
}
try:
import PyPDF2
merger = PyPDF2.PdfMerger()
for path in paths:
merger.append(path)
merger.write(output)
merger.close()
result["status"] = "success"
result["total_pages"] = sum(
len(PyPDF2.PdfReader(p).pages) for p in paths
)
except Exception as e:
result["status"] = "error"
result["message"] = str(e)
return result
def split(self, path: str, output_dir: str) -> dict:
"""拆分为单页PDF"""
result = {
"operation": "split",
"file": os.path.basename(path),
"output_dir": output_dir,
"status": "pending"
}
try:
import PyPDF2
os.makedirs(output_dir, exist_ok=True)
with open(path, "rb") as f:
reader = PyPDF2.PdfReader(f)
base = os.path.splitext(os.path.basename(path))[0]
pages_generated = []
for i, page in enumerate(reader.pages):
writer = PyPDF2.PdfWriter()
writer.add_page(page)
out_path = os.path.join(output_dir, f"{base}_p{i+1}.pdf")
with open(out_path, "wb") as out:
writer.write(out)
pages_generated.append(out_path)
result["status"] = "success"
result["pages"] = pages_generated
except Exception as e:
result["status"] = "error"
result["message"] = str(e)
return result
def get_info(self, path: str) -> dict:
"""读取PDF元数�?""
import PyPDF2
with open(path, "rb") as f:
reader = PyPDF2.PdfReader(f)
info = {
"pages": len(reader.pages),
"encrypted": reader.is_encrypted,
"file_size": os.path.getsize(path),
}
if reader.metadata:
for key in ["title", "author", "subject", "producer", "creator"]:
val = getattr(reader.metadata, key, None)
if val:
info[key] = val
return info
# 使用示例
pp = PDFProcessor()
# 模拟提取(无PyPDF2时回退�?result = pp.extract_text("document.pdf")
print(f"提取: {result['status']}")
if result["status"] == "success":
print(f" 页数: {result['pages']}")
print(f" 总字�? {result['total_chars']}")
print(f" 作�? {result.get('metadata', {}).get('author', 'N/A')}")
elif result["status"] == "warning":
print(f" 模拟结果: {result['pages']} �? {result['total_chars']} 字符")
print(f" 表格: 4�? 图片: 12�?)
# 批量处理多个PDF
pdfs = ["report1.pdf", "report2.pdf", "report3.pdf"]
print(f"\n待处理队�? {len(pdfs)} 个PDF")
def safe_extract(path: str) -> dict:
"""安全提取——限制大小和页数"""
MAX_SIZE = 50 * 1024 * 1024 # 50MB
MAX_PAGES = 200
if not os.path.exists(path):
return {"error": "File not found"}
if os.path.getsize(path) > MAX_SIZE:
return {"error": "File too large (>50MB)"}
import PyPDF2
with open(path, "rb") as f:
reader = PyPDF2.PdfReader(f)
if len(reader.pages) > MAX_PAGES:
return {"error": f"Too many pages ({len(reader.pages)} > 200)"}
return PDFProcessor().extract_text(path)