パソコンスキルの教科書

パソコンスキルの教科書

東京大学大学院卒。博士課程に進学を志すも、担当教授と折が合わず、無職になる。医者を目指すも結局断念。田舎で派遣社員として働く。「スキルがなければ、仕事ももらえない」と悟り、ビジネススキルを学ぶ。プログラミング、英語を学び、一部上場企業へ転職。年間100時間以上の業務効率化を行い、社内講師に抜擢。海外の案件を担当し、数億円のプロジェクトに携わる。個人の事業でも、月売上100万を達成。現在は、自分の価値を高めるためのスキル向上支援を行う

マクロVBAでPDFを読み込み、テキスト抽出してエクセルに一覧にする方法

f:id:gene320:20180320235245j:plain

PDFの情報をコピペして手動で書き写す人は多いです。例えば、PDFのテキスト情報を目視しながら、一つずつエクセルにコピペしていく作業があります。

この場合、PDF数枚程度なら、一枚ずつコピペしても、大変さを感じることはありません。ただ100枚以上のPDFをコピペする作業となると、話は違います。

コピペ作業だけで、数時間かかる場合もありますし、何よりもその仕事があると思っただけで、仕事へのモチベーションが低下してしまいます。

しかし、定型のPDFであれば、このようなコピペ作業はエクセルマクロVBAで解決することができます。

この記事では、エクセルマクロVBAを利用して、PDFの必要情報だけを取得してエクセルに一覧にする方法を紹介します。

マクロVBAでPDFを読み込み、テキスト抽出してエクセルに一覧にする方法|

PDFの情報を自動でエクセルに一覧にした事例を動画で紹介

PDFの情報をエクセルに一覧にする仕事と聞くと、あまりイメージしづらいかもしれません。そこで、PDF情報の必要部分だけをエクセルで自動取得した方法を事例を用いて紹介します。

まずは、こちらの動画をご覧ください。PDFの情報を取得して、エクセルに書き込んでいきます。

youtu.be

この動画で実行している内容は、所定のフォルダに保管した全てのPDFを一つずつ読み込み、必要情報だけをエクセルに一覧にしています。ちなみに、PDFはメールで送られてきた請求書です。

こういった作業は、PDF1枚であればマクロを使う必要はありません。しかし、PDFの枚数が200~300枚となると、一枚ずつコピペしていては仕事が終わりません。

しかも、1枚のPDFから複数個所をコピペする必要があると、かなり辛い作業になってしまいます。

PDFからテキスト情報を取得するときのコツ|ワード変換やテキスト変換ではうまくいかない

PDFからテキスト情報を取得する場合、PDFをワード変換したりテキスト変換したりすることを考える人は少なくありません。しかし、PDF→ワードやPDF→テキストでは、うまくいかないことが多いです。

なぜなら、PDF毎に記載量が違うからです。例えば、PDFをワードやテキストに変換すると、PDF毎にワードやテキストの行数が変化します。つまり、取得したい箇所がPDF毎に変化するのです。

その結果、マクロのプログラムを工夫しないと、特定の情報を取得するのが難しくなってしまいます。

では、どのようにすればいいのかというと、PDFをxmlに変換して、情報を取得します。xmlに変換する方法がシンプルなマクロで稼働します。

ただテキスト抽出したいの記載量が少ない場合はワードやテキスト変換でもうまくいく場合があります。

PDFのテキストを抽出してエクセルに書き出すプログラム

それでは、マクロVBAを使ってPDFのテキストを読み込み、必要箇所をエクセルに一覧にする方法を紹介します。動画で紹介した請求書PDFの情報をエクセルに一覧にするのを考えます。

具体的には、以下のような作業を自動化します。

[1] エクセルに一覧にしたいPDFファイルを所定のフォルダに集める(ここは手動)
[2] フォルダ内の請求書PDFを全て読み込む
[3] エクセルに出力する

詳しく紹介すると、以下のように流れです。

[1] エクセルに一覧にしたいPDFファイルを所定のフォルダの画像

f:id:gene320:20180320232650p:plain

フォルダ内のPDFを全て処理します。

[2] 請求書PDFの画像

