ストックドッグ

KatoTakahiro。金融系の会社で働くSEが株やPython、その他諸々について書いています。サービスも運営してます→http://fmbrain.work

seleniumの環境構築と簡単な使い方

今は日曜日の夜2時

早く寝ないと!!

明日は仕事なんです。

急いで書くのでぶっきらぼうな今日は文章になるかもです。

何とかブログだけ書いてさっさと寝ます。

環境構築

pipでインストール可能です。

pip install selenium

seleniumAPIを通じてブラウザを使用するため、seleniumとは別にブラウザ用のドライバーをインストールする必要があります。

sites.google.com

SafariFirefoxChrome、Edge、どれでも好きなブラウザのドライバーの圧縮ファイルをHPからダウンロードでき、私はChromeを選択しました。

ダウンロードした圧縮ファイルを解凍するとChromedriverというファイルが現れます。

これをseleniumを使用するファイルと同じフォルダに入れておきます。


公式HPにはPATHを通すと書いてあったが、そこは本人の自由。

私は面倒だったので、そのままコードの中にChromedriverの位置を書きました。


ここらへんの環境構築にちょっと苦労しました。

Youtubeで「YUI」と検索する操作をseleniumを使ってやってみる

#unittestは単体テスト用のライブラリ。
#動作の開始から終了までの時間を計測してくれるので、なんとなく使用。
import unittest

from selenium import webdriver
from selenium.webdriver.common.keys import Keys


class PythonOrgSearch(unittest.TestCase):

	def setUp(self):
		#pwdでカレントディレクトリを確認。
		#カレントディレクトリの場所をそのまま記述。
		#seleniumを実行するファイルとChromedriverを同じ場所に格納が楽。
		self.driver = webdriver.Chrome("/home/ubuntu/serv/robo/chromedriver")


	def test_serch_in_python_org(self):
		driver = self.driver
		#youtubeのURL
		#driverの中にはサイトの構造がHTMLとして格納されている。
		driver.get("https://www.youtube.com/")

		#youtubeの検索バーはid="masthead-search-term"
		#find_element_by_idで検索バーのidを取得してくる
		elem = driver.find_element_by_id("masthead-search-term")

		#yuiと検索
		elem.send_keys("yui", Keys.RETURN)

	def tearDown(self):
		self.driver.close()


if __name__ == "__main__":
    unittest.main()


ちなみに、youtubeのサイト構造の画像。
id="masthead-search-term"が検索バーであることがわかります。

f:id:doz13189:20170424023003p:plain

クリックもできるselenium

クリックを自動で行いときは.click()で可能。

方法はだいたいさっきと同じで、HTMLからクリックしたい要素のidを探して.click()をつけたします。

driver.find_element_by_id("about").click()

公式サイトを見るとドラッグ・アンド・ドロップもできるみたいだが、どの場面でドラッグ・アンド・ドロップを使うのかは私には思いつかない...

id要素以外の見つけ方

  • find_element_by_id
  • find_element_by_name
  • find_element_by_xpath
  • find_element_by_link_text
  • find_element_by_partial_link_text
  • find_element_by_tag_name
  • find_element_by_class_name
  • find_element_by_css_selector

案外たくさんある...

個人的にはclass_nameとidがあれば90%の作業はすむと思っています。

けっこう簡単だったselenium

思いの外使いやすかったです。

使い方自体もシンプル。

そして、汎用性抜群。

もうしばらく触ってみます。

隠しファイルの見方

ドット(.)から始まるファイルは通常、lsコマンドをうっても表示することは出来ません。

ls

ドットから始まるファイルは隠しファイルと呼ばれ、例えば環境変数を格納するために使ったりする.bashrcなどがあります。

これらを表示するにはlsコマンドにオプションをつけて、うつことで隠しファイルを表示することが出来ます。

ls -la

以上、終わり

herokuにルート権限はあるのか?

4月からはもっぱらherokuにつきっきりです。

ようやくherokuの全貌をつかめてきた感覚があり、前は読んでもわからなかった記事も少しづつではありますが、理解できるようになってきたところです。

今までローカルで動かしていたプログラムを自動プログラムに書き換えて、Webアプリで提供するという夢があと一歩のところまで来ました。

長かったです。

4月に入社して飲み会ラッシュの中、同期にはちょっとづつ飲み会苦手キャラを浸透させつつ、飲み会を断りやすい雰囲気を作って、5時に帰れる日は直帰してプログラムを書いて...

苦労に苦労を重ね、そして、大きな問題が発生しました。

まずはじめにroot権限とは?

