てけとーぶろぐ。

ソフトウェアの開発と、お絵かきと、雑記と。

Selenium+Python+PhantomJSでWebサイトのスクレイピング

先回の続き。

操作対象のWebブラウザーChromeからPhantomJSに変える。

PhantomJSはGUIを持たない、いわば透明なブラウザー
これにしてやると、動作中に画面を占領されないし
コマンドラインから起動できてサーバー上でのバッチ実行などにも使えるようになる。

PhantomJSインストール

http://phantomjs.org/download.html からダウンロードしてパスを通しておく。

操作用Pythonスクリプトの作成

先回とほぼ同じ。
webdriverの作成の部分だけ変わる。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import codecs
import time

from selenium import webdriver
from selenium.common.exceptions import TimeoutException

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

WAIT_SECOND = 30

USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"

if __name__ == '__main__':

    driver = webdriver.PhantomJS(
        service_args=['--ignore-ssl-errors=true', '--ssl-protocol=TLSv1'], 
        desired_capabilities={'phantomjs.page.settings.userAgent': USER_AGENT})
    driver.set_window_size(1280, 1024)

    driver.get('https://google.co.jp/')

    # 検索キーワードとエンターキーを入力
    t=driver.find_element_by_id('lst-ib')
    t.send_keys(u'てけとーぶろぐ\n')

    # 要素の表示待ち
    WebDriverWait(driver, WAIT_SECOND).until(
        EC.visibility_of_element_located((By.CLASS_NAME, '_Rm')))

    # リンクをクリック
    b=driver.find_element_by_xpath('//*[@id="rso"]/div/div/div[1]/div/div/h3/a')
    b.click()

    # 要素の表示待ち
    WebDriverWait(driver, WAIT_SECOND).until(
        EC.visibility_of_element_located((By.CLASS_NAME, 'entry-title-link')))

    # スクリーンショットの保存
    driver.save_screenshot("ss.png")

    # ソースの書き出し
    file_name = 'test.html'
    with codecs.open(file_name, 'a', 'utf_8') as f:
        f.write(driver.page_source)

    driver.close()

ポイント

service_args

CentOSにおいてサイトによってはこの設定をしないと表示できなかったので指定する。

userAgent

今回はChromeと同じユーザーエージェントを設定している。
サイトによってはこの設定をしないとChromeでの表示結果と変わってしまうので指定する。

スクリーンショット

以下のコードでスクリーンショットを画像ファイルとして保存できる。

driver.save_screenshot("ss.png")

見えないブラウザーなので状況把握に便利。

Selenium+PythonでChromeの自動操作

Webアプリのテストのときや、Web上のデータ収集のときなど
Webブラウザーを自作プログラムから操作できると便利なことがある。

というわけでSelenium+PythonChromeを自動操作してみる。

今回は Windows, Python 2.7 という組み合わせで行ったけど
Python 3.x でも同様だと思う。

Pythonのインストール

https://www.python.org/の「Download」から
python-2.7.13.msi」をダウンロードしてインストールする。

PythonSeleniumのインストール

「C:\Python27」「C:\Python27\Scripts」にパスを通した状態で
コマンドプロンプトから以下を実行する。

pip install selenium

Chrome用ドライバーのインストール

https://sites.google.com/a/chromium.org/chromedriver/downloads
の「Latest Release: ChromeDriver 2.29」のリンクから
「chromedriver_win32.zip」をダウンロード、展開して
中の「chromedriver.exe」を適当な場所に置く。

操作用Pythonスクリプトの作成

例えば「main.py」として以下のように作成する。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import codecs

from selenium import webdriver
from selenium.common.exceptions import TimeoutException

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

WAIT_SECOND = 30

