程序化地读取、突出显示、保存PDF

13
我想编写一个小脚本(将运行在无头Linux服务器上),它可以读取PDF,突出显示与我传递的字符串数组中的任何内容匹配的文本,然后保存修改后的PDF。 我想最终会使用类似poppler的python绑定这样的工具,但不幸的是几乎没有文档,并且我在python方面几乎没有经验。
如果有人能够向我指引一些教程、示例或其他有用的文档,让我入门,我将不胜感激!

这通常并不是100%可靠的,因为任何PDF编译器 - 即使是像pdftex这样古老而可靠的编译器 - 也可能在各个地方绘制pdf内嵌内容... 您确定您的PDF可以以这种方式阅读吗? - Gleno
在我看来,Evince(或者大多数其他PDF阅读器)中的“查找”功能基本上可以满足我的需求——它可以在基本上任何PDF中突出显示匹配的文本。如果它能够将这种突出显示呈现到屏幕上,为什么不能将其呈现到文件中呢? - Jake
这有点棘手,因为PDF通常不提供文本流。它更像是一张图片 - 文本可以出现在任何地方。通常看起来对读者很好,但内部却很混乱。例如 - 通常通过分割文本并仅放置内联来实现文本对齐。无论如何,当Evince突出显示某些内容时,要么它很聪明,你的PDF表现良好,要么你只是幸运,因为该特定字符串作为连续实体驻留在PDF中。总之,看看http://itextpdf.com/,它是目前最好的免费库。 - Gleno
3
你是否找到这个问题的答案?如果是的话,我想听听 :) - mitchus
对于通过Google进入的人:如何从PDF文件中提取高亮部分 - Martin Thoma
3个回答

4

是的,可以通过pdfminer (pip install pdfminer.six)和PyPDF2 的组合来实现。

首先,找到坐标(例如像这样)。 然后将其高亮:

#!/usr/bin/env python

"""Create sample highlight in a PDF file."""

from PyPDF2 import PdfFileWriter, PdfFileReader

from PyPDF2.generic import (
    DictionaryObject,
    NumberObject,
    FloatObject,
    NameObject,
    TextStringObject,
    ArrayObject
)


def create_highlight(x1, y1, x2, y2, meta, color=[0, 1, 0]):
    """
    Create a highlight for a PDF.

    Parameters
    ----------
    x1, y1 : float
        bottom left corner
    x2, y2 : float
        top right corner
    meta : dict
        keys are "author" and "contents"
    color : iterable
        Three elements, (r,g,b)
    """
    new_highlight = DictionaryObject()

    new_highlight.update({
        NameObject("/F"): NumberObject(4),
        NameObject("/Type"): NameObject("/Annot"),
        NameObject("/Subtype"): NameObject("/Highlight"),

        NameObject("/T"): TextStringObject(meta["author"]),
        NameObject("/Contents"): TextStringObject(meta["contents"]),

        NameObject("/C"): ArrayObject([FloatObject(c) for c in color]),
        NameObject("/Rect"): ArrayObject([
            FloatObject(x1),
            FloatObject(y1),
            FloatObject(x2),
            FloatObject(y2)
        ]),
        NameObject("/QuadPoints"): ArrayObject([
            FloatObject(x1),
            FloatObject(y2),
            FloatObject(x2),
            FloatObject(y2),
            FloatObject(x1),
            FloatObject(y1),
            FloatObject(x2),
            FloatObject(y1)
        ]),
    })

    return new_highlight


def add_highlight_to_page(highlight, page, output):
    """
    Add a highlight to a PDF page.

    Parameters
    ----------
    highlight : Highlight object
    page : PDF page object
    output : PdfFileWriter object
    """
    highlight_ref = output._addObject(highlight)

    if "/Annots" in page:
        page[NameObject("/Annots")].append(highlight_ref)
    else:
        page[NameObject("/Annots")] = ArrayObject([highlight_ref])


def main():
    pdf_input = PdfFileReader(open("samples/test3.pdf", "rb"))
    pdf_output = PdfFileWriter()

    page1 = pdf_input.getPage(0)

    highlight = create_highlight(89.9206, 573.1283, 376.849, 591.3563, {
        "author": "John Doe",
        "contents": "Lorem ipsum"
    })

    add_highlight_to_page(highlight, page1, pdf_output)

    pdf_output.addPage(page1)

    output_stream = open("output.pdf", "wb")
    pdf_output.write(output_stream)


if __name__ == '__main__':
    main()

你好,我们能否只使用一个Y坐标来突出显示所有行?例如,只有y1并将左侧到右侧的所有内容标记出来?谢谢! - sygneto
2
不确定为什么这个答案没有更多的赞 :) ..真是救命的东西..非常感谢作者。 - Vikram Murthy

3
你有没有尝试查看PDFMiner呢?听起来它可以满足你的需求。

3
据我所了解,PDFMiner旨在进行PDF到文本的提取;它似乎无法突出显示并将更改后的PDF呈现到文件中。 - Jake

1

PDFlib有Python绑定并支持这些操作。如果要打开PDF,则需要使用PDI。http://www.pdflib.com/products/pdflib-family/pdflib-pdi/和TET。

不幸的是,它是商业产品。我过去在生产中使用过这个库,它非常好用。绑定非常实用,但不太符合Python风格。我看到了一些尝试使它们更具Python风格的努力:https://github.com/alexhayes/pythonic-pdflib您需要使用:open_pdi_document()。

听起来您想要进行某种搜索高亮显示:

http://www.pdflib.com/tet-cookbook/tet-and-pdflib/highlight-search-terms/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接