【问题标题】:Extract hyperlinks from PDF in Python在 Python 中从 PDF 中提取超链接
【发布时间】:2015-02-28 21:44:39
【问题描述】:

我有一个包含几个超链接的 PDF 文档,我需要从 pdf 中提取所有文本。 我使用了 PDFMiner 库和来自http://www.endlesslycurious.com/2012/06/13/scraping-pdf-with-python/ 的代码来提取文本。但是,它不会提取超链接。

例如,我的文字是Check this link out,并附有一个链接。我能够提取单词Check this link out,但我真正需要的是超链接本身,而不是单词。

我该怎么做呢?理想情况下,我更愿意用 Python 来做,但我也愿意用任何其他语言来做。

我看过itextsharp,但没用过。我在Ubuntu 上运行,希望能提供任何帮助。

【问题讨论】:

    标签: python pdf hyperlink pypdf pdfminer


    【解决方案1】:

    这是一个老问题,但似乎很多人都在关注它(包括我在尝试回答这个问题时),所以我分享了我想出的答案。附带说明一下,学习如何使用 Python 调试器 (pdb) 很有帮助,这样您就可以即时检查这些对象。

    可以使用 PDFMiner 获取超链接。复杂之处在于(就像很多关于 PDF 一样),链接注释和链接文本之间实际上没有任何关系,只是它们都位于页面的同一区域。

    这是我用来获取 PDFPage 链接的代码

    annotationList = []
    if page.annots:
        for annotation in page.annots.resolve():
            annotationDict = annotation.resolve()
            if str(annotationDict["Subtype"]) != "/Link":
                # Skip over any annotations that are not links
                continue
            position = annotationDict["Rect"]
            uriDict = annotationDict["A"].resolve()
            # This has always been true so far.
            assert str(uriDict["S"]) == "/URI"
            # Some of my URI's have spaces.
            uri = uriDict["URI"].replace(" ", "%20")
            annotationList.append((position, uri))
    

    然后我定义了一个类似的函数:

    def getOverlappingLink(annotationList, element):
        for (x0, y0, x1, y1), url in annotationList:
            if x0 > element.x1 or element.x0 > x1:
                continue
            if y0 > element.y1 or element.y0 > y1:
                continue
            return url
        else:
            return None
    

    我用来搜索之前在页面上找到的 annotationList,以查看是否有任何超链接与我在页面上检查的 LTTextBoxHorizo​​ntal 占用相同的区域。

    在我的例子中,由于 PDFMiner 在文本框中合并了太多文本,我浏览了每个文本框的 _objs 属性并查看了所有 LTTextLineHorizo​​ntal 实例,看看它们是否与任何注释位置重叠。

    【讨论】:

      【解决方案2】:

      Ashwin 的回答稍作修改:

      import PyPDF2
      PDFFile = open("file.pdf",'rb')
      
      PDF = PyPDF2.PdfFileReader(PDFFile)
      pages = PDF.getNumPages()
      key = '/Annots'
      uri = '/URI'
      ank = '/A'
      
      for page in range(pages):
          print("Current Page: {}".format(page))
          pageSliced = PDF.getPage(page)
          pageObject = pageSliced.getObject()
          if key in pageObject.keys():
              ann = pageObject[key]
              for a in ann:
                  u = a.getObject()
                  if uri in u[ank].keys():
                      print(u[ank][uri])
      

      【讨论】:

      • PdfFileReader 方法接受文件作为参数,因此不需要 PDFFile 对象!
      【解决方案3】:

      我认为使用 PyPDF 你可以做到这一点。如果要从 PDF 中提取链接。我不确定我是从哪里得到的,但它作为其他东西的一部分存在于我的代码中。希望这会有所帮助:

      PDFFile = open('File Location','rb')
      
      PDF = pyPdf.PdfFileReader(PDFFile)
      pages = PDF.getNumPages()
      key = '/Annots'
      uri = '/URI'
      ank = '/A'
      
      for page in range(pages):
      
          pageSliced = PDF.getPage(page)
          pageObject = pageSliced.getObject()
      
          if pageObject.has_key(key):
              ann = pageObject[key]
              for a in ann:
                  u = a.getObject()
                  if u[ank].has_key(uri):
                  print u[ank][uri]
      

      我希望这应该在您的 PDF 中提供链接。 P.S:我没有广泛尝试过。

      【讨论】:

      • 这似乎工作正常,但有什么办法可以提取包含超链接的文本并修改它?
      【解决方案4】:
      import pikepdf
      pdf_file = pikepdf.Pdf.open("pdf.pdf")    
      urls = []
      for page in pdf_file.pages:
          for annots in page.get("/Annots"):
              url=annots.get("/A").get("/URI")
              if url is not None:
                  urls.append(url)
                  urls.append(" ; ")
      print(urls)
      

      您将获得给定 PDF 中以分号分隔的链接列表

      【讨论】:

        【解决方案5】:

        超链接实际上是注释,因此您需要处理注释而不是“提取文本”。我怀疑如果你真的很绝望(并且在 PostScript 中编程很舒服),你将需要使用 itextsharp、MuPDF 或 Ghostscript 之类的库。

        我认为处理寻找 LNK 类型的注释相对容易。

        【讨论】:

        • 我需要文本和超链接,所以我提取了文本。而且我不确定您所说的处理注释是什么意思...您能解释一下吗?我有点业余。
        • 您需要使用一个库来定位并返回给定页面(或大纲树中)的所有注释,并返回描述它们的字典。这应该包含要绘制的文本和 URL。很抱歉,我不能告诉你使用哪个库或如何使用它,我不知道有什么可以做到这一点。
        【解决方案6】:

        这是一个以我能找到的最简单的方式创建 URL 列表的版本:

        import PyPDF2
        
        pdf = PyPDF2.PdfFileReader('filename.pdf')
        
        urls = []
        for page in range(pdf.numPages):
            pdfPage = pdf.getPage(page)
            try:
                for item in (pdfPage['/Annots']):
                    urls.append(item['/A']['/URI'])
            except KeyError:
                pass
        

        【讨论】:

        • 在项目查找中失败并显示“TypeError: 'IndirectObject' object is not subscriptable”。
        猜你喜欢
        • 2020-10-28
        • 2015-07-06
        • 1970-01-01
        • 1970-01-01
        • 2011-10-21
        • 2016-08-26
        • 2021-02-01
        • 2013-08-29
        • 2022-08-18
        相关资源
        最近更新 更多