PDF文档导出指定章节为TXT

需求

要导出3000多个pdf文档的特定章节内容为txt格式(pdf文字可复制)。

解决

导出PDF

查了一下Python操作PDF文档的方法,主要是通过3个库,PyPDF2、pdfminer和pdfplumber。

  • PyPDF2 是一个纯 Python PDF 库,可以读取文档信息(标题,作者等)、写入、分割、合并PDF文档,它还可以对pdf文档进行添加水印、加密解密等。

  • pdfplumber 是基于 pdfminer.six 开发的模块,pdfplumber库按页处理 pdf ,获取页面文字,提取表格等操作。

  • pdfminer 使用门槛较高,但遇到复杂情况,最后还得用它。目前开源模块中,它对PDF的支持应该是最全的了。

看网上的例子,pdfminer是用得比较多的,然后直接复制了之前的代码并修改了一下变量名啥的:

# 解析pdf文件函数
def parse(pdf_path):
with open(r'C:\Users\Desktop\\' + pdf_path, 'rb') as pdf_file: # 以二进制读模式打开
# 用文件对象来创建一个pdf文档分析器
pdf_parser = PDFParser(pdf_file)
# 创建一个PDF文档
pdf_doc = PDFDocument(pdf_parser)
# 检测文档是否提供txt转换,不提供就忽略
if pdf_doc.is_extractable:
# 创建PDf 资源管理器 来管理共享资源
pdf_rm = PDFResourceManager()
# 创建一个PDF设备对象
pdf_lap = LAParams()
pdf_pa = PDFPageAggregator(pdf_rm, laparams=pdf_lap)
# 创建一个PDF解释器对象
interpreter = PDFPageInterpreter(pdf_rm, pdf_pa)
# 循环遍历列表,每次处理一个page的内容
for page in PDFPage.create_pages(pdf_doc): # doc.get_pages() 获取page列表
interpreter.process_page(page)
# 接受该页面的LTPage对象
layout = pdf_pa.get_result()
for x in layout:
if isinstance(x, LTTextBoxHorizontal): # 获取文本内容
# 保存文本内容
with open(os.path.basename(pdf_path) + '.txt', 'a', encoding='utf-8') as f: # 生成doc文件的文件名及路径
results = x.get_text()
f.write(results)
f.write('\n')

运行一下发现很慢,一张页面要很久。因此不能全部导出之后再裁剪,而是找到指定的页面之后再导出,那么找到指定页面只能是通过目录,或者边导出边扫描,发现我们已经导出了所需的内容后面就不需要再导出了。最后,30000多个的文档运行到一半电脑关机了再重新导出肯定很麻烦,所以还要保存一下导出状态等信息。

还好,每个文档都有目录,那我们可以解析目录来获取指定页。

根据目录获取指定页

百度了一下Python获取pdf的指定页,获取pdf的目录,发现用的是PyPDF2来完成的,于是就对PyPDF2进行研究,通过其官网发现,它有获取目录的能力,可以直接导出目录及对应的页码。

for index, file_path in enumerate(files_list):
start_page_number = 0 # 开始页码
is_get_page_number_range = False info = update_file_info(file_path=file_path)
with open(file_path, 'rb') as pdf_file: # 读取pdf文档
pdf = PdfFileReader(pdf_file) # 加载pdf文档
if pdf.isEncrypted:
pdf.decrypt('') # 解密
end_page_number = pdf.getNumPages() # 获取总页码
info = update_file_info(info, page_count=end_page_number) # 保存总页数
pdf_directory = pdf.getOutlines() # 获取目录 is_have_start_page_number = False
for destination in pdf_directory:
if isinstance(destination, dict):
if is_have_start_page_number:
end_page_number = pdf.getDestinationPageNumber(destination)
is_get_page_number_range = True
break title = destination.get('/Title')
if key_word in str(title):
# 在目录中找到关键词了
start_page_number = pdf.getDestinationPageNumber(destination)
is_have_start_page_number = True
continue
if is_get_page_number_range:
info = update_file_info(info, start_page_number=start_page_number, end_page_number=end_page_number,
is_have_directory=True)
res = "获取页码成功"
else:
info = update_file_info(info, is_have_directory=False)
res = "获取页码失败"
print("扫描进度 : {:.2f}%, 文件 : {}".format(index / len(files_list) * 100, os.path.basename(file_path)), res, ':',
'[', start_page_number, ',', end_page_number, ']', end=end)