f:id:gene320:20180320232703p:plain

①の取引に関する情報、②の金額について情報に関してテキスト抽出し取得します。

[3] エクセルの画像

f:id:gene320:20180320232809p:plain

上記の赤枠に[2]の請求書の項目を入れていきます。

このプログラムは所定のフォルダにあるPDFを一つずつ読み込み、エクセルにリスト化していきます。

VBAのプログラムを作る前にAcrobat、FSO操作の参照設定を行う

エクセルVBAでPDFを操作するためのプログラミングに入る前に、準備することがあります。

それは、VBEの参照設定を変更することです。参照設定とは、機能拡張のことです。

このプログラムを使うのには、参照設定で以下の2つをライブラリに追加する必要があります。

設定方法

1.VBEを開いて頂いて、「ツール」→「参照設定」
2.この二つのライブラリにチェックを入れて、OKをクリック
・Acrobat
・Microsoft Scripting Runtime

この設定を変更しないとマクロが動きません。忘れずに設定するようにしてください。

参照の設定手順|VBEの参照設定でAcrobatとMicrosoft Scripting Runtimeを追加

VBAでPDFを操作できるようにするために、AcrobatとMicrosoft Scripting Runtimeにチェックを入れます。

具体的な設定方法は以下の通りです。

1.VBEを開いて、「ツール」→「参照設定」

f:id:gene320:20170613213650p:plain

2.以下の2項目にチェックを入れて、OKをクリック
・Acrobat
・Microsoft Scripting Runtime

Acrobatはこちら

f:id:gene320:20171229230846p:plain

MicroSoft Scripting Runtimeはこちら

f:id:gene320:20171229013436p:plain

なお、VBAでフォルダを操作できるようにするために、Microsoft Scripting Runtimeにチェックを入れます。

Microsoft Scripting Runtimeにチェックを入れる理由は、この記事で紹介するプログラムが、特定フォルダ内のすべてのPDFファイルを読み込む際に、Microsoft Scripting Runtimeを利用するからです。

注意|Acrobat操作には、Acrobat Proを利用する必要がある

あなたが使っているパソコンにAcrobat Readerしか含まれていなかったとしたら、VBAでPDF操作はできません

そのため、PDFを操作する場合は、Acrobat Proを購入しておく必要があります。参照設定で、Acrobatをチェックできないならば、Acrobat Proに登録されていないことを意味しています。

したがって、こちらからAcrobat Proを試すことができます。なお、Acrobat Standardでも可能だと思われますが、検証しておりません。

PDFのテキストを読み込み、エクセルに一覧にするプログラム

プログラムは以下のとおりです。

'---コード1|フォルダ内のPDFファイルを1つずつ処理する
Option Explicit
Sub filecheck()
    Dim s1, s2, s3, filename, path, xmlpath As String
    Dim i, cmax As Long
    Dim t1, t2 As Date
    Dim ws1, ws2 As Worksheet
    Set ws1 = Worksheets("データ一覧")
    
    Dim fs As FileSystemObject
    Dim basefolder As Scripting.Folder
    Dim destifolder, filepath As String
    
    Dim mysubfiles As Scripting.Files
    Dim mysubfile As Scripting.File
    
    cmax = ws1.Range("A65536").End(xlUp).Row
    Set fs = New Scripting.FileSystemObject
    
    filepath = ThisWorkbook.path & "\Analysis"
    
    Set basefolder = fs.GetFolder(filepath)
    Set mysubfiles = basefolder.Files
    
    
    For Each mysubfile In mysubfiles
        Debug.Print mysubfile.Name
        Debug.Print fs.GetExtensionName(mysubfile)
        Debug.Print fs.GetParentFolderName(mysubfile)
        
        If fs.GetExtensionName(path:=mysubfile) = "pdf" Then
            
            path = fs.GetParentFolderName(path:=mysubfile)
            xmlpath = xmlurl(mysubfile.Name, path)
            Call xml_parse(xmlpath)
        End If
    Next