if __name__ == '__main__':

    driver = webdriver.Chrome()  
    driver.maximize_window()    
    driver.get('https://google.co.jp')
    
    # 検索キーワードとエンターキーを入力
    t=driver.find_element_by_id('lst-ib')
    t.send_keys(u'てけとーぶろぐ\n')

    # 要素の表示待ち
    WebDriverWait(driver, WAIT_SECOND).until(
        EC.visibility_of_element_located((By.CLASS_NAME, '_Rm')))

    # リンクをクリック
    b=driver.find_element_by_xpath('//*[@id="rso"]/div/div/div[1]/div/div/h3/a')
    b.click()

    # 要素の表示待ち
    WebDriverWait(driver, WAIT_SECOND).until(
        EC.visibility_of_element_located((By.CLASS_NAME, 'entry-title-link')))

    # ソースの書き出し
    file_name = 'test.html'
    with codecs.open(file_name, 'a', 'utf_8') as f:
        f.write(driver.page_source)

    driver.close()

操作用Pythonスクリプトの実行

「chromedriver.exe」にパスを通した状態で
作成した操作用Pythonスクリプトを実行する。

python main.py

ポイント

要素情報の確認方法

スクリプトでWebサイト上の要素を指定するのに
要素のXPathなどが必要だがこの確認には
Webブラウザーの機能を使うのが楽。
ChromeだとF12キーでデベロッパーツールを表示して
Shift+Ctrl+C を押してから要素をマウスクリック。
HTML上でハイライトされた行を右クリックして
Copy → Copy XPath とか。

確実なロード待ち方法

読み込み待ちには上記の例のように表示を待つのが確実。
サイトによっては要素を非表示状態でロードした後
動的に表示状態に切り替えたりするので。

その他の要素指定方法

要素の指定の仕方はXPath以外にも幾つかある。
ドキュメントをどうぞ。
http://selenium-python.readthedocs.io/locating-elements.html

AndroidDrawableResizer

Androidアプリ作成の際に、画像を使う場合
各解像度用の画像を用意するのが望ましいのだけど
手でつくっていると面倒なのでツールを作った。

GitHub - kurima-yoshida/AndroidDrawableResizer

settings.json に設定を書き込んで
変換元のファイルを引数として渡して実行すると
指定のフォルダー内に変換後のファイルが生成される。

拡大縮小の他に、非透明色部分を指定の色で塗りつぶす機能も付けている。

例えばMaterial icons - Material Designでダウンロードしたアイコンを好きな色にできる。

Windows用の実行ファイルは以下。

drisezer100.zip

一時的にパスを通したコマンドプロンプトを起動するバッチ

コマンドプロンプトから実行するソフトには
パスを通しておいた方が使いやすいものが多いけど

いちいち環境変数pathに追記していたらpathの値がえらい長くなるわ
ソフトが不要になってもpathから取り除き忘れるわ。

それを避けたい場合はコマンドで一時的にpathに追記すればいいけど
何度も使う場合はいちいちやってられない。

そんなときには「一時的にパスを通したコマンドプロンプトを起動するバッチ」を用意しておくと便利。

例えば「C:\Python27」にパスを通した状態でコマンドプロンプトを起動するバッチファイルなら以下のような感じ。

cd /d %~dp0
set path=%path%;C:\Python27
cls
%windir%\system32\cmd.exe /k

1行目はおまけでバッチファイルのあるディレクトリーをカレントディレクトリーにしている。
4行目でコマンドプロンプトを起動、そのまま表示しておく。

参照:
batファイルで、そのファイル自身のパスを取得する - 砂漠の音楽

ScreenOCR(2)

ScreenOCR で紹介した「ScreenOCR」のソースコード、公開しておきます。

GitHub - kurima-yoshida/ScreenOCR

TesseractというオープンソースOCRがあるらしい。これを組み込めばオフラインで動くものが作れるのだろうなぁ。

tesseract-ocr · GitHub

100均素材でRaspberry Piケースをつくる!

本記事はMorning Project Samurai Advent Calendar 2016の12/5の記事として作成しました。

Raspberry Piで何か、例えば監視カメラなんかをつくったとき、何もしないと基盤むき出しの配線ぐちゃぐちゃになってしまいます。
そんな状態を避けるために最低限のケース(ガワ)を作ってみましょう。

f:id:kurimayoshida:20161203215927j:plain