比较重要的就是getOutlines()函数和getDestinationPageNumber(destination)函数,分别是获取目录对象,以及根据目录对象获取页数。

这样,就把目标页码找出了,有不能直接在pdf查看器里目录那里点跳转的是扫描不出的,要另外想办法。

导出

先是使用PyPDF2导出文档。但是使用PyPDF2导出文本的时候导出的是乱码,使用的是unicode编码,暂时没找到转换的方法,网友说是其年代久远,对中文支持不好,网上一般配合pdfplumber使用,pdfplumber好像有OCR能力,安装的时候要安装一个图形库,安装了很久安装不上就放弃了pdfplumber。但是pdfminer我不会获取目录,那就只能两个库配合使用了。

首先是使用PyPDF2扫描一下目录,这个非常快,然后把配置信息保存在json文件中,然后再由pdfminer提取对应页文档。对于没有跳转目录的,可以逐页分析,找到合适的就保存需要的,没找到就保存整个文档的txt导出。

with open(path, 'rb') as pdf_file:  # 读取pdf文档
is_have_target_page = info.get('is_have_directory')
start_page_number = 0
end_page_number = 0
page_count = info.get('page_count')
if is_have_target_page:
start_page_number = info.get('start_page_number')
if start_page_number is None:
start_page_number = 0
is_have_target_page = False
end_page_number = info.get('end_page_number')
if end_page_number is None:
is_have_target_page = False
end_page_number = info.get('page_count')
else:
is_have_target_page = False pdf_parse = PDFParser(pdf_file)
pdf_doc = PDFDocument(pdf_parse)
if pdf_doc.is_extractable:
pdf_rm = PDFResourceManager(caching=True)
pdf_lap = LAParams()
pdf_pa = PDFPageAggregator(pdf_rm, laparams=pdf_lap)
pdf_pi = PDFPageInterpreter(pdf_rm, pdf_pa) if is_have_target_page: page_set = set()
for i in range(start_page_number, end_page_number):
page_set.add(i) pdf_page = PDFPage.get_pages(pdf_file, pagenos=page_set, password=b'', caching=True)
print('读取文本->>>')
for index, page in enumerate(pdf_page):
print("部分 : 当前文档进度 : {}/{}".format(index, len(page_set)), end=end)
pdf_pi.process_page(page)
layout = pdf_pa.get_result() for x in layout:
if isinstance(x, LTTextBoxHorizontal): # 获取文本内容
text += x.get_text() + '\n'
# print(x.get_text())
else:
pdf_page = PDFPage.create_pages(pdf_doc)
print('读取文本->>>')
is_find_start_page = False
text_cache = ""
for index, page in enumerate(pdf_page):
print("扫描 : 当前文档进度 : {}/{}, 找到起始位置 : {}".format(index, page_count, is_find_start_page),
end=end)
pdf_pi.process_page(page)
layout = pdf_pa.get_result() page_text = ''
for x in layout:
if isinstance(x, LTTextBoxHorizontal): # 获取文本内容
page_text += x.get_text() + '\n'
# print(x.get_text()) text_cache += page_text if re.search(r'第.节\s*经营情况讨论与分析\s*一', page_text): # 找到这一节了
text += page_text # 当前页开始保存
is_find_start_page = True
info = update_file_info(info, start_page_number=index)
continue if is_find_start_page:
text += page_text
if re.search(r'第.节\s*.*\s*一', page_text): # 找到下一节了
info = update_file_info(info, end_page_number=index)
break
if text == '':
text = text_cache

保存

保存很简单,就直接新建个文件,把文本写入即可。

def save_text_file(file_name, txt):
"""
覆盖保存文本文档到当前脚本目录下的output目录下
UTF-8编码
:param file_name: 文件名
:param txt: 文件内容
:return: None
"""
if not file_name.endswith('.txt'):
file_name += '.txt' # 补全文件名 file_path = os.path.join(os.getcwd(), 'output')
if not os.path.exists(file_path):
os.mkdir(file_path) # 创建文件夹 with open(os.path.join(file_path, file_name), 'w', encoding='utf-8') as txt_file:
txt_file.write(txt) # 保存文件

