ストックドッグ

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

seleniumで起きるエラー ~unknown error: unable to discover open pages~

発生エラー

selenium.common.exceptions.WebDriverException: Message: unknown error: unable to discover open pages

発生原因

stackoverflowにナイスな回答あり!

https://stackoverflow.com/questions/21001652/chrome-driver-error-using-selenium-unable-to-discover-open-pages


chromedriverのバージョン古くないか? ← まずこれを疑え

次は、google-chromeのバージョン古くないか? ← これも疑え

とのこと。

簡単な解決方法は、バージョンアップしよう、ってことになる。

バージョンアップしよう

chromedriver編

バージョンごとにインデックスされているので、目的のバージョンをインストールしよう。

http://chromedriver.storage.googleapis.com/index.html


最新版のバージョンはここから確認可能。

http://chromedriver.storage.googleapis.com/LATEST_RELEASE


2018/06/23時点での最新版は2.40なので、2.40をインストールする。

$ wget https://chromedriver.storage.googleapis.com/2.40/chromedriver_linux64.zip
$ unzip chromedriver_linux64.zip -d ~/bin/


起動するとバージョンが出てくるので、インストールできているかを確認する。

$ chromedriver

google-chrome

$ wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
$ sudo dpkg -i google-chrome-stable_current_amd64.deb
$ sudo apt-get update
$ sudo apt-get grade


最新版がインストールできているかを確認する。

$ google-chrome --version


最新版は、このサイトから確認できる。

https://www.whatismybrowser.com/guides/the-latest-version/chrome

なぜバージョンアップで解決できる?

seleniumがブラウザを自動制御するときには以下の構成になっている。

selenium >> chromedriver >> google-chrome

seleniumは直接は、ブラウザ(google-chrome)は制御できないので、chromedriverを介して制御する。

ユーザーによっては、googl-chromeFireFoxだったり。

このエラーは、chromedriverとgoogle-chromeのどちらかが古いことで起きる。

chromedriverのバージョンが古すぎると、google-chomeを制御できなし、その逆もしかり。

chrome-dirverには、サポートしているchromedriverのバージョンの幅も調べたら出てくるので、ちゃんと確認したければ、そこを確認する。

これでもまだ解決しないとき

chromedriverをダウングレードすると解決することが多い。

これに関しては、なぜかは不明。。。

現在最新版の2.40をインストールしてもエラーが解決できなかったため、順にダウングレードしていって2.38版でエラーなく動作するようになった。

$ wget https://chromedriver.storage.googleapis.com/2.39/chromedriver_linux64.zip

  ↓↓↓↓↓↓

$ wget https://chromedriver.storage.googleapis.com/2.38/chromedriver_linux64.zip

chromedriverは結構頻繁にバージョンが更新されているようで、こまめにバージョンを気にしないとバグのもとに...

まとめ

seleniumエラー多い。嫌い。

以上、終わり!

nginxとuwsgiを使っていてInternal Server Errorが発生したとき

Internal Server Error

nginxとuwsgiを使っていてInternal Server Errorがでたので、対処法をまとめておきます。

Internal Server Errorが発生している原因は、uwsgiの設定のミスと権限の設定のミスの2つでした。

エラーログを見てみる。

 cd /var/log/nginx
tail -n 100 error.log

以下、エラーログ。

connect() to unix:///tmp/uwsgi.sock failed (2: No such file or directory) while connecting to upstream,

uwsgi側でソケットが作成されず、uwsgi.sockが見つからない、というエラーっぽい。

uwsgi側に原因があると判明しました。

原因1

権限

公開ディレクトリの権限が正しくありませんでした。

/var/www/html

このhtmlの権限がrootになっていたので、書き換え。

chown -R www-data:www-data html

nginxはwww-dataユーザーが実行することになるため、www-dataがアクセスできる権限にしておかないといけない。

原因2

uwsgiの設定

uwsgiを立ち上げたときに、エラーがでている。

uwsgi --ini index.ini


以下、エラー。

ImportError: No module named 'app'

