市面上有多个可识别PDF内容的库,我选的是PyPDF2,可通过pip直接安装,但是在使用过程中,有一些PDF文件就会报出一个无法找到EOF标记的错误。
1. 安装 2. 报错 1 PdfReaderError: EOF marker not found 
这个错误一般都是在创建PdfReader实例时出来的,想要抽取文件里的内容,就必须先生成这个实例,这个实例会提供一系列操作PDF文件的方法,包括读取页数、抽取文字内容,等等。
3. 原因 一般来说,PDF文件最后3行是固定的,如下,注意,每行末尾都有个\n的换行符号:
这个是PDF文件结构决定的,这里不展开说了,EOF表示结束,中间的数字是startxref的值,每个文件会不同。但是有的PDF文件并不是按照这个格式来的,会在EOF的后面再加上一些东西,导致PdfReader找不到EOF这个标记,对于这种情况,处理方式就是把EOF后面的行都删掉即可。
此外,还会有一种情况,如下,同样末尾有个\n:
这三个东西在同一行上,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.pathimport  PyPDF2def  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