完成

# coding:utf-8
# @Time : 2021/11/5 11:37
# @Author : minuy
# @File : pdf_to_txt.py
# @Version : v1.1 修改搜索正则,添加文件名后缀,删除日期后缀,修复扫描不到不保存问题,修复扫描第一页丢失问题
import os
import json
import re from PyPDF2 import PdfFileReader from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTTextBoxHorizontal
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfparser import PDFParser # 换行符
end = '\n' def dispose(root_path, name_suffix=None, is_recover=False, load_cache=True, cache_info_path='pdf_cache.json'):
"""
处理pdf数据
:param name_suffix: 文件名后缀
:param root_path: 处理的根目录
:param is_recover: 是否覆盖(已导出的)
:param load_cache: 是否使用缓存(不会重新扫描)
:param cache_info_path: 缓存保存位置
:return: None
"""
if load_cache:
if not os.path.exists(cache_info_path):
load_cache = False
print('没有找到缓存数据......') if load_cache:
# pdf文档的缓存
pdf_info = load_cache_info(cache_info_path)
else:
files = get_files_list(root_path)
print('开始扫描文档.......')
pdf_info = scan_pdf_directory(files, '经营情况讨论与分析')
save_cache_info(pdf_info) files = []
for key, val in pdf_info.items():
files.append(val.get('file_path')) if name_suffix is None:
name_suffix = "" count = 0
print('开始提取数据.......')
for index, path in enumerate(files):
print("处理进度 = {:.2f}%, 文件 = {}".format(index / len(pdf_info) * 100, os.path.basename(path)), end=end) info = pdf_info.get(str(index))
if info.get('is_export') and (not is_recover):
continue # 如果已经导出并且不覆盖,则直接处理下一个
text, info = parse_pdf(info) # 提取
text_file_name = info.get('stock_code') + '_' + str(name_suffix)
save_text_file(text_file_name, text) # 保存 info = update_file_info(info, text_length=len(text), is_export=True, output_length=len(text),
text_file_name=text_file_name)
pdf_info.update({str(index): info}) # 更新缓存信息
save_cache_info(pdf_info)
count += 1
if info.get('is_have_directory'):
res = '有'
else:
res = '无'
print('> 已保存文件,文件名:{},长度:{},目录:{},本次运行处理文件个数:{}'
.format(text_file_name, len(text), res, count)) def save_cache_info(pdf_info):
"""
保存处理信息
:param pdf_info: 处理信息
:return: None
"""
with open("pdf_cache.json", 'w') as f:
json_str = json.dumps(pdf_info)
f.write(json_str) def load_cache_info(info_path):
"""
加载处理信息缓存文件
:param info_path: 加载配置信息的位置
:return: pdf缓存对象
"""
with open(info_path, 'r') as f:
json_str = f.read()
pdf_info_cache = json.loads(json_str)
return pdf_info_cache def parse_pdf(info: dict):
"""
解析pdf文档
:param info: 文档信息
:return: 文本内容,文档信息(股票代码,日期,起始位置,结束位置)
"""
path = info.get('file_path')
if path is None:
raise ValueError('不存在文件路径') file = os.path.basename(path) # 获取文件名
stock_code = re.search(r'\d{6}', file).group(0) # 解析股票代码
file_date = re.search(r'\d{4}-\d{1,2}-\d{1,2}', file).group(0) # 解析日期
info = update_file_info(info, stock_code=stock_code, date=file_date) # 更新信息 text = '' # 文本缓存
with open(path, 'rb') as pdf_file: # 读取pdf文档
is_have_target_page = info.get('is_have_directory')
start_page_number = 0
end_page_number = 0
page_count = info.get('page_count')
if is_have_target_page:
start_page_number = info.get('start_page_number')
if start_page_number is None:
start_page_number = 0
is_have_target_page = False
end_page_number = info.get('end_page_number')
if end_page_number is None:
is_have_target_page = False
end_page_number = info.get('page_count')
else:
is_have_target_page = False pdf_parse = PDFParser(pdf_file)
pdf_doc = PDFDocument(pdf_parse)
if pdf_doc.is_extractable:
pdf_rm = PDFResourceManager(caching=True)
pdf_lap = LAParams()
pdf_pa = PDFPageAggregator(pdf_rm, laparams=pdf_lap)
pdf_pi = PDFPageInterpreter(pdf_rm, pdf_pa) if is_have_target_page: page_set = set()
for i in range(start_page_number, end_page_number):
page_set.add(i) pdf_page = PDFPage.get_pages(pdf_file, pagenos=page_set, password=b'', caching=True)
print('读取文本->>>')
for index, page in enumerate(pdf_page):
print("部分 : 当前文档进度 : {}/{}".format(index, len(page_set)), end=end)
pdf_pi.process_page(page)
layout = pdf_pa.get_result() for x in layout:
if isinstance(x, LTTextBoxHorizontal): # 获取文本内容
text += x.get_text() + '\n'
# print(x.get_text())
else:
pdf_page = PDFPage.create_pages(pdf_doc)
print('读取文本->>>')
is_find_start_page = False
text_cache = ""
for index, page in enumerate(pdf_page):
print("扫描 : 当前文档进度 : {}/{}, 找到起始位置 : {}".format(index, page_count, is_find_start_page),
end=end)
pdf_pi.process_page(page)
layout = pdf_pa.get_result() page_text = ''
for x in layout:
if isinstance(x, LTTextBoxHorizontal): # 获取文本内容
page_text += x.get_text() + '\n'
# print(x.get_text()) text_cache += page_text if re.search(r'第.节\s*经营情况讨论与分析\s*一', page_text): # 找到这一节了
text += page_text # 当前页开始保存
is_find_start_page = True
info = update_file_info(info, start_page_number=index)
continue if is_find_start_page:
text += page_text
if re.search(r'第.节\s*.*\s*一', page_text): # 找到下一节了
info = update_file_info(info, end_page_number=index)
break
if text == '':
text = text_cache
return text, info def save_text_file(file_name, txt):
"""
覆盖保存文本文档到当前脚本目录下的output目录下
UTF-8编码
:param file_name: 文件名
:param txt: 文件内容
:return: None
"""
if not file_name.endswith('.txt'):
file_name += '.txt' # 补全文件名 file_path = os.path.join(os.getcwd(), 'output')
if not os.path.exists(file_path):
os.mkdir(file_path) # 创建文件夹 with open(os.path.join(file_path, file_name), 'w', encoding='utf-8') as txt_file:
txt_file.write(txt) # 保存文件 def scan_pdf_directory(files_list, key_word):
"""
扫描pdf文档目录,获得文档总页数,有无目录,有(起始位置,结束位置)
key_word 用在有目录的情况下,
不匹配则返回整个文档范围
:param files_list: 要扫描的文件列表
:param key_word: 目录关键词
:return: 字典,每个元素为一个处理单元,有唯一的ID
"""
pdf_info_dict = {}
for index, file_path in enumerate(files_list):
start_page_number = 0 # 开始页码
is_get_page_number_range = False info = update_file_info(file_path=file_path)
with open(file_path, 'rb') as pdf_file: # 读取pdf文档
pdf = PdfFileReader(pdf_file) # 加载pdf文档
if pdf.isEncrypted:
pdf.decrypt('') # 解密
end_page_number = pdf.getNumPages() # 获取总页码
info = update_file_info(info, page_count=end_page_number) # 保存总页数
pdf_directory = pdf.getOutlines() # 获取目录 is_have_start_page_number = False
for destination in pdf_directory:
if isinstance(destination, dict):
if is_have_start_page_number:
end_page_number = pdf.getDestinationPageNumber(destination)
is_get_page_number_range = True
break title = destination.get('/Title')
if key_word in str(title):
# 在目录中找到关键词了
start_page_number = pdf.getDestinationPageNumber(destination)
is_have_start_page_number = True
continue
if is_get_page_number_range:
info = update_file_info(info, start_page_number=start_page_number, end_page_number=end_page_number,
is_have_directory=True)
res = "获取页码成功"
else:
info = update_file_info(info, is_have_directory=False)
res = "获取页码失败"
print("扫描进度 : {:.2f}%, 文件 : {}".format(index / len(files_list) * 100, os.path.basename(file_path)), res, ':',
'[', start_page_number, ',', end_page_number, ']', end=end) pdf_info_dict.update({str(index): info})
return pdf_info_dict def update_file_info(info=None, file_path=None, start_page_number=None, end_page_number=None, page_count=None,
output_length=None,
is_have_directory=None, is_export=None, stock_code=None, date=None, text_file_name=None,
text_length=None):
"""
更新字典里的东西,如果不是字典,则被替换成字典
:param text_length: 导出的文本文件长度
:param page_count: 总页数
:param stock_code: 股票代码
:param date: 日期
:param text_file_name: 对应的文本文件名
:param info: 字典
:param file_path: 更新文件路径
:param start_page_number: 更新开始页码
:param end_page_number: 更新结束页码
:param output_length: 输出长度
:param is_have_directory: 是否存在目录
:param is_export: 是否已经导出
:return: 更新后的info
"""
if info is None:
info = {
'file_path': None,
'start_page_number': None,
'end_page_number': None,
'output_length': None,
'is_have_directory': None,
'is_export': None,
'stock_code': None,
'date': None,
'text_file_name': None,
'page_count': None,
'text_length': None
} if not isinstance(info, dict):
raise ValueError("传入的值info必须是空或者是字典!") if file_path:
info['file_path'] = file_path if start_page_number:
info['start_page_number'] = start_page_number if end_page_number:
info['end_page_number'] = end_page_number if output_length:
info['output_length'] = output_length if is_have_directory:
info['is_have_directory'] = is_have_directory if is_export:
info['is_export'] = is_export if stock_code:
info['stock_code'] = stock_code if date:
info['date'] = date if text_file_name:
info['text_file_name'] = text_file_name if page_count:
info['page_count'] = page_count if text_length:
info['text_length'] = text_length return info def get_files_list(path):
"""
获取传入路径中及其子目录下的所有pdf文件路径
:param path: 要搜索的根路径
:return: pdf文件路径列表
"""
files_list = []
for root, dirs, files in os.walk(path): # 遍历目录
for file in files: # 遍历文件
file_path = os.path.join(root, file) # 拼接路径
if file_path.endswith(".pdf"): # 如果是pdf文件
files_list.append(file_path) # 添加到列表中
return files_list if __name__ == '__main__':
# 扫描根目录,文件名后缀,是否覆盖,是否使用缓存信息
dispose(r'D:\Project\pdf_ouput', 2019, True, False)