ubuntuユーザはpip install ライブラリ を行う際、たいていsudoをつけます。

sudoというのはルート権限であることの宣言であり、sudoをつけることでファイルの書き込み・変更等を許可することになります。

ライブラリによってはファイルの書き換えを行う必要があるので、sudoをつけなければ、ファイルの書き込みができません的なエラーを発生させる要因になります。

たしか、windowsでは、コマンドプロンプト自体を起動する際にroot権限で起動するか否かを選択したはずです。

ここらへんの違いは設計思想の違いなんですかね。

herokuにroot権限はあるのか?

herokuはIaas系のサービスで、のせるOSは自由に選べます。(toolbeltという形で選択が可能です)

私はherokuにはUbuntuの環境を構築したのですが、なぜかheroku上でsudoコマンドが使用できません。


これが何を意味するかというと、ファイルを書き換えるライブラリがインストールできない、ということです。


これは詰みです。

本来、herokuからインストールできないライブラリ等はbuildpacksによってソースから直接インストールすれば良いのですが(私の解釈が間違ってなければ)、

今回はインストールできないわけではなくて、heroku上で動かすにはファイルを書き換える必要がある、ということなのでbuildpacksでは解決できません。


3日かけて(貴重な土日と5時帰りの月曜の夜)色々とgoogleで解決方法を探しまわったのですが、無理でした。

普通に考えてIaasでroot権限がないって考えにくいなぁと思いつつ、ただ自分では解決できないので諦めることにしました。

ただ一つ、良いことがあるとすれば、このエラーを餌に同期の中からプログラミング好きな人をたくさん見つけれたことです。

「プログラミング得意!?このエラーでてるねんけど、わかる?教えて!」みたいなノリで声をかけまくりました。

違うサービスを使しかないか...

仕方がないです。ドキュメントたくさん読んで、色々できるなぁなんて妄想していましたが...

プログラミングをはじめてそろそろ1年たつのですが、ガチで解決できないエラーに出会ったのはこれがはじめてでした。

この出会い一生忘れないと思います。


次のサービスの候補としては、AWSGoogleのやつ、さくらのVPS、conoho、このあたりです。

conohoは全く存在を知らなくて、同期の人に教えてもらいました。

今日の夜あたりからちょっとづつ調べながら次の移転先を探してみます。

以上、終わり。

herokuのタイムゾーンを変更したらAPSchedulerが動いた話

APSchedulerがピクリともしない問題発生

APSchedulerをcron式タイムスケジュールで0:20に命令を実行したいのですが、なぜか0:20になってもピクリともしませんでした。

from apscheduler.schedulers.blocking import BlockingScheduler

sched = BlockingScheduler()

#0:20
@sched.scheduled_job('cron', hour=0, minute=20)
def scheduled_job():
    print('This job is run every weekday at 0:20.')

sched.start()

時間設定の仕方はhour=0、minute=20で0:20を指すはずだが...

APChedulerをcron形式で動かすドキュメントを読んだので、きっと間違いはないはず。

apscheduler.triggers.cron — APScheduler 3.3.1.post4 documentation

だが、動かぬ。

タイムゾーンを変更していなかった

herokuのログを見るたびにいつも時間がずれてるなぁ、これどこの時間なんや、と思いつつ放置していたのですが、それが原因でした。

タイムゾーンUTCでした。

ということで。

herokuのタイムゾーンJSTに変更

まず、herokuの現在のタイムゾーンを念の為確認。

#heroku上でbashを起動してから。
heroku run bash

#タイムゾーンを確認
date

UTCだったので、タイムゾーンJSTに変更。

heroku config:add TZ=Asia/Tokyo

TZ=Asia/Tokyoという環境変数を追加して、設定を変更。

無事解決しました

最近は株価の分析には時間が割けてなくて、heroku上でシステムを動かすことにばかり時間を費やしています。

あまり楽しくはありませんが、これから自分一人でシステムを作っていこうと思うと避けて通れない道だと思っています。

なので、焦らず地道にドキュメントを読みながら作業を進めています。

herokuでのスケジュール管理にAPSchedulerを使ってみる

目次

herokuで定期的にファイルを実行したいとき何を使っていますか?

cron?

heroku scheduler?

APScheduler?

cron...?

DBの更新、データの取得、バックアップの保存などのスケジュールの管理はモダンなWebアプリには必須機能です。

ubuntuのデフォルトでインストールされているcronはあらゆるスケジューリングが可能で、上記のほとんどのことはcronによって達成することが出来ます。

