Python实现PDF提取文字并统计词频
目录
- 一、PDF转图片
- 1、PDF转图片
- 2、OCR图片转文字
- 3、读取高频词
- 二、提取文字型PDF的文字
- 三、合并文字型PDF
- 四、图片型PDF转为word并合并
- 1、单进程模式
- 2、多进程模式
- 五、合并文件夹中的word
- 六、将整个图片转换为文字并写入pandas表
- 七、提取PDF部分页
通过统计词频来快速预览PDF报告。本文提供了文字PDF和图片PDF提取文字的两类方式。
对于是文字类的PDF可以快速的提取其中文字,但是有许多PDF是图片格式,并不能直接提取文字。本文采取PDF转图片,并通过OCR识别文字生成文本,进而统计文本的词频的方式进行快速预览。
一、PDF转图片
1、PDF转图片
本文使用PyMuPDF模块进行转化。
1、 PyMuPD网上有许多资料,但是多数比较老,这个模块的API已有变动,本文做了更新。本模块安装需要pip install PyMuPDF,但是导入是fitz。该库不支持python3.10以上版本。
2、本文加了文件路径处理的功能find_pdf_files(directory)函数和以下部分。
filename = os.path.basename(pdf) file_name, file_extension = os.path.splitext(filename) image_path = f"{imagePath}\{file_name}{pg}.jpg"
代码
import datetime import os import fitz #输出以.pdf结尾的文件的完整文件路径 def find_pdf_files(directory): pdf_files = [] for root, dirs, files in os.walk(directory): for file in files: if file.endswith('.pdf'): pdf_file_path = os.path.join(root, file) pdf_files.append(pdf_file_path) return pdf_files def pyMuPDF_fitz(pdf, imagePath): startTime_pdf2img = datetime.datetime.now() # 开始时间 print("imagePath=" + imagePath) pdfDoc = fitz.open(pdf) for pg in range(pdfDoc.page_count): page = pdfDoc[pg] rotate = int(0) # 每个尺寸的缩放系数为1.3,这将为我们生成分辨率提高2.6的图像。 python # 此处若是不做设置,默认图片大小为:792X612, dpi=96 zoom_x = 1.33333333 # (1.33333333-->1056x816) (2-->1584x1224) zoom_y = 1.33333333 mat = fitz.Matrix(zoom_x, zoom_y).prerotate(rotate) pix = page.get_pixmap(matrix=mat, alpha=False) if not os.path.exists(imagePath): # 判断存放图片的文件夹是否存在 os.makedirs(imagePath) # 若图片文件夹不存在就创建 # 提取不带扩展名的文件名 filename = os.path.basename(pdf) file_name, file_extension = os.path.splitext(filename) image_path = f"{imagePath}\{file_name}{pg}.jpg" pix.save(image_path) # 将图片写入指定的文件夹内 endTime_pdf2img = datetime.datetime.now() # 结束时间 print('pdf2img时间=', (endTime_pdf2img - startTime_pdf2img).seconds) if __name__ == "__main__": path=r"xx" flist=find_pdf_files(path) # 1、PDF地址 imagePath = r"xx" for pdf in flist: # 2、需要储存图片 的目录 pyMuPDF_fitz(pdf, imagePath)
2、OCR图片转文字
本文使用的是百度开源的paddleocr库
先pip3.10 install paddlepaddle再pip install paddleocr,注意这两个库暂时不支持python3.10以上的版本,主要是paddleocr依赖的PyMuPDF不支持python3.10以上版本。
将图片上指定区域转换为文字
from paddleocr import PaddleOCR import os import re #输出结果转字符串 def text_noposition(data, left, right, bottom, top): text_res = "" # data[0]包含位置和文本信息 for i in data[0]: # i[0][0][0]是横向,i[0][0][1]是位置的纵向 x, y = i[0][0][0], i[0][0][1] if left < x < right and bottom < y < top: # i[1][0]是文字 text_res = text_res + i[1][0] return text_res def convert_png_to_txt(dir_path,output_path): # 初始化PaddleOCR ocr = PaddleOCR(use_angle_cls=True, lang="ch") output_text = "" # 遍历指定目录下的所有.png文件 for filename in os.listdir(dir_path): if filename.endswith('.jpg'): file_path = os.path.join(dir_path, filename) # 使用PaddleOCR提取图片中的文本 result = ocr.ocr(file_path, cls=True) print(result) # 使用text_noposition函数处理提取的文本 processed_text = text_noposition(result, left=0, right=10000, bottom=500, top=2000) # 将处理后的文本追加到输出文本中 output_text += processed_text + "\n" # 将输出文本写入.txt文件并关闭该文件 with open(output_path, "a") as file: # 可以根据需要更改文件名和路径 file.write(output_text) # 指定要处理的图片的目录 dir_path = r'D:\data\2024\PDF\xx' # 文件输出路径 output_path = r'D:\data\2024\PDF\xx' convert_png_to_txt(dir_path,output_path)
将全部图片转换为文字
去掉了区域选择参数,也可以采样将选择区域函数中,区域设置为极端值,例如(0,10000,0,10000)
def text_noposition(data): text_res = "" # data[0]包含位置和文本信息 for i in data[0]: # i[1][0]是文字 text_res = text_res + i[1][0] return text_res def convert_png_to_txt(dir_path,output_path): # 初始化PaddleOCR ocr = PaddleOCR(use_angle_cls=True, lang="ch") output_text = "" # 遍历指定目录下的所有.png文件 for filename in os.listdir(dir_path): if filename.endswith('.jpg'): file_path = os.path.join(dir_path, filename) # 使用PaddleOCR提取图片中的文本 result = ocr.ocr(file_path, cls=True) print(result) # 使用text_noposition函数处理提取的文本 processed_text = text_noposition(result, left=0, right=10000, bottom=500, top=2000) # 将处理后的文本追加到输出文本中 output_text += processed_text + "\n" # 将输出文本写入.txt文件并关闭该文件 with open(output_path, "a") as file: # 可以根据需要更改文件名和路径 file.write(output_text)
3、读取高频词
读取结果、使用结巴分词,并统计词频。
视文件编码不同,如果报错gbk编码问题,打开文件部分需要改为:
f = open(file_path, encoding=‘utf-8’)
from collections import Counter import jieba import pandas as pd def cut_with_filter(sentence, stopwords): # 使用结巴分词的精确模式进行分词 seg_list = jieba.cut(sentence, cut_all=False) # 去除停用词 filtered_seg_list = [word for word in seg_list if word not in stopwords] return filtered_seg_list if __name__ == '__main__': file_path = r"D:\data\2023\pdf\pdf\结果.txt" # 要分词的文本 f = open(file_path) text = f.read() #text = read_doc_file(file_path) # 停用词列表,你可以根据需要自行添加或修改 stopwords = ["的", "了", "在", "是", "我", "有", "和", "就", "不", "人", "都", "一", "一个", "上", "也", "很", "到"] word_list=cut_with_filter(text,stopwords) chinese_list = [word for word in word_list if isinstance(word, str) and word.isalpha()] # 统计每个词的词频 counter = Counter(chinese_list) word_freq = dict(counter) keys = pd.Series(list(word_freq.keys())) values = pd.Series(list(word_freq.values())) # 将分词结果和词频保存到DataFrame df = pd.DataFrame({'词': keys, '词频': values}) print(df) # 将DataFrame保存到Excel文件 df.to_excel('分词结果1.xlsx', index=False)
二、提取文字型PDF的文字
使用PyMuPDF库可以快速提取文字型PDF的文字。本文做了封装。
1、转化单个文件,使用pdf2txt函数,输入路径是PDF文件的路径
2、转化一个文件夹下,使用 pdf2txt_multi函数,输入路径是PDF所在的文件夹
import fitz import os #转化单个文件 def pdf2txt(input_file,output_file): with fitz.open(input_file) as doc: text = php"" for page in dphpoc.pages(): text += page.get_text() # 注意这里使用了 get_text() 方法 with open(output_file, "w", encoding="utf-8") as f: f.write(text) return text def pdf2txt_multi(input_folder, output_file): # 遍历输入文件夹中的所有文件 for file_name in os.listdir(input_folder): if file_name.endswith(".pdf"): print(file_name) # 构建输入文件路径 input_file = os.path.join(input_folder, file_name) # 打开PDF文件,并写入txt文件 with fitz.open(input_file) as doc: text = "" for page in doc.pages(): text += page.get_text() # 注意这里使用了 get_text() 方法 with open(output_file, "w", encoding="utf-8") as f: f.write(text) return text if __name__ == "__main__": # 输入和输出文件路径,当要转化一个文件夹时是文件夹路径。 input_file =r"xx" output_file = "output.txt" pdf2txt_multi(input_file,output_file)
三、合并文字型PDF
使用python的fitz库将一个文件夹下的pdf合并成一个pdf
import os import fitz def merge_pdfs(pdf_folder, output_pdf_path): pdf_files = [f for f in os.listdir(pdf_folder) if f.endswith(".pdf")] # 创建一个新的PDF文件 merged_pdf = fitz.open() # 遍历每个PDF文件并将其插入到合并文件中 for pdf_file in pdf_files: pdf_path = os.path.join(pdf_folder, pdf_file) pdf = fitz.open(pdf_path) merged_pdf.insert_pdf(pdf) merged_pdf.save(output_pdf_path) merged_pdf.close() if __name__ == '__main__': # 获取文件夹下所有PDF文件的路径 pdf_folder = r"D:\工作\科创专班\资料\会议报告\2024研讨会" # 保存合并后的PDF文件 output_pdf_path = "output_merged_pdf.pdf" print(f"合并完成,保存为:{output_pdf_path}")
四、图片型PDF转为word并合并
1、单进程模式
import datetime import os import fitz from paddleocr import PaddleOCR from docx import Document # 输出以.pdf结尾的文件的完整文件路径 def find_pdf_files(directory): pdf_files = [] for root, dirs, files in os.walk(directory): for file in files: if file.endswith('.pdf'): pdf_file_path = os.path.join(root, file) pdf_files.append(pdf_file_path) return pdf_files def text_noposition(data, left, right, bottom, top): text_res = "" # data[0]包含位置和文本信息 for i in data[0]: # i[0][0][0]是横向,i[0][0][1]是位置的纵向 x, y = i[0][0][0], i[0][0][1] if left < x < right and bottom < y < top: # i[1][0]是文字 text_res = text_res + i[1][0] return text_res def pyMuPDF_fitz(pdf, image_folder_path): start_time_pdf2img = datetime.datetime.now() # 开始时间 pdf_doc = fitz.open(pdf) # 创建OCR模型 ocr = PaddleOCR(use_angle_cls=True, lang="ch") # 创建Word文档 doc = Document() for pg in range(pdf_doc.page_count): page = pdf_doc[pg] rotate = int(0) # 每个尺寸的缩放系数为1.3,这将为我们生成分辨率提高2.6的图像。 # 此处若是不做设置,默认图片大小为:792X612, dpi=96 zoom_x = 1.33333333 # (1.33333333-->1056x816) (2-->1584x1224) zoom_y = 1.33333333 mat = fitz.Matrix(zoom_x, zoom_y).prerotate(rotate) pix = page.get_pixmap(matrix=mat, alpha=False) if not os.path.exists(image_folder_path): # 判断存放图片的文件夹是否存在 os.makedirs(image_folder_path) # 若图片文件夹不存在就创建 # 提取不带扩展名的文件名 filename = os.path.basename(pdf) file_name, file_extension = os.path.splitext(filename) print(file_name,"页码",pg) image_path = f"{image_folder_path}\\{file_name}_{pg}.jpg" pix.save(image_path) # 将图片写入指定的文件夹内 # 识别图片中的文字 result = ocr.ocr(image_path) # 将识别结果写入Word文档 doc.add_paragraph(f"{file_name}") doc.add_paragraph(f"页码:{pg+1}") processed_text = text_noposition(result, left=0, right=10000, bottom=500, top=2000) doc.add_paragraph(processed_text) if not os.path.exists(word_path): # 判断存放word的文件夹是否存在 os.makedirs(word_path) # 若word文件夹不存在就创建 # 保存Word文档 doc_name = f"{file_name}.docx" doc_path=f"{word_path}\\{doc_name}" doc.save(doc_path) end_time_pdf2img = datetime.datetime.now() # 结束时间 print('pdf2img时间=', (end_time_pdf2img - start_time_pdf2img).seconds) return doc_name if __name__ == '__main__': # 测试 pdf_folder = r"D:\工作\科创专班\资料\会议报告\24年工作会" image_folder = r"xx" word_path = r"xx" pdf_files = find_pdf_files(pdf_folder) for pdf_file in pdf_files: pyMuPDF_fitz(pdf_file, image_folder)
2、多进程模式
多进程需要注意在每个进程内部import paddleocr包,否则无法序列化这个包导致程序无法运行。
def pyMuPDF_fitz(pdf, image_folder_path): from paddleocr import PaddleOCR
不能再开头导入包
import datetime import os import fitz #from paddleocr import PaddleOCR from joblib import Parallel, delayed from docx import Document # 输出以.pdf结尾的文件的完整文件路径 def find_pdf_files(directory): pdf_files = [] for root, dirs, files in os.walk(directory): for file in files: if file.endswith('.pdf'): pdf_file_path = os.path.join(root, file) pdf_files.append(pdf_file_path) return pdf_files def text_noposition(data, left, right, bottom, top): text_res = "" # data[0]包含位置和文本信息 for i in data[0]: # i[0][0][0]是横向,i[0][0][1]是位置的纵向 x, y = i[0][0][0], i[0][0][1] if left < x < right and bottom < y < top: # i[1][0]是文字 text_res = text_res + i[1][0] return text_res def pyMuPDF_fitz(pdf, image_folder_path): from paddleocr import PaddleOCR start_time_pdf2img = datetime.datetime.now() # 开始时间 pdf_doc = fitz.open(pdf) # 创建OCR模型 ocr = PaddleOCR(use_angle_cls=True, lang="ch") # 创建Word文档 doc = Document() for pg in range(pdf_doc.page_count): page = pdf_doc[pg] rotate = int(0) # 每个尺寸的缩放系数为1.3,这将为我们生成分辨率提高2.6的图像。 # 此处若是不做设置,默认图片大小为:792X612, dpi=96 zoom_x = 1.33333333 # (1.33333333-->1056x816) (2-->1584x1224) zoom_y = 1.33333333 mat = fitz.Matrix(zoom_x, zoom_y).prerotate(rotate) pix = page.get_pixmap(matrix=mat, alpha=False) if not os.path.exists(image_folder_path): # 判断存放图片的文件夹是否存在 os.makedirs(image_folder_path) # 若图片文件夹不存在就创建 # 提取不带扩展名的文件名 filename = os.path.basename(pdf) file_name, file_extension = os.path.splitext(filename) print(file_name,"页码",pg) image_path = f"{image_folder_path}\\{file_name}_{pg}.jpg" pix.save(image_path) # 将图片写入指定的文件夹内 # 识别图片中的文字 result = ocr.ocr(image_path) # 将识别结果写入Word文档 doc.add_paragraph(f"{file_name}") doc.add_paragrapandroidh(f"页码:{pg+1}") processed_text = text_noposition(result, left=0, right=10000, bottom=500, top=2000) doc.add_paragraph(processed_text) if not os.path.exists(word_path): # 判断存放word的文件夹是否存在 os.makedirs(word_path) # 若word文件夹不存在就创建 # 保存Word文档 doc_name = f"{file_name}.docx" doc_path=f"{word_path}\\{doc_name}" doc.save(doc_path) end_time_pdf2img = datetime.datetime.now() # 结束时间 print('pdf2img时间=', (end_time_pdf2img - start_time_pdf2img).seconds) return doc_name if __name__ == '__main__': # 测试 pdf_folder = r"D:\data\2024\会议报告\24年工作会" image_folder = r"D:\data\2024\picture" word_path = r"D:\data\2024\word" pdf_files = find_pdf_files(pdf_folder) # for pdf_file in pdf_files: # pyMuPDF_fitz(pdf_file, image_folder) #paddleocr不能序列化,不能使用 results = Parallel(n_jobs=-1,)( delayed(pyMuPDF_fitz)(pdf_file, image_folder) for pdf_file in pdf_files)
五、合并文件夹中的word
from docx import Document import os def merge_word_documents(folder_path, output_path): # 创建一个新的Word文档 merged_document = Document() # 遍历文件夹中的每个Word文档 for filename in os.listdir(folder_path): if filename.endswith(".docx"): file_path = os.path.join(folder_path, filename) # 打开当前的Word文档 current_document = Document(file_path) # 将当前文档的内容复制到合并文档中 for element in current_document.element.body: merged_document.element.body.append(element) # 保存合并后的文档 merged_document.save(output_path) # 程序入口 if __name__ == "__main__": folder_path = r"your_folder_path" output_path = r"output_folder/merged_document.docx" merge_word_documents(folder_path, output_path)
六、将整个图片转换为文字并写入pandas表
采用先把内如写入list,再把list转DataFrame的形式实现。
import os import pandas as pd from paddleocr import PaddleOCR from pandasrw import view #输出结果转字符串 def text_noposition(data): data_res = [] # data[0]包含位置和文本信息 for i in data[0]: # i[0][0][0]是横向,i[0][0][1]是位置的纵向 x, y = i[0][0][0], i[0][0][1] # i[1][0]是文字 data_res.append(i[1][0]) return data_res def convert_png_to_txt(dir_path): # 初始化PaddleOCR ocr = PaddleOCR(use_angle_cls=True, lang="ch") list_text =[] data_text=[] # 遍历指定目录下的所有.png文件 for filename in os.listdir(dir_path): if filename.endswith('.jpg'): file_path = os.path.join(dir_path, filename) # 使用PaddleOCR提取图片中的文本 result = ocr.ocr(file_path, cls=True) data_text = text_noposition(result) list_text=list_text+data_text print(list_text) # 创建 DataFrame 并写入数据 df = pd.DataFrame(list_text) return df # 指定要处理的图片的目录 dir_path = r"D:\data\2024\pic\d" df=convert_png_to_txt(dir_path) view(df)
七、提取PDF部分页
extract_phppages_to_new_pdf(input_path, output_path, [起始页, 结束页]) 提取开始到结束页的连续PDF,对于不连续的页面提取转换为多次连续的页面提取。
import fitz # PyMuPDF def extract_pages_to_new_pdf(input_pdf_path, output_pdf_path, page_numbers): # 打开原始PDF文件 pdf_doc = fitz.open(input_pdf_path) # 创建一个新的PDF文档对象 new_pdf = fitz.open() # 遍历要提取的页面索引 new_pdf.insert_pdf(pdf_doc, from_page=min(page_numbers), to_page=max(page_numbers)) # 保存新的PDF文件 new_pdf.save(output_pdf_path) # 关闭文档 pdf_doc.close() new_pdf.close() if __name__ == '__main__': input_path=r 文件名 output_path=r"" extract_pages_to_new_pdf(input_path, output_path, [25, 42])
到此这篇关于Python实现PDF提取文字并统计词频的文章就介绍到这了,更多相关Python PDF操作内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论