看了几篇关于PDF解析的文章,就动手操练的同学非常容易受打击。找来一份PDF,使用sublime或notepad++打开一看,心情无比沮丧。其实,现在PDF很少有明文的了,是被压缩过的,所以打开都是乱码。在文件中,你可以看到很多/Filter /FlateDecode,那就是说明乱码部分内容是被zlib压缩过的。
FlateDecode, decompresses data encoded using the zlib/deflate com- pression method, reproducing the original text or binary data.
301 0 obj <>streamxÚT4ÜÝ·%ºè-jÑûˆDôÞkDÍ`0ŒfFï½]ô(!ˆè%zïÑKD¢F}“|í}ÿ÷ÖzoÍZ¿¹÷ìsö¹ûžs.;‹®¿œ-ܬ‡¡øB’
更打击你的可能是,找到的PDF对象号竟然是不连续的,怎么都找不到1 0 R在哪。突然发现xref也找不到了,但是PDF并不是损坏的文件。PDF阅读器,是怎么找到PDF的第一页的呢?
![08f051b26a6a2f25722d9e03a4d9d8f0.png](https://i-blog.csdnimg.cn/blog_migrate/0ca86c430ecd09c03a049bacd97fad87.jpeg)
某PDF的解析结构
实际上,这是PDF1.5引入的object stream对象,可以把多个对象打包在一起压缩。在ObjStm中,开始部分就是Object Number和Offset序列,其中偏移量是zlib解析后的位置。
2 0 obj <>stream1 0 3 31 4 164 5 320 6 456 7 621 10 756 11 798 18 839 20 88124 924 26 966 8 1008 31 1182 33 1281 34 1324 35 1367 37 1410 38 1453 39 1496
你现在应该知道怎么定位 1 0 R了吧,它就在PDF文件里面。接下来,我分享一小段python代码,可以把FlateDecode压缩的内容解析出来。
# -*- coding: utf-8 -*-import zlibimport reimport binascii# 把PDF放在同一个文件夹下,此处填入文件名pdf = open("你的PDF.pdf", "rb").read()#pattern = re.compile(b'.*?FlateDecode.*?stream(.*?)endstream', re.S)pattern = re.compile('.*?FlateDecode.*?stream(.*?)endstream', re.S)iterator = re.finditer(pattern, pdf)lastpos = 0for s in iterator: print(pdf[s.span(0)[0]:s.span(1)[0]]) lastpos = s.span(1)[1] try: text=zlib.decompress(s.group(1).strip()).decode('UTF-8') print(text) except: text=zlib.decompress(s.group(1).strip()) print(text) passprint(pdf[lastpos:].decode('UTF-8'))
好吧,欢迎关注点赞,下次我们探讨如何实现调整PDF的页面顺序。