ですが、cronはサーバー上で動作することもあり、Webアプリのテストをローカル環境で行うことを考えると、もっと高いレイヤーのアプリケーションのインスタンスで動作するほうが勝手がいいです。

heroku scheduler...?

herokuにはスケジュール管理のためのファンタスティックなアドオンが用意されています。

このheroku schedulerはシンプルなタスクを10分、1時間、一日、複数の間隔での実行が可能です。

しかし、5分や37分など中途半端な時間での実行は難しいです。

cronよりもheroku schedulerよりAPSchedulerが良い

アプリケーションのインスタンスで動作し、かつ、中途半端な時間でも簡単にスケジュールの管理が可能なのが、APSchedulerです。

これはPython製のライブラリなので、私のようにwebアプリを全てpythonで完結させたい人たちにはもってこいです。

heroku上でAPSchedulerを使ってみる

ということで、1分おきに現在時刻をDBにインサートするプログラムを書いてみます。

最終的な出力はこうなります。

herokuのログを見ると、1分おきにDBを更新していることがわかります。

f:id:doz13189:20170410001021p:plain

用意するもの

herokuでアプリを運用するために必要なファイルは以下です。

#適当に用意してください
runtime.txt
requirements.txt

#以下は今から作成します
Procfile
gettime.py
time.db
timeclock.py

スタート。

#screamtimeという名前のアプリを作ります
heroku create screamtime

次に、gettime.pyを作成します。

import sqlite3
import pandas as pd
import datetime


#現在時刻を取得する
now = datetime.datetime.today()
hour = now.hour
minute = now.minute

#DataFrame形式にぶち込む
#普通はSQL文書いてインサートすると思いますが、
#私がDataFrame形式に慣れているので、こちらを使用していますが、各自なれた方法でお願いします
time_df = pd.DataFrame({"Hour" : [hour], "Minute" : [minute]})


#db作成
dbname = "time.db"

#dbコネクト
conn = sqlite3.connect(dbname)
c = conn.cursor()

#dbのnameをtime_dfとし、読み込んだcsvファイルをsqlに書き込む
#if_existsでもしすでにtime_dfが存在していても、置き換えるように指示
time_df.to_sql("times", conn, if_exists="replace")

#作成したdbを見てみる
select_sql = 'select * from times'
for row in c.execute(select_sql):
    print(row)

conn.close()

これをgettime.pyという名前で保存します。

次は、今作成したgettime.pyをAPSchedulerで定期的に実行させるコードを書きます。

from apscheduler.schedulers.blocking import BlockingScheduler
import os

sched = BlockingScheduler()

#間隔は1分ごとにしています
#minutesではなくてhourに変更したら、時間での指定も可能です
@sched.scheduled_job('interval', minutes=1)
def timed_job():
	print("Let's start")
	os.system("python gettime.py")


sched.start()

これをtimeclock.pyという名前で保存します。


最後にProcfileを作成します。

clock: python timeclock.py

これで、herokuにclockのファイルであるということを宣言します。

ファイルが全て揃ったので、あとはherokuに上げるだけです。

念の為、herokuに上げるまでのgitでの手順を載せておきます。

git init
git add .
git commit -m "first commit"
git push heroku master

エラーなく行けば、これでherokuには「1分おきに現在時刻をDBにインサートするプログラム」がアップロードされました。

以下でherokuにclockをスケールします。

heroku ps:scale clock=1

上手くスケールされたことを確認して。

heroku ps
|<

数分待ってからherokuのログを見てみます。

>||
heroku logs

f:id:doz13189:20170410001021p:plain

以上で「1分おきに現在時刻をDBにインサートするプログラム」が完成しました。

まとめ

APSchedulerはとても簡単にスケジュールの管理が行うことができます。

コードもpythonで書くことができるので、使い勝手がとても良いです。

cronよりもheroku schedulerよりもAPSchedulerが良いんじゃあないでしょうか!?

herokuのworker dynoとweb dynoの違いって何?

目次

dyno?

herokuでは、プロセスの処理はdynoによって行われます。

プロセスの処理とはHTTPのリクエストやレスポンス、バックグラウンド処理などです。

dynoは3種類あり、処理をするプロセスの種類によって使い分けられます。

  • web dyno
  • worker dyno
  • one-off dyno


herokuを勉強していて、dynoはheroku内の独特の単位で一番はじめにつまづいたのでまとめておきます。

web dyno

HTTPのリクエスト・レスポンスを処理します。

ユーザーからのリクエストはweb dynoが処理するので、webアプリが行う処理の大半はweb dynoによって行われています。

