>>> from env_helper import info; info()
页面更新时间: 2024-04-05 10:27:33
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-18-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

4.2. 读取PDF

接下来使用PyPDF4对PDF文件进行读取,需要注意的是他对英文的支持比较好,如果读取中文就会出现乱码等问题,在后面我们会介绍几个支持读取中文的库。

4.2.1. 查看PDF信息

可以在自己的电脑上随便找一个PDF文件进行尝试操作。

>>> from pypdf import PdfReader
>>>
>>> with open('minimal.pdf','rb') as f:
>>>     pdf=PdfReader(f)
>>>     information=pdf.metadata
>>>     number_of_pages=len(pdf.pages)
>>>
>>> txt=f"""Author: {information.author}
>>> Creator: {information.creator}
>>> Producer: {information.producer}
>>> Subject: {information.subject}
>>> Title: {information.title}
>>> Number of pages: {number_of_pages}"""
>>> print(txt)
Author: None
Creator: cairo 1.11.2 (http://cairographics.org)
Producer: cairo 1.11.2 (http://cairographics.org)
Subject: None
Title: None
Number of pages: 1

PdfFileReader是一个具有多种与PDF文件交互的方法的类。 在此示例中,调用了 .getDocumentInfo() ,它将返回DocumentInformation的实例,包含了我们感兴趣的大部分信息。 我们还可以在reader对象上调用 .getNumPages() ,让它返回文档中的页数。

information这个变量具有多个实例属性,可以使用这些属性从文档中获取所需的其余元数据。我们可以打印出该信息并将其返回以备将来使用。

4.2.2. 读取文本

我们先打开PDF文件,再查看他的页数。

>>> pdffile = open('postgis-essential-0423.pdf','rb')
>>> pdfreader = PdfReader(pdffile)
>>> print(len(pdfreader.pages))
202

我们查看第二页的信息。

>>> page = pdfreader.pages[0]
>>> print(page.extract_text().strip())
第 1章地理空间数据库的发展、技术与标准
回答地理空间问题有很多工具,或桌面应用系统。这种方法虽然功能完备,但不能同时回
答许多问题。此外,这种方法通常无法在一个数据集中有效地管理和操作大量的空间数据集,
也无法使任务自动化。
一旦需要可伸缩性、对大型数据集的支持以及直接输入机制,大多数用户就会使用空间数
据库进行探索。有几个可用的空间数据库软件,一些是专有的,另一些是开源的。 PostGIS 是
一个开源的空间数据库软件,可能是所有空间数据库软件中最容易访问的。
PostGIS 作为扩展运行,为 PostgreSQL 数据库提供空间功能。在这种能力下, PostGIS
允许将空间数据与常规关系型数据一起包含进来。通过构建 PostGIS 提供的核心功能和
PostgreSQL 固有的可扩展性,可以实现新的或增强的功能。
在数据库存储方面,数据库是高级形式,而 PostGIS 赋予其更多的功能。
1.1平面文件、空间数据引擎到空间数据库
在传统的第一代 地理信息系统 (GIS)实现中,所有的 空间数据 都存储在 平面文件( flat
files)中,需要专门的 GIS软件来解释和操作这些数据。这些第一代管理系统旨在满足用
户的需求,其中所有所需的数据都在用户的组织领域中。它们是专为处理 空间数据 而构建的专
有的、独立的系统,应用程序和平面文件之间的耦合性非常高,平面文件里的空间数据没有数
据独立性。
为了提高数据库管理系统( DBMS)对空间数据的管理能力 ,国内外较为流行的主要集中在
“关系型数据库 +空间数据引擎” 、 “扩展对象关系型数据库”两方面。
“关系型数据库+空间数据引擎” 技术方案访问迅速,与 GIS联系紧密,在应用中占有一
定优势。问题是引擎与数据库内核独立,难以利用数据库系统中已有的成熟的管理、访问技术,
在进一步发展上有致命弱点。
“扩展对象空间数据库系统” 技术方案从理论上来看,是最适用于空间数据的表达和管理
的。
3
>>>
>>> idx_arr = [0]
>>> for idx, page in enumerate(pdfreader.pages):
>>>     cnts = page.extract_text().strip().splitlines()
>>>     # print(idx, cnts[0])
>>>     if '第' in cnts[0] and '章' in cnts[0]:
>>>         print(idx)
>>>         print(cnts[0])
>>>         if idx != 0:
>>>             idx_arr.append(idx)
>>> idx_arr.append(len(pdfreader.pages))
>>>
>>> print(idx_arr)
0
第 1章地理空间数据库的发展、技术与标准
12
第 2章创建您的第一个空间数据库
22
第 3章 PostGIS 的数据读写与转换
36
第 4章 PostGIS 中的几何图形:文本表达的输入与输出
50
第 5章几何图形的简单性与有效性
64
第 6章合成和分解几何图形
78
第 7章空间数据坐标系统与投影
84
第 8章空间度量与测度
88
第 9章使用 Geography
96
第 10章一元几何图形操作
102
第 11章空间关系
114
第 12章矢量数据空间操作:二元算子
128
第 13章空间索引
148
第 14章栅格数据读写:导入与导出
158
第 15章使用栅格数据
168
第 16章管理栅格数据
180
第 17章高级话题
190
第 18章运维
[0, 12, 22, 36, 50, 64, 78, 84, 88, 96, 102, 114, 128, 148, 158, 168, 180, 190, 202]
>>> from pypdf import PdfWriter
>>>
>>> pdf_idx = 1
>>>
>>> from pathlib import Path
>>> outws = Path('xx_post')
>>> if outws.exists():
>>>     pass
>>> else:
>>>     outws.mkdir()
>>>
>>> for qq, hh in zip(idx_arr[:-1], idx_arr[1:]):
>>>     outfile = outws / f'xx_{pdf_idx:02}.pdf'
>>>     print(outfile)
>>>
>>>
>>>     merger = PdfWriter()
>>>
>>>
>>>     # add the first 3 pages of input1 document to output
>>>     merger.append(fileobj=pdfreader, pages=(qq, hh))
>>>
>>>     # insert the first page of input2 into the output beginning after the second page
>>>     # merger.merge(position=2, fileobj=input2, pages=(0, 1))
>>>
>>>     # append entire input3 document to the end of the output document
>>>     # merger.append(input3)
>>>
>>>     # Write to an output PDF document
>>>     output = open(outfile, "wb")
>>>     merger.write(output)
>>>
>>>     # Close File Descriptors
>>>     merger.close()
>>>     output.close()
>>>     pdf_idx =  pdf_idx + 1
xx_post/xx_01.pdf
xx_post/xx_02.pdf
xx_post/xx_03.pdf
xx_post/xx_04.pdf
xx_post/xx_05.pdf
xx_post/xx_06.pdf
xx_post/xx_07.pdf
xx_post/xx_08.pdf
xx_post/xx_09.pdf
xx_post/xx_10.pdf
xx_post/xx_11.pdf
xx_post/xx_12.pdf
xx_post/xx_13.pdf
xx_post/xx_14.pdf
xx_post/xx_15.pdf
xx_post/xx_16.pdf
xx_post/xx_17.pdf
xx_post/xx_18.pdf

4.2.3. 读取图片

PDF有扫描的图片,或者插入图片在内,首先验证文档是否加密。

>>> pdffile = open('servers.pdf','rb')
>>> pdfreader.is_encrypted
False

输出为False,即为没有加密过。

>>> pg = pdfreader.pages[0]
>>> pg.keys()
dict_keys(['/Resources', '/Contents', '/Parent', '/Type', '/MediaBox'])

图片存储在 ['/Resources']['/XObject'] 里,通过type查看发现 pg['/Resources']['/XObject']['/Im1'] 是一个EncodedStreamObject,通过 getData() 方法可以获取它的数据,直接以二进制模式写入文件即可保存。再使用前面使用的pillow库查看

>>> pg.values()
dict_values([IndirectObject(322, 0, 140384372467792), [IndirectObject(321, 0, 140384372467792)], IndirectObject(1646, 0, 140384372467792), '/Page', [0, 0, 595.27999999999997, 841.88999999999999]])
>>> # im8 = pg['/Resources']['/XObject']['/FXX1'].get_data()
>>> # with open('im.png', 'wb') as f:
>>> #      f.write(im8)
>>> # from matplotlib import pyplot as plt
>>> # from PIL import Image
>>> # img=Image.open('./im.png')
>>> # plt.imshow(img)
>>> # plt.show()