Notes開発者のためのXPagesデザインレシピ

簡単でCoolなXPagesアプリケーションを作るための情報を発信していきます

コーディング フォーム

Notesクライアントでも使える-LotusScriptでスクレイピング

はじめに

このブログはXPages専門ですが、今回はDominoV10で追加された「NotesHTTPRequest」クラスを使って、NotesクライアントでWebスクレイピングしてみます。

 

スクレイピングとは何か?

ウェブサイトのHTMLから必要な情報を抽出することをスクレイピングと言います。
利用シーンとしては、RESTAPIのサービスから情報を取得することに似ていますが、HTMLから抽出するのでWebページさえあれば抽出できる点が利点です。
自社で使っているWebサービスがRESTAPIインターフェスを提供しておらずサービス連携出来ない場合や、外部RESTAPIサービスが有料で高すぎるなどの場合も一考の余地があります。
※Amazonや楽天などスクレイピングを明確に禁止している会社、サービスもあるので、事前調査を行った上で実装して下さい。

 

ゆうパックのお問い合わせ番号検索をスクレイピング

お問い合わせ番号検索は、Googleで検索して、該当のサービス事業者へ飛ぶ方が多いと思いますが、今回はGoogleが生成するURLを使います。お問い合わせ番号を検索した後の画面で「日本郵便の荷物 xxxx-xxxx-xxxxを追跡」を右クリックし、リンクのアドレスをコピーすると下記のようなURLが取得出来ます。
http://tracking.post.japanpost.jp/services/srv/search/direct?reqCodeNo1=xxxxxxxxxxxx&locale=ja

上記URLのxxxxxxxxxxxx(12桁の数字)部分がお問い合わせ番号になります。
このお問い合わせ番号は4桁区切りのxxxx-xxxx-xxxxでも、12桁連続のxxxxxxxxxxxxでも動作するようです。

実際のスクレイピングはブラウザの開発者モードを使ってHTMLを解析することから始まります。

今回欲しい情報は下記の順番で取得出来ます。

  1. ページに存在する3つの<table>タグから2つめの<table>を取得する。
  2. 取得した<table>タグ内の<tr>タグから後ろから2つ目の<tr>タグを取得する。
  3. 取得した<tr>タグ内の<td>タグの1つ目に「最新の状態日時」、2つめに「配送状態」が保存されているので、この情報を取得する。

 

実装①:フォームを作る

4つのテキストフィールドを作成し、お問い合わせ番号の下に「お問い合わせ」ボタンを作成します。

項目名 フィールド名 用途
お問い合わせ番号 TrackingId お問い合わせ番号を入力する。(手入力)
お問い合わせ結果HTML Response HTMLレスポンスをそのまま書き込む。参考用。
現在のステータス TrackingStatus スクレイピング結果
ステータス日時 TrackingDateTime スクレイピング結果

 

実装②:お問い合わせボタンにLotusScriptを書き込む

HTTPリクエストを実行し、HTMLを取得する部分はDominoV10から実装された「NotesHTTPRequest」クラスを利用します。
取得したHTMLに対して、スクレイピングを行うにはHTMLを解析する必要があります。文字列操作でも解析できますが、大変なので今回は「Microsoft HTML Object Library」オブジェクトを作成し、このオブジェクトにHTMLレスポンスを入れ、Chromeの開発者ツールで解析した通りにコード化していきます。
「Microsoft HTML Object Library」で作成したオブジェクトは、VBAの場合Object型で取得しますが、LotusScriptの場合Variant型で取得します。
また「Microsoft HTML Object Library」のメソッドは、VBAの場合、作成したオブジェクトの後ろに「vDoc.write」と記述出来ますが、LotusScriptではコードチェックに引っかかるので、With~End Withを使ってメソッド名のみ記述していきます。

「お問い合わせ」ボタンにLotusScriptで下記のコードを記述します。

【LotusScriptソース】

Sub Click(Source As Button)
    Const URL        = https://trackings.post.japanpost.jp/services/srv/search/direct?reqCodeNo1=
    Const PARAM     = "&locale=ja"
    
    Dim ws                As New NotesUIWorkspace
    Dim uidoc            As NotesUIDocument
    Dim session         As New NotesSession
    
    Dim http            As NotesHTTPRequest        'DominoV10以降
    
    Dim sUrl            As String                    '送信するURL
    Dim sTrackingId     As String                    'お問い合わせ番号
    Dim vResponse        As Variant                    'HTTPRequestからの戻り値
    
    Dim vDoc            As Variant            'Microsoft HTML Object
    Dim vTableList        As Variant            'Responseに含まれるTableタグリスト
    Dim vTable            As Variant            '取得したいTableタグ
    Dim vTrList            As Variant            'Tableタグに含まれるTrタグリスト
    Dim vTr             As Variant            '取得したいTrタグ
    Dim vTdList         As Variant            'Trタグに含まれるTdタグリスト
    Dim vTd             As Variant
    
    'フィールドの値を取得して、リクエストURIを生成
    Set uidoc = ws.CurrentDocument
    sTrackingId = uidoc.FieldGetText("TrackingId")
    sUrl = URL + sTrackingId + PARAM
    
    'Getリクエストを実行し、結果を取得
    Set http = session.CreateHTTPRequest()
    vResponse = http.Get(sUrl)    
    
    'HTTPレスポンスをそのまま書き込み
    Call uidoc.FieldSetText("Response", vResponse)
    
    'HTML解析(スクレイピング本体)
    Set vDoc = CreateObject("htmlfile")
    With vDoc
        .write vResponse
        Set vTable = .getElementsByTagName("table")(1)            '0から始まるので2個目のTableは1と指定
        With vTable
            Set vTrList = .getElementsByTagName("tr")            'Trタグリストを取得
            With vTrList
                Set vTr = .Item(.Length - 2)                        'Trタグリストの後ろから二つ目(最新レコード)を取得
                With vTr
                    Set vTdList = .getElementsByTagName("td")
                    With vTdList
                        Set vTd = .Item(0)
                        Call uidoc.FieldSetText("TrackingDateTime",vTd.innerText)
                        Set vTd = .Item(1)
                        Call uidoc.FieldSetText("TrackingStatus",vTd.innerText)
                    End With
                End With
            End With
        End With
    End With

    Call uidoc.Refresh()
End Sub

 

実行結果とまとめ

実行すると、「お問い合わせ結果HTML」にHTMLレスポンスが書き込まれ、「現在のステータス」「ステータス日時」にスクレイピング結果が書き込まれます。
フォーム上のアクションボタンに実装した場合は、Webで検索するのと同じなのでそれほど活用シーンはないかもしれませんが、定期実行エージェントに実装して、現在の状態が「お届け先にお届け済み」に変わってからお客様に電話連絡するとか、発送状態を一括で確認したいなどの仕組みを構築できるかと思います。