使用refextract提取参考文献:PDF转TXT再转回PDF的编码问题求助
我使用Python的refextract库从.docx和.pdf格式的报告中提取参考文献,发现将PDF转成TXT再转回PDF后,refextract的性能表现更好(推测是原始PDF由Word转换时引入了大量无效内容,转TXT再转回可清理这些内容),但过程中遇到了编码错误。
现有代码及问题
将PDF转为TXT的代码:
import fitz import glob import os pdf_files = glob.glob(path + r'\*.pdf') for pdf_file in pdf_files: with open(pdf_file[:-4]+'.txt', 'w', encoding='utf-8') as outfile: doc = fitz.open(pdf_file) for page in doc: outfile.write(page.get_text()) doc.close() os.remove(pdf_file)
将TXT转回PDF的代码:
from fpdf import FPDF import glob import os txt_files = glob.glob(path + r'\*.txt') for txt_file in txt_files: pdf=FPDF() doc=[] with open (txt_file, 'r', encoding='utf-8') as infile: print(txt_file) doc = infile.read() pdf.add_page() pdf.set_font('Arial', size=12) pdf.write(5, doc) pdf.output(txt_file[:-4]+'.pdf') os.remove(txt_file)
运行时出现错误:
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 120-121: ordinal not in range(256)
尝试将文本编码为latin-1时,又出现:
UnicodeEncodeError: 'latin-1' codec can't encode character '\u20ac' in position 44: ordinal not in range(256)
原始PDF中并无欧元符号,说明提取文本时引入了特殊字符。
解决思路
1. 使用支持UTF-8的FPDF版本(fpdf2)
旧版FPDF对UTF-8支持有限,默认使用latin-1编码。改用fpdf2(FPDF的升级版本),它原生支持UTF-8,还能加载支持特殊字符的字体。
首先安装依赖:
pip install fpdf2
修改后的转回PDF代码:
from fpdf import FPDF # fpdf2版本的导入方式和旧版一致,但内部支持UTF-8 import glob import os txt_files = glob.glob(path + r'\*.txt') for txt_file in txt_files: pdf = FPDF() # 添加支持UTF-8的字体,比如DejaVuSans(需确保字体文件存在,可从系统路径加载或下载至项目目录) pdf.add_font("DejaVuSans", "", "DejaVuSans.ttf", uni=True) with open(txt_file, 'r', encoding='utf-8') as infile: doc = infile.read() pdf.add_page() pdf.set_font('DejaVuSans', size=12) pdf.write(5, doc) pdf.output(txt_file[:-4]+'.pdf') os.remove(txt_file)
Windows环境下也可使用系统自带的SimSun或Microsoft YaHei等支持UTF-8的字体。
2. 预处理文本,过滤/替换特殊字符
如果不想更换库,可以预处理提取到的文本,将无法用latin-1编码的字符替换为相近的ASCII字符,或者直接移除。
示例代码:
import unicodedata from fpdf import FPDF import glob import os def clean_text(text): # 归一化字符,将特殊字符转为相近的ASCII格式 normalized = unicodedata.normalize('NFKD', text) # 过滤掉无法用latin-1编码的字符,也可将'ignore'改为'replace'用占位符替代 cleaned = normalized.encode('latin-1', 'ignore').decode('latin-1') return cleaned txt_files = glob.glob(path + r'\*.txt') for txt_file in txt_files: pdf=FPDF() with open (txt_file, 'r', encoding='utf-8') as infile: doc = infile.read() cleaned_doc = clean_text(doc) pdf.add_page() pdf.set_font('Arial', size=12) pdf.write(5, cleaned_doc) pdf.output(txt_file[:-4]+'.pdf') os.remove(txt_file)
3. 跳过TXT中转,直接清理PDF
既然转TXT再转回的目的是清理无效内容,不如直接用PyMuPDF(fitz)提取文本后直接生成新PDF,省去TXT中转步骤,从根源避免编码问题。
示例代码:
import fitz import glob import os pdf_files = glob.glob(path + r'\*.pdf') for pdf_file in pdf_files: # 打开原始PDF doc = fitz.open(pdf_file) # 创建新PDF文档 new_pdf = fitz.open() for page in doc: # 提取页面文本 text = page.get_text() # 创建与原页面尺寸一致的新页面 new_page = new_pdf.new_page(width=page.rect.width, height=page.rect.height) # 在新页面写入文本(可调整字体、字号、起始位置) new_page.insert_text((50, 50), text, fontsize=12, fontname="helv") # 保存清理后的PDF temp_path = pdf_file[:-4]+'_cleaned.pdf' new_pdf.save(temp_path) new_pdf.close() doc.close() # 替换原始PDF os.remove(pdf_file) os.rename(temp_path, pdf_file)
内容的提问来源于stack exchange,提问作者MaxJay