モジュールの呼び出しに失敗しているので、これはuwsgiでエラーが発生はしているが、python周りっぽい。

以下、uwsgiの設定。

[uwsgi]
module = app
callable = app
master = true
processes = 1
socket = /tmp/uwsgi.sock
chmod-socket = 666
vacuum = true
die-on-term = true

module = app、こいつが原因だ。

moduleには、アクセスがあったときに立ち上がるpythonファイルを指定する。

この場合だと、app.pyが立ち上がる設定になっている。

しかし、app.pyなんてファイルはないため、ImportErrorが発生している。

そういえば、app.pyではなく、index.pyという名前で作成していた。

module = appからmodule=indexに書き換えて解決。

うっかりミス。

まとめ

以上、終わり!

RSA暗号をpythonで実装してみた(車輪の再発明)

RSA暗号を実装しみてる

半年前にRSA暗号勉強したのですが、ほぼほぼ忘れてしまっていました...

記憶力悲しき。

RSA暗号を忘れないように、今回はちゃんと記事として置いておこうと。

人様に公開するような内容ではありません。

参考記事

非理系が学ぶなら、このサイトがおすすめ。

RSA暗号の世界 – まいとう情報通信研究会


コードを書くときに参考にしました。

qiita.com

コード

import random


def gcd(a, b):
	# 最大公約数を求める
	while b:
		a, b = b, a % b
	return a

def lcm(a, b):
	# 最小公倍数を求める
	return a * b // gcd (a, b)

def generate_keys(p, q):
	# 与えられた2つの素数pとqから秘密鍵と公開鍵を生成する

	pq = p * q
	period = lcm(p - 1, q -1)

	#公開鍵の候補をリストに入れる
	#period = lcm(p - 1, q -1)の中にある素数をappned
	prime_number_list = []
	for i in range(2, period):
		if gcd(i, period) == 1:
			prime_number_list.append(i)

	#ランダムでpublic keyを抽出
	public_key = random.choice(prime_number_list)

	#秘密鍵を生成
	secret_key = 1
	n = 1
	while True:
		# 乗算したら元に戻る数値を探す
		# (A3)D = A{n × (P – 1) × (Q – 1) + 1}
		if secret_key * public_key == n * period + 1:
			break

		# secret_key * public_keyがn * period + 1より大きくなった場合は、nにプラス1
		if secret_key * public_key > n * period + 1:
			n += 1

		secret_key += 1 

	return [public_key, secret_key, pq]


def encrypt(plain_text, public_key, law):
	# 公開鍵を使って、プレーンテキストを暗号化
	encode_text =  [ord(char) for char in plain_text]
	encrypt_text = [i ** public_key % law for i in encode_text]
	encrypt_text_join = "".join(chr(i) for i in encrypt_text)

	return encrypt_text_join


def dencrypt(encrypt_text, secret_key, law):
	# 暗号化されたテキストの解読
	encode_text = [ord(char) for char in encrypt_text]
	dencrypt_text = [i ** secret_key % law for i in encode_text]
	dencrypt_text_join = "".join(chr(i) for i in dencrypt_text)

	return dencrypt_text_join


if __name__ == "__main__":
	text = "hello world"

	p = 101
	q = 3259

	public_key, secret_key, law = generate_keys(p, q)
	encrypt_text = encrypt(text, public_key, p*q)
	dencrypt_text = dencrypt(encrypt_text, secret_key, p*q)
	
	print("plain_text : ", text)
	print("encrypt_text : ", encrypt_text)
	print("dencrypt_text : ", dencrypt_text)

雑用は全てチャットボットに任せよう計画

今日の記事

自宅のubuntupython製のチャットボットを作成しました。

このチャットボットは業務効率化のためのキーマンであり、このチャットボットを会社で使いたい。

そのために奮闘したことを書き綴ります。

f:id:doz13189:20171105211852p:plain

チャットボットを作成しようと思った背景

私の所属する会社は、雑用は1年目に任されます。(だいたいどこの会社も一緒かな)

雑用とは例えば、どこどこのサーバーの権限ちょうだいとか、この日に誰々来るから入館のカードを作って、とかどこの会社でもあるようなことです。

