メールに添付されたPDFをテキスト形式にする


とある会社からPDFが添付されたメールが送られてくる。

GmailなどPDFも検索できるメールサービスを使うのも手だが、あまり外部に出したくないのと、特定のキーワードが見つかった場合に適当に処理させたかったので、PythonのpyPdfを試してみた。

まず。メールの設定から。普段、使ってるメールソフトを「サーバにメールを残す」という設定にして、サーバに残ってるメールをfetchmailとprocmailで取得する。今回はCygwin環境のものを使い、下記のような設定ファイルを書いた。

.fetchmailrc
defaults
  fetchall
  keep
  mda "/usr/bin/procmail"

poll pop.xxx.com
  protocol pop3
  port 110
  username "XXXXX"
  password "XXXXX"
.procmailrc
MAILDIR=$HOME/Mail/
DEFAULT=/dev/null

:0 H
* ^From:.*[email protected]
/var/spool/mail/t.uehara/

こう書くことで、test@exampleからのメールは/var/spool/mailに格納され、他のメールは/dev/null(つまり廃棄)。fetchmail側でkeepと書いているのでサーバ上には残される。格納先はどこでもいいのだが、Muttなどで読めた方が動作確認に便利なので、/var/spool/mailにしておいた。

次にpyPdfをダウンロードしてpython setup.py installする。

pyPdfのサンプルプログラムと、emailパッケージを使って添付ファイルを書き出すサンプルを適当にコピペして、適当なフォルダにPDFファイルと、PDFファイルからテキストを抜き出したファイルを生成するスクリプトを書く。

pdfmail.py
import os
import sys

import email
import mailbox
import mimetypes

import pyPdf

def pdfmail(msgfile):

    fp = open(msgfile)
    msg = email.message_from_file(fp)
    fp.close()

    counter = 1
    for part in msg.walk():
        if part.get_content_maintype() == 'multipart':
            continue
        fname = part.get_filename()
        if not fname:
            ext = mimetypes.guess_extension(part.get_type())
            if not ext:
                ext = '.bin'
            fname = 'part-%03d%s' % (counter, ext)
        counter += 1

        if fname.find('.pdf') != -1:

            print fname

            fp = open('pdf/'+fname, 'wb')
            fp.write(part.get_payload(decode=True))
            fp.close()

            c = getPDFContent('pdf/'+fname).encode("ascii","xmlcharrefreplace")
            fp = open('pdf/'+fname+".txt", 'wb')
            fp.write(c)
            fp.close()
def getPDFContent(path):
    content = ""
    pdf = pyPdf.PdfFileReader(file(path, "rb"))
    for i in range(0, pdf.getNumPages()):
        content += pdf.getPage(i).extractText() + "\n"
    content = " ".join(content.replace(u"\xa0", " ").strip().split())
    return content

if __name__ == '__main__':

    maildir = '/var/spool/mail/t.uehara'
    m = mailbox.Maildir(maildir)
    for key in m.keys():
        pdfmail(maildir+'/new/'+key)

最後に、こんな感じでバッチファイルを作って、Windowsのタスクスケジューラ等で定期的に回せばOK。

pdfmail.bat
C:\cygwin\bin\bash --login -i -c "fetchmail"
C:\cygwin\bin\python2.7.exe pdfmail.py