运行结果

D:\Project\pdf_ouput\venv\Scripts\python.exe D:/Project/pdf_ouput/pdf_to_txt.py
开始扫描文档.......
扫描进度 : 0.00%, 文件 : 000045深纺织A:深纺织A2019年年度报告_2020-03-14.pdf 获取页码失败 : [ 0 , 182 ]
扫描进度 : 33.33%, 文件 : 002030达安基因:达安基因2019年年度报告_2020-04-30.pdf 获取页码成功 : [ 18 , 38 ]
扫描进度 : 66.67%, 文件 : 102030达安基因:达安基因2019年年度报告_2020-04-21.pdf 获取页码失败 : [ 0 , 283 ]
开始提取数据.......
处理进度 = 0.00%, 文件 = 000045深纺织A:深纺织A2019年年度报告_2020-03-14.pdf
读取文本->>>
扫描 : 当前文档进度 : 0/182, 找到起始位置 : False
扫描 : 当前文档进度 : 1/182, 找到起始位置 : False
扫描 : 当前文档进度 : 2/182, 找到起始位置 : False
扫描 : 当前文档进度 : 3/182, 找到起始位置 : False
扫描 : 当前文档进度 : 4/182, 找到起始位置 : False
扫描 : 当前文档进度 : 5/182, 找到起始位置 : False
扫描 : 当前文档进度 : 6/182, 找到起始位置 : False
扫描 : 当前文档进度 : 7/182, 找到起始位置 : False
扫描 : 当前文档进度 : 8/182, 找到起始位置 : False
扫描 : 当前文档进度 : 9/182, 找到起始位置 : False
扫描 : 当前文档进度 : 10/182, 找到起始位置 : False
扫描 : 当前文档进度 : 11/182, 找到起始位置 : False
扫描 : 当前文档进度 : 12/182, 找到起始位置 : False
扫描 : 当前文档进度 : 13/182, 找到起始位置 : True
扫描 : 当前文档进度 : 14/182, 找到起始位置 : True
扫描 : 当前文档进度 : 15/182, 找到起始位置 : True
扫描 : 当前文档进度 : 16/182, 找到起始位置 : True
扫描 : 当前文档进度 : 17/182, 找到起始位置 : True
扫描 : 当前文档进度 : 18/182, 找到起始位置 : True
扫描 : 当前文档进度 : 19/182, 找到起始位置 : True
扫描 : 当前文档进度 : 20/182, 找到起始位置 : True
扫描 : 当前文档进度 : 21/182, 找到起始位置 : True
扫描 : 当前文档进度 : 22/182, 找到起始位置 : True
扫描 : 当前文档进度 : 23/182, 找到起始位置 : True
扫描 : 当前文档进度 : 24/182, 找到起始位置 : True
扫描 : 当前文档进度 : 25/182, 找到起始位置 : True
扫描 : 当前文档进度 : 26/182, 找到起始位置 : True
扫描 : 当前文档进度 : 27/182, 找到起始位置 : True
扫描 : 当前文档进度 : 28/182, 找到起始位置 : True
> 已保存文件,文件名:000045_2019,长度:21424,目录:无,本次运行处理文件个数:1
处理进度 = 33.33%, 文件 = 002030达安基因:达安基因2019年年度报告_2020-04-30.pdf
读取文本->>>
部分 : 当前文档进度 : 0/20
部分 : 当前文档进度 : 1/20
部分 : 当前文档进度 : 2/20
部分 : 当前文档进度 : 3/20
部分 : 当前文档进度 : 4/20
部分 : 当前文档进度 : 5/20
部分 : 当前文档进度 : 6/20
部分 : 当前文档进度 : 7/20
部分 : 当前文档进度 : 8/20
部分 : 当前文档进度 : 9/20
部分 : 当前文档进度 : 10/20
部分 : 当前文档进度 : 11/20
部分 : 当前文档进度 : 12/20
部分 : 当前文档进度 : 13/20
部分 : 当前文档进度 : 14/20
部分 : 当前文档进度 : 15/20
部分 : 当前文档进度 : 16/20
部分 : 当前文档进度 : 17/20
部分 : 当前文档进度 : 18/20
部分 : 当前文档进度 : 19/20
> 已保存文件,文件名:002030_2019,长度:17705,目录:有,本次运行处理文件个数:2
处理进度 = 66.67%, 文件 = 102030达安基因:达安基因2019年年度报告_2020-04-21.pdf
读取文本->>>
扫描 : 当前文档进度 : 0/283, 找到起始位置 : False
扫描 : 当前文档进度 : 1/283, 找到起始位置 : False
扫描 : 当前文档进度 : 2/283, 找到起始位置 : False
扫描 : 当前文档进度 : 3/283, 找到起始位置 : False
扫描 : 当前文档进度 : 4/283, 找到起始位置 : False
扫描 : 当前文档进度 : 5/283, 找到起始位置 : False
扫描 : 当前文档进度 : 6/283, 找到起始位置 : False
扫描 : 当前文档进度 : 7/283, 找到起始位置 : False
扫描 : 当前文档进度 : 8/283, 找到起始位置 : False
扫描 : 当前文档进度 : 9/283, 找到起始位置 : False
扫描 : 当前文档进度 : 10/283, 找到起始位置 : False
扫描 : 当前文档进度 : 11/283, 找到起始位置 : False
扫描 : 当前文档进度 : 12/283, 找到起始位置 : False
扫描 : 当前文档进度 : 13/283, 找到起始位置 : False
扫描 : 当前文档进度 : 14/283, 找到起始位置 : False
扫描 : 当前文档进度 : 15/283, 找到起始位置 : False
扫描 : 当前文档进度 : 16/283, 找到起始位置 : False
扫描 : 当前文档进度 : 17/283, 找到起始位置 : False
扫描 : 当前文档进度 : 18/283, 找到起始位置 : True
扫描 : 当前文档进度 : 19/283, 找到起始位置 : True
扫描 : 当前文档进度 : 20/283, 找到起始位置 : True
扫描 : 当前文档进度 : 21/283, 找到起始位置 : True
扫描 : 当前文档进度 : 22/283, 找到起始位置 : True
扫描 : 当前文档进度 : 23/283, 找到起始位置 : True
扫描 : 当前文档进度 : 24/283, 找到起始位置 : True
扫描 : 当前文档进度 : 25/283, 找到起始位置 : True
扫描 : 当前文档进度 : 26/283, 找到起始位置 : True
扫描 : 当前文档进度 : 27/283, 找到起始位置 : True
扫描 : 当前文档进度 : 28/283, 找到起始位置 : True
扫描 : 当前文档进度 : 29/283, 找到起始位置 : True
扫描 : 当前文档进度 : 30/283, 找到起始位置 : True
扫描 : 当前文档进度 : 31/283, 找到起始位置 : True
扫描 : 当前文档进度 : 32/283, 找到起始位置 : True
扫描 : 当前文档进度 : 33/283, 找到起始位置 : True
扫描 : 当前文档进度 : 34/283, 找到起始位置 : True
扫描 : 当前文档进度 : 35/283, 找到起始位置 : True
扫描 : 当前文档进度 : 36/283, 找到起始位置 : True
扫描 : 当前文档进度 : 37/283, 找到起始位置 : True
> 已保存文件,文件名:102030_2019,长度:18753,目录:无,本次运行处理文件个数:3 Process finished with exit code 0

