PythonのSeleniumでログインありのwebページをPDF保存する


はじめに

  • Python の Selenium を使って、ログインありの web サイトのページを pdf としてダウンロードした時のメモです
  • Selenium は自動でブラウザを操作できるツールです。web ページの自動テストなどに使う事が多いようです

環境

  • macOS Mojave 10.14.6
  • python 3.6.0
  • Chrome

事前準備

以下ライブラリを pip でインストールします

  • selenium
  • chromedriver-binary
pip install selenium chromedriver-binary

selenium での操作

ドライバの設定

  • selenium でブラウザを操作するために必要なドライバをインスタンス化します
import chromedriver_binary
from selenium import webdriver

options = webdriver.ChromeOptions()
driver = webdriver.Chrome(options=options)

ログインする

  • セキュリティのため、ログインに必要な id とパスワードを環境変数から読み取るようにします
import os

login_id = os.environ["MY_LOGIN_ID"]
login_password = os.environ["MY_LOGIN_PASSWORD"]
  • driver.get()で URL を指定し、ログインページを取得します
  • 今回はログイン対象ページの ID/パスワードを入力するテキストボックスとログインボタンが id 属性値で特定できたため、driver.find_element_by_id()でページの要素を取得します
  • 取得した要素に対してsend_keys()で値を入力し、submit()でログインします
driver.get("<ログインページのURL>")
driver.find_element_by_id("username").send_keys(login_id)
driver.find_element_by_id("password").send_keys(login_password)
driver.find_element_by_id("authform").submit()

クリックする

  • 取得した要素に対してclick()でクリックします
driver.find_element_by_id("hogeid").click()

表の中の要素を取得する

  • 表の中の要素の取得にはfind_elements_by_xpath()を使いました
  • XPath の取得には chrome のデベロッパーツールが便利です。対象要素の HTML を右クリックして Copy XPath でコピーできます
  • 以下のような表のdataA-2のリンクを取得したいとします
header1 header2 header3
dataA-1 dataA-2 dataA-3
dataB-1 dataB-2 dataB-3
html
<table class="hoge fuga piyo">
  <thead>
    <tr>
      <th>header1</th>
      <th>header2</th>
      <th>header3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>
        dataA-1
      </td>
      <td>
        <a href="http://dummy">dataA-2</a>
      </td>
      <td>
        dataA-3
      </td>
    </tr>
    <tr>
      <td>
        dataB-1
      </td>
      <td>
        <a href="http://dummy">dataB-2</a>
      </td>
      <td>
        dataB-3
      </td>
    </tr>
  </tbody>
</table>
python
driver.find_element_by_xpath(
            "//table[contains(@class,'hoge')]/tbody/tr[1]/td[2]/a")
  • 今回は取得したい表の class が複数指定されていたのでcontainsでフィルタしました
  • class が一つの場合は"//table[@class='hoge']/tbody/..."でよさそう

指定した秒数待つ

  • ページに遷移してから表の表示に少し時間がかかっていたようで、要素の取得ができなかったことがありましたが、implicitly_wait()で待ち時間を設定するとうまくいきました
driver.implicitly_wait(n)

ページを pdf としてダウンロードする

  • chrome の印刷機能で pdf として保存します
  • ドライバにオプションを追加し、ダウンロードするパスを指定します
  • ドライバのオプションに--kiosk-printingを加えると、印刷ダイアログを開いた後に自動で印刷ボタンを押してくれます
    • ドライバのオプションに--headlessオプションを加えると、ブラウザを立ち上げずに実行する「ヘッドレスモード」で実行できますが、--kiosk-printingオプションとの併用はできないようです。実際に併用してみましたが pdf をダウンロードできませんでした(悲)
ドライバの設定
options = webdriver.ChromeOptions()

options.add_experimental_option("prefs", {
    "download.default_directory": "~/Downloads"
})

options.add_argument('--kiosk-printing')

driver = webdriver.Chrome(options=options)
  • 印刷ダイアログを開くためには、javascript を実行するexecute_script()を使用しました。ドライバの--kiosk-printingオプションにより、これでPDFが保存されます
driver.execute_script('window.print();')

参考