Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JJUG-2018-Fall-MF2

 JJUG-2018-Fall-MF2

Takeshi Nakamoto

December 15, 2018
Tweet

More Decks by Takeshi Nakamoto

Other Decks in Programming

Transcript

  1. Selenium WebDriverと
    ヘッドレスChromeを用いた
    スクレイピング
    2018/12/15 JJUG CCC 2018 Fall
    中本 武志
    1

    View Slide

  2. 自己紹介
    中本 武志(なかもとたけし)
    株式会社マネーフォワード(2016〜)
    サービス基盤本部アプリケーション部
    サーバーサイドエンジニア(Java)
    静岡県駿東郡長泉町在住
    2

    View Slide

  3. 3
    熱海
    小田原
    新横浜
    品川
    ● 通勤は約1時間
    ● 終電は品川発22:54
    ● 週1でリモート勤務
    ○ 保育園の送迎
    ○ 家事
    三島

    View Slide

  4. 内容
    1. ヘッドレスChromeの検討を始めた経緯
    2. ヘッドレスChromeの使い方
    3. アグリゲーションシステムへの組み込み
    4. まとめ
    開発中プロジェクトの内容となります。
    本番環境での運用を始めていないため、遭遇していない問題がある可能性があります。
    4

    View Slide

  5. 内容
    1. ヘッドレスChromeの検討を始めた経緯
    2. ヘッドレスChromeの使い方
    3. アグリゲーションシステムへの組み込み
    4. まとめ
    5

    View Slide

  6. マネーフォワードのアグリゲーションシステム
    ● カスタマイズした HtmlUnit を利用したスクレイピング
    ● OkHttp などを利用したAPI連携
    ● 様々な金融機関サイトに対応
    ● 毎分4000セッション
    https://github.com/HtmlUnit/htmlunit
    6

    View Slide

  7. 対応金融機関
    ● 銀行、など ・・・ 2279 サイト
    ● カード ・・・ 141 サイト
    ● 証券、投信、FX・貴金属 ・・・ 87 サイト
    ● ポイント ・・・ 41 サイト
    ● 電子マネー・プリペイド ・・・ 37 サイト
    ● 交通(JAL, ANA) ・・・ 12 サイト
    ● 通販(Amazon, 楽天) ・・・ 10 サイト
    ● 携帯 ・・・ 12 サイト
    ● など ・・・ 計 2678 サイト
    7

    View Slide

  8. 対応金融機関
    ● API連携でのアグリゲーションも増えている
    ○ 仕様が決まっているので、問題なくデータが取得できる
    ○ (基本的には)処理速度も速い
    ○ ログインパスワードなども預からない
    ● とはいえ大多数はスクレイピングを行っている
    ○ 最近スクレイピングが難しいサイトが増えてきた
    8

    View Slide

  9. スクレイピングの課題
    例1) MF KESSAI (https://mfkessai.co.jp/)
    スクレイピングしようとしたらエラーになった
    9

    View Slide

  10. スクレイピングの課題
    エラー内容
    Caused by: net.sourceforge.htmlunit.corejs.javascript.EcmaError:
    TypeError: Cannot find function resolvedOptions in object [object DateTimeFormat].
    https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat/resolvedOptions
    2012年ごろ策定されたAPI (?)
    10

    View Slide

  11. スクレイピングの課題
    エラー内容
    Caused by: net.sourceforge.htmlunit.corejs.javascript.EcmaError:
    TypeError: Cannot find function resolvedOptions in object [object DateTimeFormat].
    https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat/resolvedOptions
    2012年ごろ策定されたAPI (?)
    11
    エラーになる箇所と同等の処理を実装して回避

    View Slide

  12. スクレイピングの課題
    例2) HtmlUnitの改修
    とあるサイトのリニューアル後にスクレイピングできなくなった
    com.gargoylesoftware.htmlunit.ScriptException:
    ReferenceError: Assignment to undefined "getHoge" in strict mode
    var getHoge = function getHoge() {
    alert ('foo')
    }
    名前付き関数式でパースに
    失敗するパターンが存在した
    12

    View Slide

  13. スクレイピングの課題
    例) HtmlUnitの改修
    暫定対応後に、根本対応を行い、HtmlUnit に報告
    13

    View Slide

  14. スクレイピングの課題
    ● HtmlUnit ではスクレイピングが難しいサイトが増えた
    ● リニューアル等でこれまでできていたスクレイピングが
    できなくなることが増えた
    ○ 解決策を模索するコストが増加
    GUIなし(ヘッドレス)で動く本物のブラウザを使ったスクレイピング を
    選択できるようにしておく
    14

    View Slide

  15. ブラウザのヘッドレスモード
    ● 2018年7月当時、ヘッドレスモードがあったのは
    ○ Google Chrome v68
    ○ Mozilla Firefox v61
    ● とりあえず Chrome を使うことにした
    ○ ブラウザシェアの多い方に
    15

    View Slide

  16. 内容
    1. ヘッドレスChromeの検討を始めた経緯
    2. ヘッドレスChromeの使い方
    3. アグリゲーションシステムへの組み込み
    4. まとめ
    16

    View Slide

  17. ヘッドレスChromeとは
    Google Chrome v59 から利用できるようになった
    GUIなしでブラウザを動作させる機能
    https://developers.google.com/web/updates/2017/05/nic59 より
    17

    View Slide

  18. 制御方法
    ● Chromeをプログラムから操作する手段はいくつか存在する
    ○ puppeteer(パペティア) とかが有名
    ● Java アプリケーションから利用できるものは2つくらい
    ○ Chrome DevTools Protocol(CDP)
    ○ Selenium/WebDriver
    18

    View Slide

  19. 制御方法
    構成
    App
    App chromedriver
    WebSocket / CDP
    HTTP/JSON WebSocket / CDP
    19
    Selenium

    View Slide

  20. Chrome DevTools Protocol
    Chrome DevTools Protocol(CDP) を使って操作することができる
    ● WebSocket で通信
    ● JSON 形式のコマンド
    20
    https://chromedevtools.github.io/devtools-protocol/

    View Slide

  21. Chrome DevTools Protocol
    {
    "method": "Page.navigate",
    "params": {
    "url": "https://moneyforward.com/"
    }
    }
    ページ遷移コマンド
    DevTools Protocol エンドポイントに対して、コマンドを渡して操作する
    21

    View Slide

  22. Chrome DevTools Protocol
    DevTools Protocol のみだとけっこう煩雑
    22
    - 要素を検索 (DOM.performSearch)
    - 検索結果を取得 (DOM.getSearchResults)
    - 検索結果のボックス情報を取得 (DOM.getBoxModel)
    - ボックス情報から要素の中心座標を計算
    - 中心座標で mousePressed イベントを発火(Input.dispatchMouseEvent)
    - 中心座標で mouseReleased イベントを発火(Input.dispatchMouseEvent)
    (注: デバッガ経由での観察結果で、実装の一例です。)
    ある要素をクリックするために必要な処理

    View Slide

  23. Selenium WebDriver
    ブラウザ操作の自動化ツール
    ● Chrome も含めた、ブラウザ共通の操作用API
    ● 様々な言語での実装がある
    23

    View Slide

  24. Selenium WebDriver
    App
    chromedriver
    ブラウザ固有の
    WebDriver実装
    geckodriver
    edgedriver
    etc ...
    WebDriver
    クライアント
    JSON Wire Protocol
    (HTTP)
    24

    View Slide

  25. chromedriver
    chrome/chromium 向けの WebDriver 実装
    WebDriver 標準API以外にも、いろんなAPIが定義されている
    https://chromium.googlesource.com/chromium/src/+/master/chrome/test/chromedriver
    ● W3C standard endpoints
    ● Json wire protocol endpoints
    ● Extension commands from other specs
    ● ChromeDriver specific extension commands
    ● Commands of unknown origins
    CDPコマンドを渡すAPIもある
    25

    View Slide

  26. chromedriver
    指定可能なオプションやAPIの使い方などは
    テストコードを見てみるとわかりやすい
    https://chromium.googlesource.com/chromium/src/+/master/chrome/test/chromedriver/test/run_py_tests.py
    26

    View Slide

  27. chromedriver
    findElement というコマンドは最終的にJavaScript として実行されていた
    https://chromium.googlesource.com/chromium/+/trunk/third_party/webdriver/atoms.cc
    27

    View Slide

  28. CDP / WebDriver の比較
    機能(Chromeの場合)
    CDP WebDriver
    多機能
    (DevTools でできることができる)
    主にブラウザ操作関連
    WebDriver でできることはCDPでもできる
    28

    View Slide

  29. CDP / WebDriver の比較
    実装(Chromeの場合)
    CDP WebDriver
    - ほぼ自前で実装する必要がある
    (ライブラリはあったが、ライセンスの関係で
    見送った)
    - 学習コストが高そう
    (puppetterなどのライブラリの実装を読んで
    学んだ)
    - Selenium が提供するクラスが利用可能
    - ドキュメントが豊富
    - 事例も豊富
    29

    View Slide

  30. スクレイピングの要件
    アグリゲーションシステムに組み込むための最小限の要件
    1. プロキシの利用
    2. Cookie の利用
    3. ファイルダウンロードの利用
    2. と 3. については問題なく行えた。
    4. も動作サンプルは実装できた。
    30

    View Slide

  31. ファイルダウンロード
    HtmlUnit
    31
    ● 同一プロセス内で動作しているため、アプリケーションから直接アクセス可能
    ○ ダウンロード完了イベントなどもわかる
    ヘッドレスChrome
    ● 別プロセスのため、ファイルシステムを介して取得する必要がある
    ○ ダウンロード完了イベントも明示的に取得しないといけない

    View Slide

  32. ファイルダウンロード
    CDP
    ダウンロードディレクトリの指定
    Page.setDownloadBehavior コマンドで可能
    ダウンロード完了判定
    ディレクトリのファイル名判定(xxx.crdownload)
    または
    リクエスト完了イベントハンドリング(Network.loadingFinished)
    など
    32

    View Slide

  33. ファイルダウンロード
    WebDriver
    ダウンロードディレクトリの指定
    chrome 起動時のオプションとして設定可能
    (prefs.download.default_directory)
    ダウンロード完了判定
    ディレクトリのファイル名判定(xxx.crdownload)
    または
    リクエスト完了イベントハンドリング(Network.loadingFinished)
    Performance Log を有効にするとCDPと同様のイベントログを取得できる
    33

    View Slide

  34. どちらを使うか
    ● CDPのほうがいろいろできるが、実装コストが高い
    ● WebDriver は機能としてはCDPに劣るが、ライブラリの整備な
    どを考えると使いやすい
    実験的な位置づけで、速くリリースに持っていけるWebDriverを採用
    34

    View Slide

  35. 内容
    1. ヘッドレスChromeの検討を始めた経緯
    2. ヘッドレスChromeの使い方
    3. アグリゲーションシステムへの組み込み
    4. まとめ
    35

    View Slide

  36. スクレイピング実装
    HtmlUnit API WebDriver
    WebDriver を利用するサービスは、Chrome 及び chromedriver がインストール
    された特定のサーバーに振り分ける実装を追加
    36

    View Slide

  37. 構成
    アグリゲーション chromedriver
    外部サービス
    systemd
    外部サービス
    外部サービス
    server
    37

    View Slide

  38. 構成
    ● chromedriver は daemon として起動しておく
    ○ スクレイピングセッション毎にchromedriverとchromeが起
    動するのは重そうだったので(感想)
    ○ 同時スクレイピング数を絞った状態でリリースして調整す
    る予定
    38

    View Slide

  39. 追加開発した機能
    ● Selenium 提供の機能でほぼ対応できた
    ● chrome が起動しっぱなしにならないよう確実に閉じるようにし

    ● 既存の開発スタイルに合わせるため、明示的な待機の実装を
    ラップ
    ○ 指定時間を過ぎても例外を投げないで戻す
    ○ エラー画面になったことを検出できるようにした
    39

    View Slide

  40. 使ってみた感想1
    ● スクレイピングできなかったサイトができるようになって
    単純にうれしい
    ○ スクレイピングできないサイトがなくなった感がある
    ● HtmlUnit と比べてそこまで遅くなった感じはない
    ○ ページ遷移時などは速く感じることも
    ○ 外部サイトとの通信にかかる時間のほうが大きい
    ○ 単純な動作速度よりも、正しいデータを取得できるようになるこ
    とのほうが重要なため問題ない
    40

    View Slide

  41. 使ってみた感想2
    ● けっこうリソースを消費する(CPU/メモリ)
    ○ 同時接続数を増やした場合の負荷がどうなるか
    ○ 計測した値を元に調整していく
    ● chrome のバージョンアップなどへの追従はどうするか
    ○ apt では基本的に最新バージョンしかインストールできない
    ○ リポジトリをコピーしてくるなどが必要そう
    ● 既存のライブラリ資産を使えるようにしたい
    ○ HtmlUnit 提供のクラスのラッパーなど
    ○ 便利メソッドを使えるように改修しないといけない
    41

    View Slide

  42. 内容
    1. ヘッドレスChromeの検討を始めた経緯
    2. ヘッドレスChromeの使い方
    3. アグリゲーションシステムへの組み込み
    4. まとめ
    42

    View Slide

  43. まとめ
    ● HtmlUnit 以外のスクレイピングの選択肢を準備したい
    ○ そのためにヘッドレス chrome を使う
    ● Chrome DevTools Protocol は使えたら使いたい
    ○ ライブラリ整備ができれば
    ● WebDriver 便利
    ○ サクッと使い始められる
    ○ chrome のバージョンアップ等の運用に課題
    ○ リソースは結構消費する模様
    ● 定量的な評価は今後の課題
    43

    View Slide

  44. Thank you!
    44

    View Slide

  45. Javaエンジニア募集中
    ● 扱うデータへ強い責任感をお持ちの方
    ● この世界に流れるデータを綺麗にしたい!というパッションをお持ちの方
    ● 大規模トラフィックを捌いてみたい方
    ● ミドルウェアを使い倒したい方
    45

    View Slide