その雑用は、1年目の新人がやります。

雑用の量を定量的に示すと、週5日 × 8時間勤務だとすると、そのうちの1日はこういった雑用で消えます。


また、次の新人が入ってきたらこれらの雑用は次に引き継がれます。


私が問題視したのは、この引き継ぎにかかる時間です。

1年間、そういった雑用をしているそれになりに詳しくなり、それを次の新人に引き継ぐのはそれなりに時間がかかります。


新人は配属されて早々にこういった雑用を一気に引き継がれる、というスタイルで私の会社は長年回ってきたようです。


この引き継ぎの量の多さに、配属された新人は100%げんなりします。

しかも、職場の右も左もわかっていない新人がこれらを覚えるのはけっこう苦痛!

(私はその地点で本気で転職を考えていました、私はこんなことをやりにこの会社に入ったんじゃない!と思いながら...)


この引き継ぎの時間をどうにか短縮できないか、と色々と考えついた先がチャットボットでした。


徹底的に雑用をマニュアル化し、それをドキュメントにしておいて、そこへのアクセスにチャットボットを使う、というイメージです。


例えば、派遣社員の方が、

skypeのパスワード忘れちゃった〜、パスワード初期化して〜」

ということはよく起こります。


初期化の手順はドキュメント化しているので、チャットボットに、

skypeのパスワードの初期化の仕方を教えて」

と問い合わせます。

f:id:doz13189:20171105211915p:plain


すると、ドキュメントの場所を返してくれます。

f:id:doz13189:20171105211852p:plain


あとはドキュメントを見ることでこの雑用は解決します。


この計画を「雑用は全てチャットボットに任せよう計画」と呼んでいます。

この計画の肝

この計画の肝は、実は徹底したマニュアル化にあります。

正直、チャットボットはオマケなんですよね。

面白そうだし、作ったら上司の食いつきが良くなりそうだから作りました(個人的に1回チャットボットを作ってみたかった)


あくまでもチャットボットは、マニュアルへのアクセスの手段でしかありません。

それよりも、ちゃんとしたマニュアルを作成しないと、次に入る新人はマニュアルを見ても雑用をこなすことが出来ません。

中途半端なマニュアルでは新人は「これわかりません、どうやってやるんですか」と私に聞きに来ることが目に見えています。

この計画はもっと先がある

今はチャットボットは、マニュアルへのアクセス手段でしかありません。

しかし、今後は雑用をチャットボットで行う、というところまで持って行きたいです。


つまり、自動化ですね。

ゆえの「雑用は全てチャットボットに任せよう計画」です。


雑用の種類によっては、自動化できないものもありますし、自動化するコストとその後のメンテのコストを考えると見合わないものもあります。

そこはしっかりと見極めながら進めようと思っています。

全部が全部、というのは難しいですが少しでも雑用を減らしたいと考えています。


マニュアルを作成しながら、ここは自動化出来そうとか、しても意味なさそうとか目星をつけながら、作業をしています。

来年の新人には雑用じゃなくて、もっと大切なことに時間を割いて欲しい

新人は、業務知識が圧倒的に足りていないため、寸暇を惜しんで勉強をしています。

でないと、まともに仕事ができないですし、仕事が楽しくもなりません。


そこに雑用があるわけですから、この雑用の鬱陶しさは半端じゃありません。

私の意見

この雑用を新人に任す、ということに関しては一定の合理性があります。

先輩社員の中で、人件費を比べた時に一番安いのは新人であるためです。


ただ、これらの雑用は新人の仕事への満足度と成長の機会を大きく失わせています。

またこういった企業体質から、優秀な新人ほど転職をしようとしています。


多くの上の人は「1年の我慢だから」と言います。

確かに、以前のように終身雇用を約束され、会社での人生プランを20年、30年考えているなら、「1年くらいだったら我慢するか」となります。


しかし、そういう時代じゃないですよね。

5年で転職を考えている人にとっては、1年は5分の1です。


昔より転職が楽な今の時代は、仕事への満足度が低い、というのは転職の動機に簡単になりえます。


