8

我正在尝试将 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)。

这是我尝试解析的 PDF 类型的示例。

4

3 回答 3

11

我对 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

如果运算符是TjTJ(在您的示例 PDF 中为 Tj),则仅附加文本并且不添加换行符。现在您不一定添加换行符,至少如果我正在阅读 PDF 参考正确:Tj/TJ只是单个和多个显示字符串运算符,并且某种分隔符的存在不是强制性的。

无论如何,如果您将此代码修改为类似

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如果您不想编辑自己,则不必编辑:您可以简单地将这个方法拉出到一个函数中。

于 2012-06-19T18:55:26.653 回答
0

pyPdf 并不是真正为这种文本提取而设计的,请尝试使用pdfminer(如果您不介意创建另一个进程,请使用 pdftotext 或类似的东西)

于 2012-06-26T14:27:18.293 回答
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')
于 2021-07-21T07:46:16.720 回答