材料

  • Raspberry Pi 2 Model B
  • はがきケース(100均(ダイソー)で調達)
  • ネジ(M2.6 長さ8mm)
  • ナット(M2.6)
  • スペーサー(M2.6 長さ3mm)
  • ワッシャー(M2.6)

ケースとして今回ははがきケースを選択しました。LANケーブル、USBケーブル、HDMIケーブル等をつなぐ場合は大きめのものを使い、ケースに穴を空けてケーブルだけ出すと見た目がすっきりします。また、開閉しやすいものを選ぶとメンテナンスが楽です。

f:id:kurimayoshida:20161203215524j:plain

ネジ類はRaspberry Piの基盤にある穴にあわせてネジ径 M2.6 のものを使います。
あまりお店に置いていないサイズらしいのですが渋谷の東急ハンズなどにありました。
通販だとヒロスギネットが少量から購入できておすすめです。

ケースとRaspberry Piにネジを通してナットでとめるだけなのですがRaspberry Piの裏側はデコボコなのでケースとRaspberry Piの間にスペーサーが必要になります。

ネジは、ネジにワッシャー、ケース、スペーサー、Raspberry Piと通してナットで止められる長さのものを選んでください。

工具

  • ドライバー
  • ピンバイス(タミヤ クラフトツール 精密ピンバイスD 74050)
  • ドリル刃(タミヤ クラフトツールシリーズ No.49 ベーシックドリル刃セット 74049)
  • ニッパー
  • 棒ヤスリ(半丸など丸面があるもの)
  • 紙ヤスリ(400番くらいの細かいもの)
  • コンパス(両方の脚の先が針になっているもの)

タミヤ クラフトツール 精密ピンバイスD 74050

タミヤ クラフトツール 精密ピンバイスD 74050

手順

ケースにRaspberry Pi固定用のネジ穴を開ける

Raspberry Piのケース内での位置を決め、ケースにドリルでネジ穴を空けます。
ドリル刃は2.5mm径のものを使います。
ケース内にRaspberry Pi を置いて、その状態でRaspberry Piのネジ穴に上からドリル刃を通してケースに穴を空けます。

1つ穴が空いたらスペーサーを入れてネジを通し、ナットで固定してしまいます。
ケース内にRaspberry Pi を置いているのに対して裏からネジを通す形になります。
裏から、ネジ頭→ワッシャー→ケース→スペーサー→Raspberry Pi→ナット の並びです。

この状態で残りのRaspberry Piのネジ穴からドリル刃を通してケースに穴を空けていけば穴の位置を間違うこともありません。(ドリル刃を垂直に通すようには注意)

穴を空け終わってネジで止めたのを裏から見るとこんな感じです。(写真では上の説明と逆でナットが表になってしまっていますがミスです…)

f:id:kurimayoshida:20161203220024j:plain

ケースにケーブル用の穴を開ける

Raspberry Piに繋いだケーブル類を通すための穴を空けます。
ケーブルを通すためにはコネクターを通さなければなりませんからそれなりの大きさの穴を開けることになります。

まずケースに、両方の脚の先が針になっているコンパスで、開ける穴の形に円を描きます。(針で円の形に傷をつける)
この円の少し内側に、円に沿う感じでピンバイスで穴をいくつも空けていき、円を一周したら隣り合う穴同士をニッパーで繋いで切り取り、あとはヤスリで仕上げます。
棒ヤスリで円の痕に近づくように削っていき、あと0.2ミリくらいになったら紙ヤスリを棒ヤスリに巻きつけて微調整をかける感じです。

塗装後ですけど、穴はこんな感じ。

f:id:kurimayoshida:20161203220903j:plain

Raspberry Piをケースに固定する

Raspberry Piをネジでケースに固定し、配線し、完成。

写真だと脚ついてるけど…?

これも100均(ダイソー)で調達したスマホ用の脚です。これのすばらしいところは分解するとナットが手に入るところ。
このナット、一般的なカメラの三脚に対応していて、三脚の変更にも対応できちゃう。

Raspberry PiにLakkaをインストールしてゲーム機にする

