Python
Selenium
PhantomJS
初心者

Pythonによるスクレイピング&機械学習のお勉強その2-2 - ブラウザーを経由したスクレイピング

今回の目標

このシリーズでは教科書(文献1)に沿ってPythonによるスクレイピングと機械学習を学びます。今回は第2章「高度なスクレイピング」から2-2「ブラウザーを経由したスクレイピング」を学びます。具体的には、Webブラウザ遠隔操作ライブラリのSeleniumと、画面なし操作が可能なWebブラウザのPhantomJSの組み合わせを用います。

原則、教科書のサンプルプログラムを作成してゆきますが、著作権に配慮し、できるだけそのままではなく類題を作成して勉強してゆく方針です。

方法と結果

  • 準備

今回は教科書でUbuntuベースのdockerイメージを使う方法が紹介されているので、いつもと違って教科書通りに新しいdockerイメージを構築します。

まず、Ubuntu 16.04イメージを取得します。

$ docker pull ubuntu:16.04
16.04: Pulling from library/ubuntu
b234f539f7a1: Pull complete 
55172d420b43: Pull complete 
5ba5bbeb6b91: Pull complete 
43ae2841ad7a: Pull complete 
f6c9c6de4190: Pull complete 
Digest: sha256:b050c1822d37a4463c01ceda24d0fc4c679b0dd3c43e742730e2884d3c582e3a
Status: Downloaded newer image for ubuntu:16.04

そこそこダウンロード量多いです。
次に、このUbuntuコンテナを起動してPython3, Selenium, PhantomJSをインストールし、日本語環境を整備します。

$ docker run -it ubuntu:16.04
#ここからdocker内での作業
# apt-get update
# (結果省略)
# Python3のインストール
# apt-get install -y python3 python3-pip
# (結果省略)
# pip3のアップグレード
$ pip3 install —upgrade pip
# (結果省略)
# Seleniumのインストール
# pip3 install selenium
# (結果省略)
# BeautifulSoup4のインストール
# pip3 install beautifulsoup4
# PhantomJSのインストール
# apt-get install -y wget libfontconfig
# (結果省略)
# mkdir -p (ホームディレクトリ)/src  && cd $_
# wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
# (結果省略)
# tar jxvf phantomjs-2.1.1-linux-x86_64.tar.bz2
# (結果省略)
# cd phantomjs-2.1.1-linux-x86_64/bin; cp phantomjs /usr/local/bin
# 日本語フォントをインストール
# apt-get install -y fonts-migmix
# フォント設定を書き換える
# cat <<EOF > /etc/fonts/local/conf
<?xml version=“1.0”?>
<!DOCTYPE fontconfig SYSTEM “fonts.dtd”>
<fontconfig>
   <match target=“pattern”>
       <test qual=“any” name=“family”>
          <string>serif</string>
       </test>
       <edit name=“family” mode=“assign” binding=“strong”>
           <string>MigMix 2P</string>
       </edit>
    </match>
</fontconfig>
EOF
# 一旦dockeを抜ける
# exit

ここで、ここまで作業したdockerコンテナを新しいイメージubuntu-phantomjsとして保存します。

$ docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
cf2613d2a949        ubuntu:16.04        "/bin/bash"         34 minutes ago      Exited (0) 6 seconds ago                       musing_almeida
$ docker commit cf2613d2a949 ubuntu-phantomjs
sha256:c530a06599b3a53399a267d6ac218a09f8cd83d87d8a9053855ffc47cbfeaf9c

今後、このイメージを使用する際には日本語関係の環境変数の設定も入れて以下のように使用します。

$ docker run -it -v $HOME/src:$HOME/src \
    -e LANG=ja.JP_UTF-8 \
    -e PYTHONIOENCODING=utf-8 \
    ubuntu-phantomjs /bin/bash

準備はここまでで終了です。

類題2-2-1 画面キャプチャしてみよう

最初のサンプルプログラムはwebサイトのスクリーンキャプチャを作るプログラムでした。少し改変して、コマンドラインからURLを読み取る形式の類題を作成します。

selenium-capture-cclef.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from selenium import webdriver
from urllib.parse import urlparse
import sys

# スクリーンショットを作成するクラス
class WebShot:

    def __init__(self):
        self.browser = webdriver.PhantomJS()
        self.browser.implicitly_wait(3)


    def __del__(self):
        if self.browser is not None:
            self.browser.quit()

    @classmethod
    def URL2filename(cls, url):
        parsed = urlparse(url)
        site = parsed.netloc
        path = parsed.path
        filename = site.translate(str.maketrans(':', '-')) + path.translate(str.maketrans('/', '-')) + '.png'
        print(filename)
        return filename

    def shot(self, url):
        self.browser.get(url)
        self.browser.save_screenshot(WebShot.URL2filename(url))


# メインプログラム
if len(sys.argv) <= 1:
    print('USAGE: ', sys.argv[0], 'URL')
    quit()

ws = WebShot()
ws.shot(sys.argv[1])
  • 実行結果