ただ、こういった現場でのことは、管理職の人はあまり見えません。

そのため、恐縮ながら新人の私が声を大にして改善を呼びかけています。

私の意見2

この雑用の量を見た時に、こんなの派遣でも雇ってやらせるべきだと考えていました。

ですが、今のこの時代に人を雇って雑用をやらせるっていうのもスマートではないのかも、と。

派遣の分、本社員よりは人件費は安いですが、会社としてはやはりコストです。


であれば、何とか自分の得意なpythonを使って何とかできないかなぁなんて。

プログラミングを使って解決するということに、一度はトライしていいかな、と考えるようになりました。


docomoのReplAIなど社外のサービスを使うことも考えましたが、コストもかかってしまうし、新人がさすが部からお金を落とすのはまだ難しい。

まぁ、チャットボット自体はそこまで難しいものではないし、作ってみるか、というノリです。

まとめ

この計画はなんとか形にもっていきたいです。(まだまだ途中!)

しかし、この計画はメイン業務ではありません。

自分の仕事は仕事であり、また雑用もあり、その雑用のマニュアル化もあります。

業務中はなかなか忙しいですが、何とか完遂したいという思いです。

※P.S.

社内で雑用と言うと、一部の上の人から起こられます笑

雑用ではない!と。

そのため社内では依頼業務とか呼んでいますが、これらは確実に雑用だと個人的に思っているので、この記事では雑用と書いてやりました

MeCabをPython 3.4.5にインストール in Ubuntu 16.0.4

MeCabのインストールってコケがちらしいです

たしかに、ちょっとコケた

condaでpythonのバージョンを変えながら、試してると3.4.5で成功。

インストール手順

mecabをインストール。
ついでに辞書も。

#mecabをインストール
$ sudo apt-get install mecab

#辞書もインストール
#mecab-naist-jdicという辞書もある
$ sudo apt-get install mecab-ipadic


この時点でMeCabは使用可能。

#mecabというコマンドの後に適当に文章を打つ
$ mecab
私はストックドッグというブログをやっています。

この状態では、文字化けしているはず。

UTF-8に変換することで解消。

apt-get install mecab-ipadic-utf8


python3に対応させるためのツールをインストール。

sudo apt-get install libmecab-dev
sudo apt-get install python3-setuptools


いよいよ、pythonライブラリをインストール。
の前にpipをアップデートしておく。

pip install --upgrade pip

なぜなら、これしないとこんな警告がでる。

You are using pip version 8.1.1, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.


この後にpythonライブラリをインストール。

pip install mecab-python3

まとめ

同じ手順でdocker上のubuntuに入れようとしたら、エラーが出ました。

適当に何回かやったら上手くインストールできました。

ほんとよくわからんかったです。

bitFlyerのAPIをPythonで使ってみた

bitFlyerのAPIを使ってみた

すごく丁寧なドキュメントなので、本当にわかりやすいです。

こちらがAPIの公式ドキュメント。

https://lightning.bitflyer.jp/docs?lang=ja&_ga=2.266574860.321189620.1504178349-1321023365.1503200033


bitFlyerのAPIが使えるpythonライブラリもあるのですが、勉強もかねて一度は自分でやってみようという感じです。

簡単なAPIの使い方説明

基本的には、curlでリクエストを送ったら、レスポンスに情報が入っています。

マーケット情報が欲しければ...

$ curl https://api.bitflyer.jp/v1/getmarkets

[{"product_code":"BTC_JPY"},{"product_code":"FX_BTC_JPY"},{"product_code":"ETH_BTC"},{"product_code":"BCH_BTC"},{"product_code":"BTCJPY01SEP2017","alias":"BTCJPY_MAT1WK"},{"product_code":"BTCJPY08SEP2017","alias":"BTCJPY_MAT2WK"}]

けっこうたくさんの種類の仮想コイン扱ってるんですね〜

ちなみに、返り値はjson形式なので、jsonファイルに保存したい場合はリダイレクトしてあげる感じ。