完成~

速度明显提升,但是后面扫描的时候不应该直接就是一页一页的扫描,而是先扫描前面的目录,获取对应页面,这个看看将来还有没有需求,有需求再改进吧。

总结

Python 导出pdf文档,可以导出为txt,html,表格,xml,图片等,PyPDF2主要用来获取目录,拆分、合并等操作,主要用到的函数:getNumPages() 获取总页码,getOutlines() 获取目录,getDestinationPageNumber(destination) 获取目录对应的页码,pdfminer功能很强大,现在只会导出,主要的函数有:PDFPage.create_pages(pdf_doc) 导出全部页,PDFPage.get_pages(pdf_file, pagenos=page_set) 导出集合中的指定页,pdfplumber 貌似能识别图片字符。

其他的,扫描根目录下的所有pdf文档,配置的读取和保存,配置的更新等主要涉及到Python基础和操作逻辑问题了,正则表达式也是个好东西。

参考文档

Python操作PDF全总结|pdfplumber&PyPDF2

Python使用pdfminer解析PDF_光明~~~

如何利用Python抓取PDF中的某些内容?

python 从PDF文件中读取书签/目录_龙纸人的博客

Python利用PyPDF2库获取PDF文件总页码实例

PDFMiner: PDFMiner 是一个 Python 的 PDF 解析器,可以从 PDF 文档中提取信息

