Python
python3
pdfminer

PDFから注釈を抜き出した話

きっかけ

春の人事異動に向けてWebページの改定が必要になりました。
URLの一覧からChromeの --print-to-pdf オプションを使ってすべてのページをPDFに落として修正が必要な個所にすべて注釈を入れたけど、一覧にして管理したいからPDFから注釈を全部引っこ抜けないだろうか?

PDFMinerを使う

よく調べてみると、GitHubに4年前に書かれた extract_pdf_comments.py というphthon2系らしきソースがあるのでこれを試す

動作環境

いつものSurface3 (Win10 x64)
Phthon 3.6.4

PDFMinerの導入

ここを参考に PDFMiner.six を導入する
前提条件としてVS2015とpycryptoが必要なのでここを参考に入れる

ソースを直す

エラーメッセージと闘いながらpython3 向けの修正と日本語対応を行う。サンプルソースは以下のように変化した。

extract_pdf_comments.py
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdftypes import PDFObjectNotFound

pages = []

def extract(objid, obj):
    global pages
    if isinstance(obj, dict):
        # 'Type' is PDFObjRef type
        if 'Type' in obj and obj['Type'].name == 'Page':
            pages.append(objid)
        elif 'C' in obj:
            pr = obj['P']
            try:
                pi = pages.index(pr.objid)+1
            except:
                pi = -1
            print(objid,pi, obj['Subj'].strip(b'\xfe\xff').decode('utf-16be'),obj['T'].decode(),obj['Contents'].strip(b'\xfe\xff').decode('utf-16be')

fp = open("sample.pdf", 'rb')
parser = PDFParser(fp)
doc = PDFDocument(parser, "")
visited = set()
for xref in doc.xrefs:
    for objid in xref.get_objids():
        if objid in visited: continue
        visited.add(objid)
        try:
            obj = doc.getobj(objid)
            if obj is None: continue
            extract(objid,obj)
        except PDFObjectNotFound as e:
            print >>sys.stderr, 'not found: %r' % e

これを実行するとこんな感じで出力される

51 9 ハイライト表示 user 表題:部署名の変更
55 9 ハイライト表示 user マネージメントの入れ替え
57 9 ハイライト表示 user 要検討:部署名の変更?言い回しの変更?
59 9 ハイライト表示 user 2018/4の記事を追加

実際にはこれをフォルダ指定して存在するPDFファイルをすべて処理して、ファイル名も含めてカンマ区切りで出力するように変更している。

(2018/2/22追記)
現状のソースでは、ユーザー名は英数字のみで、コメントは日本語で何かが記入されている(無記入でない)ことが前提になっています。
マーキングだけしてコメントを入力しないと、"Contents"がないとか言われてエラーになります。

おまけ

URLの一覧からWebページをPDFとして保存する

printPDF.bat
REM chrome \
REM  --headless \                   # Chrome をヘッドレスモードで実行する
REM  --disable-gpu \                # 暫定的に必要なフラグ
REM  --remote-debugging-port=9222 \
REM  https://www.chromestatus.com   # 開きたい URL(デフォルトは about:blank)
REM
REM CSVの書式は、 #,<url>,<filename>
REM
set curdir=C:\tmp
set csvfile=%curdir%\url.csv
set chromedir="C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
for /f "tokens=1,2,3 delims=," %%a in (%csvfile%) do (
 %chromedir%  --headless --disable-gpu --print-to-pdf=%curdir%\%%c.pdf %%b)