End Sub
'---コード2|PDF毎にxml化する
Function xmlurl(filename, path)
    
    Dim objAcroApp As New Acrobat.AcroApp
    Dim objAcroAVDoc As New Acrobat.AcroAVDoc
    Dim objAcroPDDoc As Acrobat.AcroPDDoc
    Dim id As Long
    Dim js As Object
    Dim fullpath, savename As String
    
    fullpath = path & "\" & filename
    Debug.Print fullpath
    id = objAcroApp.Show 'Acrobatアプリケーションを起動する。
    id = objAcroAVDoc.Open(fullpath, "")
    Set objAcroPDDoc = objAcroAVDoc.GetPDDoc()
    'JavaScriptオブジェクトを作成する。
    Set js = objAcroPDDoc.GetJSObject
    savename = Replace(fullpath, ".pdf", "")
    js.SaveAs savename & ".xml", "com.adobe.acrobat.xml-1-00"
    
    'PDFファイルを変更無しで閉じます。
    id = objAcroAVDoc.Close(1)
    'Acrobatアプリケーションを終了する。
    id = objAcroApp.Hide
    id = objAcroApp.Exit
    'OLEを行うとAcrobatが不安定になるので、
    '一応オブジェクトを強制開放する。
    Set js = Nothing
    Set objAcroAVDoc = Nothing
    Set objAcroApp = Nothing
    
    xmlurl = savename & ".xml"
    
End Function

'---コード2|フォルダ内のPDFファイルだけを抽出
Sub xml_parse(ByVal xmlpath As String)
'Microsoft XML v6.0 を参照設定
    Dim XMLDocument As MSXML2.DOMDocument60
    Dim pElem     As MSHTML.HTMLParaElement
    'Dim Doc As New XMLDocument
    Dim e As MSHTML.HTMLHtmlElement
    Dim ws1 As Worksheet
    
    Set ws1 = Worksheets("データ一覧")
    
    'MSXMLオブジェクトを生成し、xmlファイルをロード
    Set XMLDocument = New MSXML2.DOMDocument60
    
    'async = False → 読み込み終了後、次の処理をします(同期処理)
    'async = true →だと、読み込みが終わらなくても、次のステップへ(非同期処理)
    'VBAは非同期処理に対応していないので、async = Falseとします
    XMLDocument.async = False
    
    Dim strMsg As String
    Dim i, j, k, cmax, n As Long
    
    i = 0
    cmax = ws1.Range("A1048576").End(xlUp).Row
    'Doc.Load (xmlpath)
    XMLDocument.Load (xmlpath)
    
    If (XMLDocument.parseError.ErrorCode <> 0) Then 'ロード失敗
        
        strMsg = XMLDocument.parseError.reason      'エラー内容を出力
        
        MsgBox "ロードに失敗しました・・・" & vbCrLf & vbCrLf & strMsg, vbCritical
        
        Exit Sub
    
    End If
    
    ws1.Range("A" & cmax + 1).Value = cmax
    
    Dim objxml As Object
    Dim tmp As Variant
    
    For Each objxml In XMLDocument.getElementsByTagName("P")
        If InStr(objxml.XML, "請求番号") > 0 Then
        
        tmp = Split(objxml.Text, ":")
            
            For k = 0 To UBound(tmp)
                Debug.Print tmp(k)
                If InStr(tmp(k), "請求日") > 0 And InStr(tmp(k), "請求日の") = 0 Then 
                    ws1.Range("B" & cmax + 1).Value = Left(tmp(k), Len(tmp(k)) - 3)
                
                ElseIf InStr(tmp(k), "支払期日") > 0 Then
                    ws1.Range("C" & cmax + 1).Value = Left(tmp(k), Len(tmp(k)) - 4)
                    
                ElseIf InStr(tmp(k), "貴社コード") > 0 Then
                    ws1.Range("D" & cmax + 1).Value = Mid(tmp(k), 2, Len(tmp(k)) - 6)
                
                ElseIf InStr(tmp(k), "契約番号") > 0 Then
                    ws1.Range("E" & cmax + 1).Value = Mid(tmp(k), 2, Len(tmp(k)) - 5)
                    
                ElseIf InStr(tmp(k), "支払方法") > 0 Then
                    ws1.Range("F" & cmax + 1).Value = Left(tmp(k), Len(tmp(k)) - 4)
                
                ElseIf k = UBound(tmp) Then
                    ws1.Range("G" & cmax + 1).Value = Mid(tmp(k), 2)
                    
                End If
            Next
            
            tmp = Null
    
        End If
    Next
  
    j = 0
    
    Dim cnode, dnode As IXMLDOMNode
    Dim str() As Variant
    Dim tdvar As Variant
    
    Set cnode = XMLDocument.SelectSingleNode("//Table")
    
    j = 0
    For Each dnode In cnode.getElementsByTagName("TD")
        ReDim Preserve str(j)
        str(j) = dnode.Text
        Debug.Print j, str(j)
        j = j + 1
    Next
    
    Dim kingaku, zeigaku As Double
    Dim tekiyou As String
    kingaku = 0
    zeigaku = 0
    tekiyou = ""
    
    For j = 0 To UBound(str)
        k = 4 * j + 1
        If InStr(str(k), "ご請求") > 0 Then
            ws1.Range("H" & cmax + 1).Value = kingaku
            ws1.Range("I" & cmax + 1).Value = zeigaku
            ws1.Range("J" & cmax + 1).Value = kingaku + zeigaku
            ws1.Range("K" & cmax + 1).Value = tekiyou
            Exit For
        
        ElseIf InStr(str(k), "消費税") > 0 Then
            zeigaku = zeigaku + str(k + 2)
        
        ElseIf str(k) <> "" Then
            kingaku = kingaku + str(k + 2)
            If tekiyou = "" Then
                tekiyou = str(k)
            End If
        End If

    Next