$ python3 ./selenium-capture-cclef.py http://www.yahoo.co.jp
/usr/local/lib/python3.5/dist-packages/selenium/webdriver/phantomjs/webdriver.py:49: UserWarning: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead
  warnings.warn('Selenium support for PhantomJS has been deprecated, please use headless '
www.yahoo.co.jp.png

図のように正しくスクリーンショットの保存ができていました。

www.yahoo.co.jp.png

また、Warningに出ているようにSeleniumによるPhantomJSのサポートは終了するようです。とりあえず、この学習シリーズはそのままPhantomJSを使い、その後必要になったら別のブラウザを使うことにします。

類題2-2-2 会員制Webサイトにログインしてみよう

今度はBeautifulSoup4ではなく、Seleniumの機能を使った会員制Webサイトのログイン、スクレイピングです。2-1でも勉強した「作詞BBS」にログインする処理を今度はseleniumの機能を用いて実現しています。
類題は行うことは同じですが、少しコードをすっきりする感じに改変しました。例によってURLとユーザーID、パスワードは伏せ字にします。ご興味ある方は原著をご参照ください。

selenium-login-cclef.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from selenium import webdriver

# ユーザーIDとパスワード、 URLのハードコード
USER = '******'
PASS= '******'
URL = 'https://******/users.php?action=login'

class WebSession:

    def __init__(self, baseurl, username, password):
        self.browser = webdriver.PhantomJS()
        self.browser.implicitly_wait(3)
        self.lurl = baseurl
        self.user = username
        self.pw = password

    def __del__(self):
        if self.browser is not None:
            self.browser.quit()

    def login(self):
        self.browser.get(self.lurl)
        userbox = self._gettextbox('user')
        userbox.clear()
        userbox.send_keys(self.user)
        passbox = self._gettextbox('pass')
        passbox.clear()
        passbox.send_keys(self.pw)
        frm = self.getbycsss('#loginForm form')
        frm.submit()
        print('ログイン処理を行いました')

    def visitPage(self, url):
        self.browser.get(url)

    def _gettextbox(self, id):
        return self.browser.find_element_by_id(id)

    def getbycsss(self, selector):
        return self.browser.find_element_by_css_selector(selector)

# メインプログラム

session = WebSession(URL, USER, PASS)

# ログインする
session.login()

# マイページのURLを得る
a = session.getbycsss('.islogin a')
url_mypage = a.get_attribute('href')

# マイページを表示
session.visitPage(url_mypage)

# お気に入りのタイトルを列挙
links = session.browser.find_elements_by_css_selector('#favlist li > a')
for a in links:
    href = a.get_attribute('href')
    title = a.text
    print('-', title, '>', href)
  • 実行結果(URLは消去)
/usr/local/lib/python3.5/dist-packages/selenium/webdriver/phantomjs/webdriver.py:49: UserWarning: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead
  warnings.warn('Selenium support for PhantomJS has been deprecated, please use headless '
ログイン処理を行いました
- 春に咲く花 by Homary
- ジャパニーズインザブラック by Homary
- httpsにしないといけない by JS-TESTER
- ネジ by JS-TESTER
- スクラップブック by JS-TESTER
- 聞こえない by JS-TESTER
- 今日も明日もJS三昧 by JS-TESTER
- 眠ってもデバッグ by JS-TESTER
- プリンとシュークリーム by JS-TESTER
- 吾輩はテスターである by JS-TESTER
- 吾輩はテスターである その2 by JS-TESTER
- test by JS-TESTER
- test2 by JS-TESTER
- 憎しみの果て by JS-TESTER
- test1 by JS-TESTER
- 無題 by JS-TESTER
- 無題 by JS-TESTER
- 無題 by JS-TESTER
- 吾輩は爆薬である by JS-TESTER
- クローリングララバイ by JS-TESTER
- ラット・リフ by Homary
- メダリオン by Homary
- 桜花 by Homary
- 格好 by Homary
- ぼんやり by Homary
- Seraphim by Homary
- 命想い by Homary
- 夕日 by Homary
- 昭和ノスタルジック by Homary
- つまびく by Homary
- 哀愁メトロ by Homary
- Razury by Homary
- 鍵 by Homary
- キャベツ by Homary
- メモリーズ by Homary
- memo by Homary
- 親愛なる君へ・・・ by Homary
- Horror killer by Homary
- 黄昏時 by Homary
- 人間なんて飽きました by Homary
- オカモッチ by Homary
- 僕の足 by Homary
- チャイルドスカイ by Homary
- 学校行こうよ by Homary
- オルタナティブ by Homary
- 命の価値 by Homary
- 病魔 by Homary
- Radish Legs by Homary
- クリエイト by Homary
- そして僕は空を愛した by Homary

SeleniumでもCSSセレクタその他の方法でスクレイピングはできるということのようです。

類題2-2-3 JavaScriptを実行してみよう

次はSeleniumから適当なWebサイトを開いて、JavaScriptを実行するという例題です。
非常に短いプログラムなので、気の利いた類題をあまり考えられず、教科書のサンプルコードをほぼそのまま掲載しますが、実は「適当なWebサイト」は訪問しなくともJavaScriptは実行できることがわかりました。要するにブラウザをスクリプトエンジンとして動かす、ということですね。ページ上のデータをいじるようなときは必要になるのかもしれません。

selenium-js-cclef.py
from selenium import webdriver

# PhantomJSのドライバを得る
browser = webdriver.PhantomJS()

# JavaScriptを実行
r = browser.execute_script('return 100 + 99')
print(r)
  • 実行結果
/usr/local/lib/python3.5/dist-packages/selenium/webdriver/phantomjs/webdriver.py:49: UserWarning: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead
  warnings.warn('Selenium support for PhantomJS has been deprecated, please use headless '
199

今回達成したこと

  • SeleniumとPhantomJSを併用したPythonからのブラウザ操作の基本を学びました。

参考文献

  1. クジラ飛行机, Pythonによるスクレイピング&機械学習[開発テクニック], ソシム株式会社, 2016