みずりゅの自由帳

主に参加したイベントやソフトウェア技術/開発について記録しています

go-wkhtmltopdfでHTMLをPDF出力

自分が担当している運用作業の中で、数十個のグラフが表示されるHTMLをPDFに変換して、そのPDFをエビデンスとして保管する作業があります。

これまではHTMLをブラウザに表示した後に印刷ボタンを押し、出力先をPDFにするという手順で実施していました。最初は手動で実施していたのですが、途中から何度も実施するのが面倒になってきました。

なら自動化するか、ということでブラウザの操作を自動化する方法を探していましたが、wkhtmltopdfというHTMLをPDFに変換するコマンドラインツールを見つけたので利用することにしました。ライセンス形態はLGPLv3です。
ついでに、go-wkhtmltopdfというGo言語でwkhtmltopdfを呼び出せるライブラリも見つけたので、Go言語で簡単なスクリプトを書くことにしました。

wkhtmltopdfのインストール:

https://wkhtmltopdf.org/downloads.html

上記のURLから、自分のOSに該当するパッケージをダウンロードして適用してください。
なお、自分の場合は「CentOS 7」でしたので、以降はCentOS 7上で実施する例で記述します。
※ wkhtmltopdfのバージョンは、2019.03.20時点で最新である「0.12.5」で記載しています。

$ wget https://downloads.wkhtmltopdf.org/0.12/0.12.5/wkhtmltox-0.12.5-1.centos7.x86_64.rpm

CentOS では、インストールの際に必要なライブラリを事前にインストールしておく必要があります。(無いとwkhtmltopdfのインストール時にエラーが出ます。)

$ sudo yum install xorg-x11-fonts-75dpi xorg-x11-fonts-Type1 libXext libXrender

日本語も扱う場合は、以下の日本語フォントもインストールしておきます。

$ sudo yum install ipa-mincho-fonts ipa-gothic-fonts ipa-pmincho-fonts ipa-pgothic-fonts


ライブラリのインストールが終わったら、rpmをインストールする。

$ sudo rpm -Uvh wkhtmltox-0.12.5-1.centos7.x86_64.rpm

インストールが完了したら、バージョンの確認でパスが通っているか確認。インストールした0.12.5が表示されました。

$ wkhtmltopdf --version

wkhtmltopdf 0.12.5 (with patched qt)   ・・・ 表示されたバージョン。

実際にPDFファイルを作ってみます。一つ目の引数(URL or HTML)が変換元のHTML、二つ目の引数が変換後のPDFのファイル名となります。

$ wkhtmltopdf "http://www.yahoo.co.jp/" sample.pdf

Proxy配下だったり、アクセス先でBasic認証などが発生する場合は、以下のようになります。

$ wkhtmltopdf --username userhoge --password passhoge -p http://proxy.server.jp:8080  "https://yourserver.example.com/sample" sample.pdf

認証の場合、ユーザ/パスワードは「--username <ユーザ名> --password <パスワード>」のように指定します。
Proxyサーバの指定は「-p <http(s)://プロキシサーバ名:ポート番号>」のように指定します。
上記以外のオプションは「wkhtmltopdf -h」で確認してください。
以下のファイルからも確認できます。
https://wkhtmltopdf.org/usage/wkhtmltopdf.txt

go-wkhtmltopdfのインストール:

特に難しいことはありません。go getで入手します。

$ go get -u github.com/SebastiaanKlippert/go-wkhtmltopdf

その後、利用するGoのコードに「"github.com/SebastiaanKlippert/go-wkhtmltopdf"」をインポートしてください。

go-wkhtmltopdfの利用:

大きく以下の流れになります。

  1. PDFジェネレータの生成
  2. PDFジェネレータに対して変換対象となるURL(or HTML)を設定
  3. PDF データを生成
  4. PDFデータをファイルに出力

以下、サンプルになります。
PDFを2個作るため、sliceでデータ(HTMLファイル名とPDFファイル名)を持たせています。
また、Proxy配下のローカル環境からBasic認証が必要なサーバにアクセスする、という前提で作っています。
※2019.04.20追記:2つ目以降のPDFで以前のページが残ったまま出力されていたので、NewPDFGeneratorをループ内に入れました。

package main

import (
    "fmt"
    "github.com/SebastiaanKlippert/go-wkhtmltopdf"
    "log"
)

func main() {

    // PDF変換対象のデータをSliceで用意
    pdfs := []struct {
        input string
        output string
    }{
        {"../test1.html", "../pdf/test1.pdf"},
        {"../test2.html", "../pdf/test2.pdf"},
    }

    // PDFにしたい分、ループで回す。
    for _, tt := range pdfs {

        // 変換対象となるページ(URL or HTML)をPage型にする。
        page := wkhtmltopdf.NewPage(tt.input)

        // Proxy配下の際の設定
        page.PageOptions.Proxy.Set("http://proxy.server.jp:8080")

        // BASIC認証対応
        page.PageOptions.Username.Set("userhoge")
        page.PageOptions.Password.Set("passhoge")

        // PDF Generatorの生成
        pdfg, err := wkhtmltopdf.NewPDFGenerator()
        if err != nil {
            log.Fatal(err)
        }
        // PDFジェネレータに対して変換対象となるURL(or HTML)のPage型を設定
        pdfg.AddPage(page)

        // PDFデータを作成
        err = pdfg.Create()
        if err != nil {
            log.Fatal(err)
        }

        // PDFデータをファイルに出力
        pdf := tt.output
        fmt.Println("pdf output:", pdf)
        err = pdfg.WriteFile(pdf)
        if err != nil {
            log.Fatal(err)
        }
    }
    fmt.Println("complete.")
}

利用するProxyの指定や、ベーシック認証のユーザ名/パスワードは、Page型の「PageOptions」経由で指定します。
コード中にも記載していますが、利用するProxyサーバを指定したい場合は、以下のように「PageOptions.Proxy」に対して「Set("<http(s)://プロキシサーバ名:ポート番号>")」と記載します。

    page.PageOptions.Proxy.Set("http://proxy.server.jp:8080")

PageOptionsにどのような設定項目があるかは、以下のコードから確認できます。
Page型以外(例えば、HeaderやFooterなど)にもオプションがあるので、それらも合わせて確認できます。

https://github.com/SebastiaanKlippert/go-wkhtmltopdf/blob/master/options.go