End Sub

プログラムの解説は要望があれば行います。ただ、ここで紹介している内容は簡単な内容ではありません。配列を使ったり、XML化を使ったりしてPDF内のテキストを取得しています。

もし、詳しく知りたい人は問い合わせから質問してみてください。

VBAを使ったPDF操作について、もっと知りたいなら

エクセルVBAを使ったPDF操作する方法について、解説した記事を紹介します。

www.fastclassinfo.com

www.fastclassinfo.com

www.fastclassinfo.com

PDF操作を習得より、VBA基礎作りが先決

エクセルVBAを使ったPDFからのテキスト抽出の方法について事例で紹介しました。今回の内容をぜひVBAの勉強に活かしてみてください。

ここで紹介したコードを編集して利用すれば、VBAでPDFを解析することができるはずです。

しかし、PDF操作のプログラムを編集するといっても、「私にできるかな、、、」と感じている方もいるかもしれません。

もし、そのように感じているなら、それはマクロの基本がまだできていない証拠です。

実際、エクセルVBA初心者がPDF操作でエラーを起こすと、一人で解決するのはムズカシイでしょう。

もし、このプログラムをみて、レベルが高いなと感じたら、VBAの基本から学びなおすことをオススメします。

VBAの基本が分かれば、PDFだけでなくアウトルックやIE操作も本当の意味で理解できるようになります。

きちんと学ぶなら、こちらの無料動画がオススメです。基礎を確実に学んでから、トライしてみてください。

この記事を読んだ方へのオススメ

「マクロの力を実感したい」と感じているなら、こちらの記事がオススメです。マクロが入ったエクセルファイルをダウンロードできるようにしています。もし詳細が知りたいなら、以下の記事で紹介していますので、合わせて読んでみてください。

サンプル1|月末処理の自動処理する
サンプル2|エクセルで在庫管理するマクロ
サンプル3|outlookのメールを自動送信する
サンプル4|outlookの受信メールをエクセルに一覧にして、添付ファイルも保管する
サンプル5|エクセルマクロVBAで大量データを比較・照合してマッチングする方法
サンプル6|ウェブの情報を自動取得して、エクセルに出力する
サンプル7|エクセルの情報をワードに差し込み、印刷まで行う

ぜひご活用ください。

エクセルマクロでできることを知りたいなら

www.fastclassinfo.com

エクセルマクロを独学で習得したいなら

www.fastclassinfo.com

エクセルマクロとは?もっと詳しく知りたいなら

www.fastclassinfo.com

エクセルマクロの難易度や習得までの期間を知りたいなら

www.fastclassinfo.com