PyPDF2 Documentation — PyPDF2 1.26.0 documentation

【Python】PDF文档导出指定章节为TXT的更多相关文章

  1. PDF文档导出

    代码如下: /// <summary> /// 获取html内容,转成PDF(注册) /// </summary> public void DownloadPDFByHTML( ...

  2. 【转】Python读取PDF文档,输出内容

    Python3读取pdf文档,输出内容(txt) from urllib.request import urlopen from pdfminer.pdfinterp import PDFResour ...

  3. C# 复制PDF页面到另一个PDF文档

    C# 复制PDF页面到另一个PDF文档 有时候我们可能有这样一个需求,那就是把PDF页面从一个PDF文档复制到另一个PDF文档中.由于PDF文档并不像word文档那样好编辑,因此复制也相对没有那么容易 ...

  4. C# 给PDF文档设置过期时间

    我们可以给一些重要文档或者临时文件设置过期时间和过期信息提示来提醒读者或管理者文档的时效性,并及时对文档进行调整.更新等.下面,分享通过C#程序代码来给PDF文档设置过期时间的方法. 引入dll程序集 ...

  5. 程序生成word与PDF文档的方法(python)

    程序导出word文档的方法 将web/html内容导出为world文档,再java中有很多解决方案,比如使用Jacob.Apache POI.Java2Word.iText等各种方式,以及使用free ...

  6. Python监控进程性能数据并画图保存为PDF文档

    引言 利用psutil模块(https://pypi.python.org/pypi/psutil/),可以很方便的监控系统的CPU.内存.磁盘IO.网络带宽等性能參数,下面是否代码为监控某个特定程序 ...

  7. python爬虫处理在线预览的pdf文档

    引言 最近在爬一个网站,然后爬到详情页的时候发现,目标内容是用pdf在线预览的 比如如下网站: https://camelot-py.readthedocs.io/en/master/_static/ ...

  8. 利用Python将PDF文档转为MP3音频

    1. 转语音工具 微信读书有一个功能,可以将书里的文字转换为音频,而且声音优化的不错,比传统的机械朗读听起来舒服很多. 记得之前看到过Python有一个工具包,可以将文字转换为语音,支持英文和中文,而 ...

  9. 将w3cplus网站中的文章页面提取并导出为pdf文档

    最近在看一些关于CSS3方面的知识,主要是平时看到网页中有很多用CSS3实现的很炫的效果,所以就打算系统的学习一下.在网上找到很多的文章,但都没有一个好的整理性,比较凌乱.昨天看到w3cplus网站中 ...

  10. Python抓取单个网页中所有的PDF文档

    Github博文地址,此处更新可能不是很及时. 1.背景 最近发现算法以及数据结构落下了不少(其实还是大学没怎么好好学,囧rz),考虑到最近的项目结构越来越复杂了,用它来练练思路,就打算复习下数据结构 ...

随机推荐

  1. 使用AI进行Web功能测试的方法

    在使用Python和Selenium进行Web功能测试时,引入AI(人工智能)通常可以用于改善测试效率和覆盖范围.以下是一些使用AI进行Web功能测试的方法: 智能元素定位: 使用AI技术来改进元素的 ...

  2. 解读ENS网络连接,面向多云多池网络的高效互联

    本文分享自华为云社区<ENS网络连接,面向多云多池网络的高效互联>,作者:华为云Stack ENS研发团队. 1.ENS网络连接服务场景详细介绍 ENS网络连接通过统一建模和全局管控实现跨 ...

  3. Solution -「LOJ #6538」烷基计数 加强版 加强版

    \(\mathscr{Description}\)   Link.   求含 \(n\) 个结点.无标号有根.结点儿子数量不超过 \(3\) 的树的数量.答案模 \(998244353\).   \( ...

  4. 《CUDA编程:基础与实践》读书笔记(3):同步、协作组、原子函数

    1. 单指令多线程模式 从硬件上看,一个GPU被分为若干个SM.线程块在执行时将被分配到还没完全占满的SM中,一个线程块不会被分配到不同的SM中,一个SM可以有一个或多个线程块.不同线程块之间可以并发 ...

  5. w3cschool-微信小程序开发文档-API

    https://www.w3cschool.cn/weixinapp/weixinapp-network-request.html 微信小程序API 发起请求 发起 HTTPS 网络请求.使用前请注意 ...

  6. KafKa动态分组ID

    背景说明:做这个的原因主要是因为懒,KafKa监听没有独立项目出去,由于KafKa没有组内广播模式,这就造成了一个问题:项目多处启动的时候,就只有一个地方能接收信息.这个时候就要手懂修改分组ID了. ...

  7. redux初探

    action是一个普通对象 里面必须有一个type字段,代表将要执行的行为,其他字段自己规划. action只是描述了将要发生的事情并不能直接修改状态 action创建函数 尽量是一个纯函数,他返回的 ...

  8. 解决安装python各种包速度慢问题

    # 改用清华镜像库 pip install ******* -i https://pypi.tuna.tsinghua.edu.cn/simple

  9. .NET Core GC压缩(compact_phase)底层原理浅谈

    简介 终于来到了GC的最后一个步骤,在此之间,大量预备工作已经完成.万事俱备,只欠东风 清除 如果GC决定不压缩,它将仅执行清除操作.清除操作非常简单,把所有不可到达对象(gap),转换成Free.也 ...

  10. 0101-win10 jkd配置注意事项

    更换新的电脑预装win10家庭版,根据常规方法配置jdk8后运行javac提示:不是内部或外部命令,也不是可运行的程序或批处理文件. 1 设置变量classpath时前面有个点(完成这一步后javac ...