oynix

于无声处听惊雷,于无色处见繁花

PyPDF2中关于EOF问题

市面上有多个可识别PDF内容的库,我选的是PyPDF2,可通过pip直接安装,但是在使用过程中,有一些PDF文件就会报出一个无法找到EOF标记的错误。

1. 安装

1
pip install PyPDF2

2. 报错

1
PdfReaderError: EOF marker not found

这个错误一般都是在创建PdfReader实例时出来的,想要抽取文件里的内容,就必须先生成这个实例,这个实例会提供一系列操作PDF文件的方法,包括读取页数、抽取文字内容,等等。

3. 原因

一般来说,PDF文件最后3行是固定的,如下,注意,每行末尾都有个\n的换行符号:

1
2
3
startxref
14234
%%EOF

这个是PDF文件结构决定的,这里不展开说了,EOF表示结束,中间的数字是startxref的值,每个文件会不同。但是有的PDF文件并不是按照这个格式来的,会在EOF的后面再加上一些东西,导致PdfReader找不到EOF这个标记,对于这种情况,处理方式就是把EOF后面的行都删掉即可。

此外,还会有一种情况,如下,同样末尾有个\n

1
startxref 14234 %%EOF

这三个东西在同一行上,PdfReader在找到EOF后,就会去这一行的上面找startxref,所以如果在同一行的话,还是会找不到,然后就报错。对于这种情况,就需要把这三个东西分开,放到3行即可。

4. 代码

思路就是,输入一个PDF文件的路径,然后依次判断上述的2种情况,有则处理,最后把处理好的结果输出到一个新文件,将该文件的路径返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import os.path
import PyPDF2


def fix_pdf_eof(file_path: str) -> str:
if not os.path.exists(file_path):
return ''

file_name = os.path.basename(file_path)
file_dir = file_path.replace(file_name, '')

fix_file_name = 'fix_%s' % file_name
fix_file_path = '%s%s' % (file_dir, fix_file_name)

if os.path.exists(fix_file_path):
return fix_file_path

with open(file_path, 'rb') as input_stream:
lines = input_stream.readlines()
length = len(lines)
eof_index = get_eof_index(lines)
if eof_index == -1:
return ''
if eof_index != length - 1:
lines = lines[:eof_index + 1]
last_line = lines[-1]
if last_line.startswith(b'startxref'):
xref = last_line.replace(b'startxref', b'').replace(b'%%EOF\n', b'').replace(b' ', b'')
lines[-1] = b'startxref\n'
lines.append(xref + b'\n')
lines.append(b'%%EOF\n')
with open(fix_file_path, 'wb') as fix_output:
fix_output.writelines(lines)
return fix_file_path


def get_eof_index(lines: list):
length = len(lines)
for i, line in enumerate(lines[::-1]):
if line.endswith(b'%%EOF\n') or line.endswith(b'%%EOF\r\n'):
return length - 1 - i
return -1
------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.com/2023/05/23d18905bbb6/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道