ファミコン自作にて「recalbox」や「RetroPie」といったRaspberry Piをゲーム機のようにするエミュレーター専用OSの名をあげた。

実際試してもみたのだけど、操作方法が洗練されておらずゲームパッドで完結しないところがあったり、画面遷移や画面デザインも若干つぎはぎな印象を受けた。

そんなところ、もっと良さそうなものを見つけた。それが「Lakka」だ。

日本語でインストール方法を説明しているサイトが少なそうだったので書いておく。

Lakkaのイメージファイルのダウンロード

Lakka documentation - Disclaimerにアクセスし「Get Lakka」をクリック。
操作中のOS(例えばWindows)を選択。
LakkaをインストールしたいRaspberry Piの種類(例えばRaspberry Pi 2)を選択。
「Download Lakka」をクリック。圧縮されたイメージファイルがダウンロードされる。

Raspberry Pi用のSDカードの準備

LakkaをインストールするRaspberry Pi用のMicroSDカードを用意する。
容量はLakka自体には1GBも必要ないので8GBもあれば十分だがエミュレーター用のロムファイルをどのぐらい入れたいのかによってお好みで。

圧縮されたLakkaのイメージファイルを7-zipなどで解凍する。

Win32DiskImagerを使って解凍したLakkaのイメージファイルをSDカードに書き込む。
Win32DiskImagerを起動して、Image FileとしてLakkaのイメージファイルを、DeviceとしてSDカードのドライブを選んでWriteをクリックすればOK。

Raspberry Piの起動

Raspberry Piに出来上がったSDカードを挿入し、ディスプレイ、USBゲームパッド、USB無線LANアダプターを接続して電源を入れる。
Lakkaが起動し、USBゲームパッドで操作できるはず。

iBUFFALO USBゲームパッド 8ボタン スーパーファミコン風 グレー BSGP801GY

iBUFFALO USBゲームパッド 8ボタン スーパーファミコン風 グレー BSGP801GY

BUFFALO 11n対応 11g/b 無線LAN子機 親機-子機デュアルモード対応モデル WLI-UC-GNM2

BUFFALO 11n対応 11g/b 無線LAN子機 親機-子機デュアルモード対応モデル WLI-UC-GNM2

ネットワーク設定

Lakkaのメイン画面から歯車のアイコン→Wi-Fiと進み
接続するWi-Fiスポットを選択する。
Passphraseを入力するとネットワークに接続される。

Lakkaのメイン画面からLakkaのアイコン→Informationと進み
Network Informationを選択する。
「Interface(wlan0):」に続くIPアドレスをメモする。

ゲームのROMファイルの転送

PCから先程メモしたLakkaのIPアドレスに接続する。
例えばPCのOSがWindowsで、LakkaのIPアドレスが「192.168.12.5」だったら
エクスプローラーのパス欄に「\\192.168.12.5」と入力する。
するとLakka内のフォルダーが表示されるのでその中の1つ「ROMs」フォルダー内にゲームのROMファイルを置く。

Lakkaに戻り、Lakkaのメイン画面から+のアイコン→Scan Directoryと進み
romsを選択、<Scan This Directory>を選択すると、ROMsフォルダー内に置いたROMファイルが認識される。

コントローラーの設定

ゲームからLakkaのメイン画面に戻るためのボタンを設定する。
ボタンの少ないゲームパッドで初期設定だと存在しないボタンが設定されている事になりゲームから戻れずハマるので注意。

Lakkaのメイン画面から歯車のアイコン→Input→Menu Toggle Gamepad Comboと進み
ボタンの組み合わせ(例えばL1+R1+Start+Select)を選択する。

ゲームの実行

認識したROMファイルに応じて、エミュレーターのアイコンが増えているので、そこからゲームを選択してプレイする。

ゲームの中断

ゲームを中断する時はコントローラーの設定で設定したボタンの組み合わせを押す。

Raspberry Piのシャットダウン

Lakkaのメイン画面からLakkaのアイコン→Shutdownを選択する。
少し待つとシャットダウンされる。