worker dyno

バックグラウンド処理を行います。(ほぼweb dyno以外の処理)

バックグラウンド処理とは、例えばAPIsからのデータ取得やRSSフィードの読み込み、画像のリサイズ、S3へのデータ送信などが当てはまります。

one-off dyno

一時的な処理を行うためのdyno。

heroku run

などのherokuコマンドを実行したときに使用されるdynoです。

ログ

これらdynoの動作状況はログを見ることによって確認できます。

#ログの確認
heroku logs -t

#見たい行数を指定する(最大1500行まで)
heroku logs -n 200

Control+Cでログの出力を中止できます。

ログは直近の1500行のみしか表示されず、ログの保存を行う場合はアドオンを追加します。

使用中のdynoを確認する

heroku ps

このコマンドで現在、使用しているdynoを確認することができます。

まとめ

worker dynoとweb dynoの違いは、まとめると処理するプロセスの違い、ということになります。

Webアプリによって必要な処理は違ってくるので、アクセス数がひたすら多いWebアプリはweb dynoを増やしたり(=スケーリング)、バックグラウンドでの処理が多いならworker dynoを増やしたりと適宜変更しながら運用していきたいですね。

cronで定期的にフォルダを作成してみる(Ubuntu 16.04)

色々とcronについて勉強したので、今回はcronで一分毎にTestという名のフォルダを作成するまでやってみようと思います。

cronとは

設定したファイルを定期的に実行させるためのツール

crontabに登録されているcronを確認

crontab -e

編集等はvimで行うことになります。
もし、まだcronがひとつも登録されていなければ、no crontab for <ユーザー名> が表示されます。

crontabは /etc の中にあるのですが、私はvimの使い方がわからなかったので、sublimetext(テキストエディタ)に移してから編集していましたが、これではうまくいきませんでした。(編集しても内容が反映されない)

おそらく、編集・実行の権限が与えられていなかったからだと思います。

諦めてvimの使い方をドットインストールで学んできて、ようやく編集することができました。

vimは癖が強すぎるが、慣れれば最高に使いやすいツールになることの片鱗をつかめた!)

そもそもcronが動作しているのかをチェック

sudo service cron status

active(running)が表示されていれば正常に動作しています。

また、cronの動作ログもこれで確認可能です。

基本的にcronの動作ログは /var/log のsyslogファイルに書かれています。

なので。

cd /var/log
cat syslog

で、確認可能ですが、いちいちsyslogを見に行くのも面倒なので、sudo service cron status で確認したほうが楽です。


定期的に実行させるファイルを作成

/home にtest.shというファイルを作成します。

#!/bin/shシェルスクリプトであるということを明示するためのものです。

mkdir Test にしているので、cronが上手く実行されれば/home にTestという名のフォルダが作成されるはずです。

(mkdirでもなくても大丈夫です、今回はcronが動作しているかどうかを確認したいため、適当にmkdirにしました)

#!/bin/sh
mkdir Test

crontabからcronを設定

crontab -e
* * * * * /bin/sh /home/ubuntu/test.sh > /dev/null 2>&1

時間は1毎分に設定しています。

エラーが発生していた場合、すぐに確認できるので。

また、cronによって実行するファイルがシェルスクリプトであることを明示するために /bin/sh を記述しています。

cronでの時間設定の書式は以下のサイトがわかりやすかったです。

qiita.com


これでcronの設定は終わったので、ログを見てみます。

3月 30 23:09:01 tk CRON[4148]: (ubuntu) CMD (/bin/sh /home/test.sh)

CMDとはcronが実行したコードを示しています。

ログを見る限り、cronは正常に実行されています。

ディレクトリを見てみると...

これが...

テンプレート
ピクチャ
test.sh
デスクトップ
ミュージック
ドキュメント
公開
ダウンロード
ビデオ

1分後...

Testフォルダが作成されたので、無事にcronが動作したようです。

Test
ダウンロード
ビデオ
テンプレート
ピクチャ
test.sh
デスクトップ
ミュージック
ドキュメント
公開

MTAというエラーが出た場合

cronはエラーが出た際、メールで通知しようとするのですが、メールの設定を行っていない場合にMTAというエラーが出ます。

postfixなどでメールの設定を行うことでこのエラーは解決できます。

以下のサイトがわかりやすかったです。

ryoichi0102.hatenablog.com

まとめ

今回はcronを動かすまでを最短距離で行ったので、至らない点が多数あります。

cronにはまだまだ工夫の余地があり、以下のサイトがとても参考になります。

dqn.sakusakutto.jp