我正在尝试将PDF的每个页面提取为字符串:
import pyPdf
pages = []
pdf = pyPdf.PdfFileReader(file('g-reg-101.pdf', 'rb'))
for i in range(0, pdf.getNumPages()):
this_page = pdf.getPage(i).extractText() + "\n"
this_page = " ".join(this_page.replace(u"\xa0", " ").strip().split())
pages.append(this_page.encode("ascii", "xmlcharrefreplace"))
for page in pages:
print '*' * 80
print page
但是这个脚本会忽略换行符,让我留下像information concerning an individual which, because of name, identifyingnumber, mark or description
这样的混乱字符串(即,这应该是identifying number
,而不是identifyingumber
)。
Here's an example我试图解析的PDF类型。
答案 0 :(得分:7)
我对PDF编码了解不多,但我认为您可以通过修改pdf.py
来解决您的特定问题。在PageObject.extractText
方法中,您可以看到正在发生的事情:
def extractText(self):
[...]
for operands,operator in content.operations:
if operator == "Tj":
_text = operands[0]
if isinstance(_text, TextStringObject):
text += _text
elif operator == "T*":
text += "\n"
elif operator == "'":
text += "\n"
_text = operands[0]
if isinstance(_text, TextStringObject):
text += operands[0]
elif operator == '"':
_text = operands[2]
if isinstance(_text, TextStringObject):
text += "\n"
text += _text
elif operator == "TJ":
for i in operands[0]:
if isinstance(i, TextStringObject):
text += i
如果运算符为Tj
或TJ
(在示例PDF中为Tj),则只会附加文本,不会添加换行符。现在你不一定想要添加换行符,至少在我正在阅读PDF参考权时:Tj/TJ
只是单个和多个show-string运算符,并且存在某种分隔符不是强制性的。
无论如何,如果您将此代码修改为
def extractText(self, Tj_sep="", TJ_sep=""):
[...]
if operator == "Tj":
_text = operands[0]
if isinstance(_text, TextStringObject):
text += Tj_sep
text += _text
[...]
elif operator == "TJ":
for i in operands[0]:
if isinstance(i, TextStringObject):
text += TJ_sep
text += i
然后默认行为应该是相同的:
In [1]: pdf.getPage(1).extractText()[1120:1250]
Out[1]: u'ing an individual which, because of name, identifyingnumber, mark or description can be readily associated with a particular indiv'
但您可以在以下情况下进行更改:
In [2]: pdf.getPage(1).extractText(Tj_sep=" ")[1120:1250]
Out[2]: u'ta" means any information concerning an individual which, because of name, identifying number, mark or description can be readily '
或
In [3]: pdf.getPage(1).extractText(Tj_sep="\n")[1120:1250]
Out[3]: u'ta" means any information concerning an individual which, because of name, identifying\nnumber, mark or description can be readily '
或者,您可以通过自行修改操作数本身来添加分隔符,但这可能会破坏其他内容(像get_original_bytes
这样的方法会让我感到紧张)。
最后,如果您不想这样做,则无需编辑pdf.py
:您只需将此方法拉入函数即可。
答案 1 :(得分:0)
pyPdf并不是真正用于这种文本提取,请尝试pdfminer(或者如果你不介意创建另一个进程,请使用pdftotext或类似的东西)
答案 2 :(得分:0)
扩展 DSM 的回答。 以下是如何通过扩展几个类来实现它
import PyPDF2
import pandas as pd
from PyPDF2.generic import TextStringObject
from PyPDF2.pdf import ContentStream, IndirectObject, NameObject
from PyPDF2.utils import b_, u_
class PageObject2(PyPDF2.pdf.PageObject):
def extractText(self, Tj_sep="", TJ_sep=""):
"""
Locate all text drawing commands, in the order they are provided in the
content stream, and extract the text. This works well for some PDF
files, but poorly for others, depending on the generator used. This will
be refined in the future. Do not rely on the order of text coming out of
this function, as it will change if this function is made more
sophisticated.
:return: a unicode string object.
"""
text = u_("")
content = self["/Contents"].getObject()
if not isinstance(content, ContentStream):
content = ContentStream(content, self.pdf)
# Note: we check all strings are TextStringObjects. ByteStringObjects
# are strings where the byte->string encoding was unknown, so adding
# them to the text here would be gibberish.
for operands, operator in content.operations:
if operator == b_("Tj"):
_text = operands[0]
if isinstance(_text, TextStringObject):
text += Tj_sep
text += _text
elif operator == b_("T*"):
text += "\n"
elif operator == b_("'"):
text += "\n"
_text = operands[0]
if isinstance(_text, TextStringObject):
text += operands[0]
elif operator == b_('"'):
_text = operands[2]
if isinstance(_text, TextStringObject):
text += "\n"
text += _text
elif operator == b_("TJ"):
for i in operands[0]:
if isinstance(i, TextStringObject):
text += TJ_sep
text += i
text += "\n"
return text
class PdfFileReader2(PyPDF2.PdfFileReader):
def _flatten(self, pages=None, inherit=None, indirectRef=None):
inheritablePageAttributes = (
NameObject("/Resources"), NameObject(
"/MediaBox"),
NameObject("/CropBox"), NameObject("/Rotate")
)
if inherit == None:
inherit = dict()
if pages == None:
self.flattenedPages = []
catalog = self.trailer["/Root"].getObject()
pages = catalog["/Pages"].getObject()
t = "/Pages"
if "/Type" in pages:
t = pages["/Type"]
if t == "/Pages":
for attr in inheritablePageAttributes:
if attr in pages:
inherit[attr] = pages[attr]
for page in pages["/Kids"]:
addt = {}
if isinstance(page, IndirectObject):
addt["indirectRef"] = page
self._flatten(page.getObject(), inherit, **addt)
elif t == "/Page":
for attr, value in list(inherit.items()):
# if the page has it's own value, it does not inherit the
# parent's value:
if attr not in pages:
pages[attr] = value
pageObj = PageObject2(self, indirectRef)
pageObj.update(pages)
self.flattenedPages.append(pageObj)
# creating an object
file = open('travelers.pdf', 'rb')
# creating a pdf reader object
fileReader = PdfFileReader2(file)
# print the number of pages in pdf file
no_of_pages = fileReader.numPages
pageObj = fileReader.getPage(page_no)
page = pageObj.extractText(Tj_sep='\n')