Извлечение гиперссылок из PDF в Python

У меня есть PDF-документ с несколькими гиперссылками, и мне нужно извлечь весь текст из PDF-файла. Я использовал библиотеку PDFMiner и код с http://www.endlesscurious.com/2012/06/13/scraping-pdf-with-python/ для извлечения текста. Однако он не извлекает гиперссылки.

Например, у меня есть текст с надписью Проверьте эту ссылку, к которой прикреплена ссылка. Я могу извлечь слова Check this link out, но мне действительно нужна сама гиперссылка, а не слова.

Как мне это сделать? В идеале я бы предпочел сделать это на Python, но я готов сделать это и на любом другом языке.

Я смотрел на itextsharp, но не использовал его. Я работаю на Ubuntu и буду признателен за любую помощь.


person Randomly Named User    schedule 02.01.2015    source источник


Ответы (6)


Это старый вопрос, но, похоже, многие люди смотрят на него (включая меня, когда я пытаюсь ответить на этот вопрос), поэтому я делюсь ответом, который придумал. В качестве примечания: очень полезно научиться использовать отладчик 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

который я использовал для поиска списка аннотаций, который я ранее нашел на странице, чтобы увидеть, занимает ли какая-либо гиперссылка ту же область, что и LTTextBoxHorizontal, который я проверял на странице.

В моем случае, поскольку PDFMiner объединял слишком много текста в текстовом поле, я просмотрел атрибут _objs каждого текстового поля и просмотрел все экземпляры LTTextLineHorizontal, чтобы увидеть, не перекрывают ли они какие-либо позиции аннотаций.

person Shawn Dyer    schedule 02.04.2018

Я думаю, что с помощью 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. Я особо не пробовал.

person Ashwin S    schedule 10.02.2015
comment
Кажется, это работает нормально, но могу ли я каким-либо образом извлечь текст, содержащий гиперссылку, и изменить его? - person Sundeep Pidugu; 22.04.2019

слегка измененная версия ответа Ашвина:

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])
person Imrul Huda    schedule 24.05.2019
comment
Метод PdfFileReader принимает файл в качестве параметра, поэтому объект PDFFile не требуется! - person shantanuo; 30.06.2019

Гиперссылка на самом деле будет аннотацией, поэтому вам нужно обработать аннотацию, а не «извлекать текст». Я подозреваю, что вам придется использовать такую ​​библиотеку, как itextsharp, или MuPDF, или Ghostscript, если вы действительно в отчаянии (и вам удобно программировать на PostScript).

Я бы подумал, что относительно легко обрабатывать аннотации в поисках типа LNK.

person KenS    schedule 02.01.2015
comment
Мне нужен был как текст, так и гиперссылка, поэтому я извлек текст. И я не совсем уверен, что вы подразумеваете под обработкой аннотации... Не могли бы вы это объяснить? Я немного любитель. - person Randomly Named User; 02.01.2015
comment
Вам нужно использовать библиотеку, которая будет находить и возвращать все аннотации на данной странице (или в дереве Outlines) и возвращать словарь, описывающий их. Он должен содержать как текст, который нужно нарисовать, так и URL. Извините, но я не могу сказать вам, какую библиотеку использовать или как ее использовать, я не знаю ни одной, которая будет это делать. - person KenS; 02.01.2015

Вот версия, которая создает список 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
person weebsnore    schedule 27.09.2019
comment
Сбой с ошибкой типа: объект «IndirectObject» не может быть подписан при поиске элемента. - person gasstationwithoutpumps; 05.09.2020

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-файле.

person Shivang Raj    schedule 31.01.2021