29.08.2018
Эта статья-руководство отражает пройденный мною путь от постановки вопроса "как извлечь выделенный текст (highlight) из PDF книги" до найденного решения. Времени на поиск решения я потратил немало, из-за чего не решился удалить описание тех программ и способов получения аннотаций, которые меня не устроили, либо работали не корректно.
Зачем это нужно?
Я читаю книги.. Когда я читаю печатное издание, то всегда оставляю липкие закладки на полях, отмечая тем самым интересную и важную для меня информацию. Через некоторое время после прочтения книги, я перелистываю эти закладки и сохраняю, либо анализирую отмеченную информацию. И такое ощущение, что так никто не делает.. По крайней мере, при чтении электронных книг. Ни один линуксовый PDF ридер (Foxit, Okular) не умеет экспортировать аннотации! Лишь немногие могут более-менее сносно показывать их в меню. Тем не менее, я обнаружил платный сервис, который умеет извлекать примечания из PDF - sumnotes.net . Импорт 50 примечаний (или страниц) бесплатный, а за 500 просят $7 в год.
Извлечение аннотаций на сервисе sumnotes, есть экспорт в TXT
Я задался целью найти именно консольную утилиту, которая умела бы извлекать аннотации. Сразу приведу работающее решение, а после него те, которые обнаружил в процессе.
Все действия проводились в Ubuntu 14.04.
Poppler - это python библиотека для работы с PDF файлами, которая умеет извлекать аннотации.
Ставим библиотеку python-poppler: (предполагается, что python уже установлен в системе)
sudo apt-get install python-popplerСкрипт pdf_extract_annotations.py, который будет извлекать заметки/аннотации с помощью poppler:
import poppler import sys import urllib import os def main(): input_filename = sys.argv[1] # http://blog.hartwork.org/?p=612 document = poppler.document_new_from_file('file://%s' % \ urllib.pathname2url(os.path.abspath(input_filename)), None) n_pages = document.get_n_pages() all_annots = 0 for i in range(n_pages): page = document.get_page(i) annot_mappings = page.get_annot_mapping () num_annots = len(annot_mappings) if num_annots > 0: for annot_mapping in annot_mappings: if annot_mapping.annot.get_annot_type().value_name != 'POPPLER_ANNOT_LINK': all_annots += 1 print 'page: {0:3}, {1:10}, type: {2:10}, content: {3}'.format(i+1, annot_mapping.annot.get_modified(), annot_mapping.annot.get_annot_type().value_nick, annot_mapping.annot.get_contents()) if all_annots > 0: print str(all_annots) + " annotation(s) found" else: print "no annotations found" if __name__ == "__main__": main()Извлекаем аннотации из PDF файла:
python pdf_extract_annotations.py book.pdfПример вывода аннотаций:
page: 6, D:20160204112641Z00'00, type: text , content: Тестовая заметка Adobe PDF Reader page: 8, D:20160204113002+02'00', type: highlight , content: good practicesЭто C библиотека, которая предоставляет консольную утилиту leela (неужели та самая, из футурамы). Импортирует аннотации в XML формате, но структура не валидная. В общем использовать можно, но с костылями.
Установка зависимостей и компиляция:
git clone [email protected]:TrilbyWhite/Leela.git sudo aptitude install libpoppler-glib-dev cd Leela makeИзвлечь аннотации:
./leela annots book.pdfОбработанный формат вывода:
<annot page="7" index="5" type="text"> <rect x1="315.000000" y1="731.000000" x2="333.000000" y2="749.000000"/> <name>c9ff65f3-0caf-480b-9833-71c73f71c500</name> <color r="65535" g="65535" b="0"/> <label>Stanislav</label> </markup> <text>Тестовая заметка Adobe PDF Reader</text> </annot> <annot page="7" index="6" type="highlight"> <rect x1="128.919000" y1="682.944000" x2="211.297000" y2="700.228000"/> <name>f4c04f7f-da60-4653-ac3e-343825a667fd</name> <color r="65535" g="65535" b="0"/> <text>good practices</text> </annot>Для получения нормальной разметки я набросал скрипт pdf_annotate_extract.sh:
annotations=$(./leela annots "$1" \ | sed -r 's/\s<\/markup>//g' \ | sed '/^\s*$/d' \ | pcregrep -iM '<annot.*? type="(text|highlight)">(.|\n)+?</annot>') xml=$(echo $annotations | xml_wrap.sh) echo $xmlФормирование валидного XML (xml_wrap.sh):
echo '<?xml version="1.0"?><container>' $(cat) '</container>'Изначально, я пытался получить аннотации с помощью таких утилит, как pdftotext, pdftohtml и pdfgrep. Забудьте! Все они извлекают лишь "сырой" текст, никаких аннотаций.
Также, я нашел упоминание про хорошую поддержку аннотаций в виндовой программе pdf-xchange-viewer . Скачал портативную версию, запустил под wine. Есть функция экспорта аннотаций, называется "сводка комментариев", но только в PDF.
Панель экспорта сводки комментариев и аннотаций
Сказано, что DEMO версия оставляет водяные знаки, но я их не обнаружил, м.б. где-то внизу листа.
Пример сводки комментариев
В общем, это не совсем то, что мне было нужно, идем дальше...
Это система обмена документами. Для моей задачи это избыточно, но я все же зарегистрировался и установил десктопную версию.
Интерфейс приятный, создание примечаний простое, но.. Утилита не от отображает список аннотаций, которые я добавил через Adobe и Foxit, хотя видит посдсвеченный текст и примечания. Дают 2GB места под документы, интегрируется с Zotero.
Клиентское приложение сервиса mendeley.com
Вот с этой штуковиной я изрядно повозился, но ничего толкового у меня не вышло - примеяания не удалось извлечь из-за ошибки " java.lang.Exception: Unsupported annotation subtype ".
Нам понадобятся утилиты pax и texlive-latex-extra (весит не мало):
sudo apt-get install texlive-latex-extra paxУстановим зависимость PDFBox:
pdfannotextractor --install* будет установлен PDFBox в ~/.texmf-var/scripts/pax/PDFBox-0.7.3.zip.
Извлекаем аннотации:
pdfannotextractor book.pdfИ в итоге я получил:
* Processing file `modern_php.pdf' ... !!! Warning: Annotation on page 8 not recognized! java.lang.Exception: Unsupported annotation subtype: Text !!! Warning: Annotation on page 8 not recognized! java.lang.Exception: Unsupported annotation subtype: Popup !!! Warning: Annotation on page 8 not recognized! java.lang.Exception: Unsupported annotation subtype: HighlightКопать дальше не хватило терпения.. Да и жавовский PDFBox довольно медленная штука.
Утилиты, которые я не проверил:
marginalia - https://github.com/nichtich/marginalia PDFMiner - http://www.unixuser.org/~euske/python/pdfminer/#extract annotations, #linux pdf highlight extractor