curl https://api.bitflyer.jp/v1/getmarkets > getmarkets.json


エンドポイントURLがhttps://api.bitflyer.jp/v1/これなので、こいつのお尻に欲しい情報の種類をくっつけます。

マーケット情報が欲しいなぁって思ったら、getmarkets

板情報が欲しいなぁって思ったら、getboard

みたいな感じです。

https://api.bitflyer.jp/v1/

#マーケット情報
https://api.bitflyer.jp/v1/getmarkets

#板情報
https://api.bitflyer.jp/v1/getboard

と、こんな感じですが、毎回、curlするのも面倒なので、Pythonで書いてしまいましょう。

Pythonプログラム

汚いプログラムですみません笑

初心者でも読みやすいようなプログラムにしています。

チャームポイントはエンドポイントURLの場所です(なんで関数の外にいるんですかね)


リストじゃなくて辞書型のほうがいいやろ、とかは自分でも思うのでまた今後直します...

import urllib.request
import json


#エンドポイントURL
endpoint = "https://api.bitflyer.jp/v1/"


#APIを呼んでくる関数
def call_api(what, which):

	print("----------" + what + "----------")

	#GETパラメータで付与したい情報を辞書形式で持つ
	data = {}
	data["product_code"] = which
	# data["count"] = 
	# data["before"] =
	# data["after"] =  

	#URLとして送れる形に変換(エンコード)
	url_values = urllib.parse.urlencode(data)

	#リクエストを送っている
	req = urllib.request.Request(endpoint + what + "?" + url_values)
	with urllib.request.urlopen(req) as res:

		#レスポンスを読める形にする
		response = res.read().decode("utf-8")


	#jsonファイルを保存します
	saveFile(what, response)

	return response


def saveFile(what, response):
	f = open(what + ".json", "w")
	f.write(response)
	f.close()


#APIで呼べる情報をリスト形式に
api_list = ["getmarkets", "getboard", "getticker", "getexecutions", "gethealth",
			"getchats"]

#GETパラメータに付与する情報をリスト形式に
product_code = ["BTC_JPY", "ETH_BTC"]


response = call_api(api_list[1], product_code[0])
print(response)

プログラムとしては、APIで受け取った情報をjsonファイルに保存しています。

何かに使うときは保存したファイルを読み込む形がいいと思います。

まとめ

bitFlyerのAPIは、この中からさらに種類が2つに別れます。

HTTP Public APIとHTTP Private APIの2つです。

これらの2つの違いは取得してくる情報です。


HTTP Private APIはアカウントがないと取得できない情報をもってきます。

資産残高や他にも注文を出したりとかです。


今回使ったのは、HTTP Public APIです。

次は、HTTP Private APIの方を使ってみようと思います。


と、こんな感じでした。

以上終わり!

エラーの対処法 chrome not reachable

VPSなどの仮想環境でseleniumを扱っていると、こんなエラーに遭遇しました。

selenium.common.exceptions.WebDriverException: Message: chrome not reachable
  (Driver info: chromedriver=2.29.461571 (8a88bbe0775e2a23afda0ceaf2ef7ee74e822cc5),platform=Linux 4.4.0-57-generic x86_64)

エラーメッセージを直訳すると、「クロームは到達しなかった」的な。

原因

chromeのプロセスが溢れかえっている。

GUIで言うところの、chromeのブラウザを開きすぎて星の数ほどのタブがある状態。(たぶん)


chromeのプロセスが溢れかえっているか確かめてみよう。

ps aux | grep chrome

このコマンドで、私は溢れんばかりのchromeプロセスがでてきた

対処法

chromedriverのコマンドで動いているプロセスを全部killします。

killでPIDを一つ一つ打てる数ではないので、killallを使います。

killall chrome
killall chromedriver
killall chrome-sandbox

対処法2

解決法として以下のseleniumのオプションを追加します。

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-setuid-sandbox")
self.driver = webdriver.Chrome("/home/uTakahiro/py3/fund/chromedriver", chrome_options=chrome_options)

qxf2.com

stackoverflow.com


まとめ

以上、終わり!