2017年08月02日

レンタルサーバー(xrea.com)でpythonを動かす時の覚書

下記の様な今まで作成した下記のPythonのコードをレンタルサーバのxrea.com上でCGIで動かしました。その時の覚書です。
WordPressやはてな等でよく見る「ブログカード」があります。多分↓な感じな...

ログイン準備とログイン直後

  1. SSHのログインはログインするHost情報をWebから登録する必要がある
  2. ログイン後のbashは、そのままだとcdすらできないのでcshを起動させる

外部モジュールのインストール

インストールの前に下記を設定する
setenv PYTHONPATH "."
setenv PYTHONPATH "${PYTHONPATH}:~/.local/lib/python3.5/site-packages"

pipはインストール済みなので下記のコマンドでモジュールのインストールが可能
python3.5 -m pip install requests --user
python3.5 -m pip install beautifulsoup4 --user
python3.5 -m pip install tweepy --user
python3.5 -m pip install lxml --user
python3.5 -m pip install numpy --user
python3.5 -m pip install pillow --user

文字コード関連

  1. FTPの転送はバイナリで実施する
  2. エンコードはUTF-8の改行はLFで保存
  3. ソースコード中に下記を記述しておく
import io,sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

とりあえず、これぐらいでローカル環境と同様に動作したかな。

追記

anacondaを用いたレンタルサーバ(xrea.com)上のpython環境構築は下記のエントリーで実施しています。
【解決編】と銘打ってもXreaPlusの有料プランにしただけなのですが、一応+α...
posted by くまなべ at 07:50 | Comment(0) | TrackBack(0) | Python

2017年07月27日

フォロー・フォロワーの分類を自動で実施してみた

たまにフォロワー分類みたいなことをしている人がいると思います。TwitterのUser情報やTweet情報を用いて自動で分類ができないかなーと思って、次の様な分類を実施してみました。

分類方法

  • X軸:投資方法がアクティブかどうか
  • Y軸:Twitter上での活動がアクティブがどうか

図にしてみると下記となります。Userの自己紹介文やTweet頻度を参考にして、この図の上にフォロワーやフォローの方のアイコンを分類わけして置いてみました。

20170730_activeGraphBase_0.png

結果


結果としては、下記のような分類分けになりました。投資方針の軸は株式・海外投資・不動産な人をアクティブにしてみました。いい加減なアルゴリズムですがインデックス投資な人はX軸の左寄りになるようにしています。

20170730_activeGraphBase_1.jpg

というわけで、そのいい加減なアルゴリズムに基づいたプログラムは次に続きます。


続きを読む
posted by くまなべ at 07:54 | Comment(0) | TrackBack(0) | Python

2017年07月25日

フォローとフォロワーの関係の可視化(Python + Graphviz)

最近、TwitterのAPIを叩いているのですが、せっかくなのでフォロー・フォロワーの繋がりを可視化してみたいなーと思いました。

と言うわけで、graphvizを用いて可視化しようとしたのですが、少しのノードでもグラフがbusyになってしまうので、自分のフォローとフォロワーの間だけにしてみました。といっても結構ごちゃごちゃしたグラフになりましたが。

自分のフォロー・フォロワーの関係図

作成したグラフは下記のようになります(巨大画像ファイルのため注意)。→の方向でフォローしている方向になります。

20170723_twitter_0.png

Graphvizにくわせるdot

Graphvizをpythonから直接叩ければよかったのですが、windowsでは環境設定が面倒なため、とりあえず下記のようなdotファイルを作成してGraphvizに食わせてグラフを作成しました。

digraph sample{
node[fontname="meiryo"];
"kumana_be"[image="C:\python\intro\twitter\icon\get\883820222527885312-kumana_be.jpg"];
"chihimasah"[image="C:\python\intro\twitter\icon\get\840769338671996928-chihimasah.jpg"];
"churio777"[image="C:\python\intro\twitter\icon\get\847223574586769408-churio777.jpg"];
<<中略>>
"manesetsu_crowd" -> "zenzenkabu";
"manesetsu_crowd" -> "minasek";
"manesetsu_crowd" -> "ryo_tatibana";
}


続いてソースコードになります。

続きを読む
posted by くまなべ at 07:13 | Comment(0) | TrackBack(0) | Python

2017年07月22日

リスク資産グラフの自動生成[SBI証券+DC年金](Python + matplotlib)

前回、SBI証券のリスク資産をパイチャート(円グラフ)で示すEXCELを作成しました。
Python関連を連続して書いているけれど、投資に関連する内容も!ということでS...
自分が保有しているリスク資産はSBI証券とDC年金となります。また、現在は半年に1回サイトにアクセスして評価額を確認しながらEXCELを作成してグラフを作成していました。この作業は手間がかかるため、SBI証券とDC年金の2つのリスク資産配分をを合算したパイチャートのグラフを自動で作成したいと考えました。

コマンドと実行結果

コマンドは下記となります。

> python.exe .\graphAA.py .\piChart.png <SBIID> <SBIPW> <DCID> <DCPW>
Navigating for SBI...
Signing for SBI...
Navigating for SMTB...
Signing for SMTB...
Saving pieChart...

今回はEXCELを作成するのではなくて、パイチャートの画像データを直接作成しています。下記のパイチャートが自動で作成されました。
20170719_python_piChart.png

下記の記事の2017年7月時点のリスク資産と比較してほぼ同じとなっているので、情報の取得はうまくいっていると思います。あと、他の人はリスク資産の分類のチャートをどのようにして作成しているのかが気になります。MoneyForwardでも自分が思ってたようなチャートを作れなかったので……。
半年に一度の資産状況確認を実施してみました。...
続いてソースコードになります


続きを読む
posted by くまなべ at 16:00 | Comment(0) | TrackBack(0) | Python

2017年07月21日

Twitter上のインデックス投資家はズボラなのか?(Python+Tweepyコード編)

と言うわけで、結果編からの続きです。
最近「Python+Tweepy」でTwitterのAPIを叩いているのですが、...
参考にしている書籍は「Pythonによるスクレイピング&機械学習 開発テクニック」になります。


TwitterのAPIを叩いて、特定の検索ワードのTweetを取得し、そのtweetを呟いているIDのアイコンを確認しています。defaultアイコンかどうかであれば単純な一致で良いと思いますが、せっかくなので上記書籍の七章のAverage Hashとハミング距離を用いています。

自己紹介文の文字数は、そのまま情報を取得して文字数を数えています。

# coding='utf-8'
###########################################################################
# Twitterの検索を行って、その検索に引っかかるユーザーのiconをチェックする
# defaultアイコンの人はズボラと判断する
# アカウント情報が必要になるのでforegoで.envを読みだす
# Usage : .\forego.exe run python.exe .\tweepy_search.py <検索ワード> <検索数> <Debugファイル名>
# Example : .\forego.exe run python.exe .\tweepy_search.py "インデックス投資" 100 bbb.txt

from PIL import Image
import numpy as np
import os
import sys
import tweepy
import urllib.request
from requests_oauthlib import OAuth1Session
import matplotlib.pyplot as plt


# Agerage hash生成
def average_hash (fname, size = 16):
img = Image.open(fname)
img = img.convert('L')
img = img.resize((size,size), Image.ANTIALIAS)
pixel_data = img.getdata()
pixels = np.array(pixel_data)
pixels = pixels.reshape((size,size))
avg = pixels.mean()
diff = 1 * (pixels > avg)
return diff

# np2hashは今回は使用しない
def np2hash(ahash):
bhash = []
for n1 in ahash.tolist():
s1 = [str(i) for i in n1]
s2 = "".join(s1)
i = int(s2,2)
bhash.append("%04x" % i)
return "".join(bhash)

# 元画像と比較画像のハミング距離の計算
def hamming_dist(a,b):
alist = a.reshape(1,-1)
blist = b.reshape(1,-1)
dist = (alist != blist).sum()
return dist

# 環境変数から認証情報を取得する。
CONSUMER_KEY = os.environ['CONSUMER_KEY']
CONSUMER_SECRET = os.environ['CONSUMER_SECRET']
ACCESS_TOKEN = os.environ['ACCESS_TOKEN']
ACCESS_TOKEN_SECRET = os.environ['ACCESS_TOKEN_SECRET']

# 初期化
maxId = 999999999999999999 # 検索結果用ID
maxIdOld = 999999999999999999 # 検索結果用ID
words = {} # 単語とその登場回数を格納
searchPage = 0

# 認証情報を使う
# wait_on_rate_limit = True はAPI制限に引っかかったときにWaitする設定
auth = tweepy.OAuthHandler(CONSUMER_KEY,CONSUMER_SECRET)
auth.set_access_token(ACCESS_TOKEN,ACCESS_TOKEN_SECRET)
api = tweepy.API(auth, wait_on_rate_limit = True)

checkedUserList = []
totalNum = 0
zuboraNum = 0
totalBioLenSum = 0
totalBioLenList = []
searchWord = sys.argv[1] # 検索WORD
maxPage = int(sys.argv[2]) # maxPage * 100のTweetを取得する
outFileName = sys.argv[3] # Debug出力

# 出力ファイルOpen
outFile = open(outFileName,'w',encoding='utf-8')

# defaultアイコンのhash
srcHash = average_hash(os.path.join(os.getcwd(),"icon","default","default.jpg"))
while True:
# maxIdは前のid-1を渡すことに注意
searchTweets = api.search(q=searchWord,count=100,result_type='recent',max_id=maxId-1)
for tweet in searchTweets:
# Debug用にTweetをTextに保存しておく
# cmdline = str(tweet.user.screen_name) + str(tweet.text) + str(tweet.created_at) + str(tweet.id) +'\n'
# outFile.write(cmdline)

# 初めてチェックするUserのみを処理する
if not tweet.user.id_str in checkedUserList:
# API制限に引っかかったときの例外処理対策(実際はErrorは発生せずにWaitがかかる設定にしている)
try:
checkedUserList.append(tweet.user.id_str)
# Iconの取得
iconUrl = tweet.user.profile_image_url
iconPath = os.path.join("icon","get",tweet.user.id_str+"-"+tweet.user.screen_name+".jpg")
urllib.request.urlretrieve(iconUrl,iconPath)
# Hashの作成とdefaultアイコンとの比較
destHash = average_hash(os.path.join(os.getcwd(),iconPath))
hammingValue = hamming_dist(srcHash,destHash) / 256
# 自己紹介文の取得
bio = api.get_status(tweet.id).user.description
# 取得情報の処理
totalNum += 1
totalBioLenSum += len(bio)
totalBioLenList.append(len(bio))
print(hammingValue,":",tweet.user.screen_name)
# アイコンがdefaultアイコンだった時
if (hammingValue==0):
zuboraNum += 1
except:
print("[Error]:Because twitter API was accessed too much")
break

# idが今までのより小さければ代入
if(tweet.id < maxIdOld):
maxId = tweet.id
if maxIdOld == maxId:
# Tweetが見つからなければmaxIdOldと変わらないので検索結果をすべて受けとったと判断
break
elif searchPage == maxPage:
# もしくは最大で引数で指定したmaxPagex100までのTweetをチェックする
break
else:
maxIdOld = maxId
searchPage += 1

outFile.close()

# 結果出力
print("--------------- Result -----------------")
print("検索に引っかかったID数:",totalNum,"そのうちDefaultアイコンのID数:",zuboraNum,"Defaultアイコンの割合:",zuboraNum/totalNum*100,"%")
print("検索に引っかかったIDの自己紹介文の平均文字数:",totalBioLenSum/totalNum)

plt.hist(totalBioLenList,bins=20)
plt.title("自己紹介の文字数のヒストグラム")
plt.xlabel("自己紹介の文字数")
plt.ylabel("該当ID数")
plt.savefig("hist.png")
plt.show()
今回TwitterのAPIを叩いて気付いたのですが、15分間に情報取得のために叩けるAPIの回数制限って厳しいんですね。サードパーティのアプリを使っていてタイムラインが更新されないなーとか思っていたのですが、API回数制限によってタイムラインなど情報取得ができない状態が発生しているのに気づかされました。
posted by くまなべ at 07:48 | Comment(0) | TrackBack(0) | Python

2017年07月19日

とりあえずブログカードを自分で生成してみた

WordPressやはてな等でよく見る「ブログカード」があります。多分↓な感じなものだと思うのですが……
BLOG開始の自己紹介がてら半年に1度作成しているリスク資産状況です。...
で、このブログは「さくらのブログ」で作成しているのですが、「さくらのブログ」でのブログカードの作成方法が分からなかったため、今まで他のサイトの方のhtmlタグを参考にしながらタグを書いていました。

とは言っても、これだと非効率なのでリンクを入力すると自分用のブログカードを作成してくれるスクリプトをPythonで作成してみました。(画像は熊の絵で固定ですが……)

どんなものかと言うと・・・

Textのフォームにブログカードを作成したいLinkを記入して「作成」のボタンを押すと
20170719_python_0.jpg

下記の様なリンクカードを生成します。
20170719_python_1.jpg
あとは上記のタグを張り付ける形になります。見ての通りですがlocalhostでのCGIで実施しています。

備忘録代わりのソースコードは下記となります。
続きを読む
posted by くまなべ at 21:07 | Comment(0) | TrackBack(0) | Python

2017年07月16日

インデックス投資とアクティブ投資のTwitter検索結果解析(Python + Tweepy + janome)環境・コード編

前回の結果編に対しての環境・コード内容です。

PythonでTwitterの検索結果の解析をやってみたいなーということで、「イ...



使用するモジュールなど

下記を今回使用しています。
  • Tweepy
  • janome
> pip install janome
> pip install tweepy
また、foregoも用いていますダウンロードしたファイルを実行DIR直下に置いています。詳細情報は下記となります。

ソースコードとforego用環境ファイル

ソースコードは下記となります。
# coding='utf-8'

import os
import sys
import types
import json
import tweepy
import codecs
from requests_oauthlib import OAuth1Session
from janome.tokenizer import Tokenizer

# 環境変数から認証情報を取得する。
CONSUMER_KEY = os.environ['CONSUMER_KEY']
CONSUMER_SECRET = os.environ['CONSUMER_SECRET']
ACCESS_TOKEN = os.environ['ACCESS_TOKEN']
ACCESS_TOKEN_SECRET = os.environ['ACCESS_TOKEN_SECRET']

# 引数
searchWord = sys.argv[1] # 検索WORD
maxPage = int(sys.argv[2]) # maxPage * 100のTweetを取得する
outputNum = int(sys.argv[3]) # 上位outputNum個の単語を出力する
outFileName = sys.argv[4] # Debug用出力ファイル(Tweetを保存)

# 初期化
maxId = 999999999999999999 # 検索結果用ID
maxIdOld = 999999999999999999 # 検索結果用ID
words = {} # 単語とその登場回数を格納
searchPage = 0

# 認証情報を使う
auth = tweepy.OAuthHandler(CONSUMER_KEY,CONSUMER_SECRET)
auth.set_access_token(ACCESS_TOKEN,ACCESS_TOKEN_SECRET)
api = tweepy.API(auth)

# 出力ファイルOpen
outFile = open(outFileName,'w',encoding='utf-8')

# 日本語の解析
# Userの辞書を使用するときは前者を使う
# t = Tokenizer("userdic.csv", udic_type="simpledic", udic_enc="utf8")
t = Tokenizer()

while True:
# maxIdは前のid-1を渡すことに注意
searchTweets = api.search(q=searchWord,count=100,result_type='recent',max_id=maxId-1)
for tweet in searchTweets:
# Debug用にTweetをTextに保存しておく
cmdline = str(tweet.user.screen_name) + str(tweet.text) + str(tweet.created_at) + str(tweet.id) +'\n'
outFile.write(cmdline)

# Tweet内容を解析して単語にばらす
tokens = t.tokenize(tweet.text)
for token in tokens:
if token.part_of_speech.split(',')[0] == u'名詞':
# 名詞の取得
# 初めて出てきた名詞なら1.2度目以降はincrして登場回数を保存
if token.surface in words:
words[token.surface] += 1
else:
words[token.surface] = 1
elif token.part_of_speech.split(',')[0] == u'動詞':
# 動詞の取得
# 動詞は原型で保存する
if token.base_form in words:
words[token.base_form] += 1
else:
words[token.base_form] = 1

# idが今までのより小さければ代入
if(tweet.id < maxIdOld):
maxId = tweet.id
if maxIdOld == maxId:
# Tweetが見つからなければmaxIdOldと変わらないので検索結果をすべて受けとったと判断
break
elif searchPage == maxPage:
# もしくは最大で引数で指定したmaxPagex100までのTweetをチェックする
break
else:
maxIdOld = maxId
searchPage += 1

outFile.close()

# 単語の発生回数で降順に並べて出力する
loopNum = 0
for key,value in sorted(words.items(), key=lambda x: -x[1]):
# 特定の文字列は出力結果から除外
if not key in ['@',':','/',')','(','#','.','_', # 1文字記号
'0','1','2','3','4','5','6','7','8','9', # 1文字数字
'RT','co','https','://','t', # 特定文字列[1Byte]
'の']: # 特定文字列[2Bytes]
# Twitter検索で引っかかった単語(key)と登場回数(value)を出力
print(loopNum+1,key,value)
loopNum += 1
# 指定した分だけ単語を出力したら終了
if(loopNum == outputNum):
break

また環境変数をforego経由で渡すために.envという下記のようなファイルも作成しています。(ちなみに正式なファイルにはちゃんとしたKEYやTOKENを記載しています)

CONSUMER_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
CONSUMER_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ACCESS_TOKEN_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

それにしてもPythonはモジュールをpipでインストールして少しコードを書けば色々なことができるんですね。
posted by くまなべ at 21:02 | Comment(0) | TrackBack(0) | Python

2017年07月14日

Python + SeleniumでSBI証券の保有資産データを取得

Python関連を連続して書いているけれど、投資に関連する内容も!ということでSBI証券の保有資産データを取得&分類分けをしてEXCELでパイチャートを作成してみました。

まずは結果から

下記の様なパイチャートを含むEXCELを自動生成しました。国内株と投資信託のデータを取得して8分類に分けています。8分類なのはeMAXIS Slimバランスがあるからなのですが。
20170715_python_0.jpg

使用モジュール

EXCELのデータを吐き出すためにopenpyxlをインストールしています

> pip install openpyxl
続いてコード関連です。
続きを読む
posted by くまなべ at 22:44 | Comment(0) | TrackBack(0) | Python

2017年07月12日

Python + Seleniumによるヨドバシカメラ注文履歴の取得

Amazon注文履歴取得の時にも書きましたが、家計管理上、毎月の自分が使った分は分類でまとめたEXCELを作成して妻に送っています。そのデータには自分のクレジットカードの内容も含まれています。クレジットの明細だけだと、何を買ったのか分からないため過去の履歴を知りたい時があります。実はよっぽどのことが無い限り紙の本はAmazonではなくヨドバシで買っているので、ヨドバシの履歴も必要になります。

今回は「Python + Selenium」で取得してみました。備忘録替わりのソースコードは後回しで先に実行方法と結果です。

必要なもの

Seleniumとchromdriver(ブラウザにChromeを使っているので)をインストールしました。

コマンドと実行結果

引数にID(メールアドレス)とパスワードを渡して実行して3か月分の結果を取得します。
> python.exe .\yodobashi_order_history.py <ID> <Password>
Navigating...
Signing in...
---------------
注文日:2017年7月7日 注文番号:2142606149 ヨドバシ・ドット・コムでのご注文: 配達受取商品
  Pythonクローリング&スクレイピング -データ収集・解析のための実践開発ガイド- [ムックその他]
---------------
注文日:2017年6月11日 注文番号:2141144933 ヨドバシ・ドット・コムでのご注文: 配達受取商品
  リンスインシャンプー つめかえ用 [400ml]
  Fシステムサムライエッジ 8P [T字カミソリ替刃]
---------------
注文日:2017年4月22日 注文番号:2138765666 ヨドバシ・ドット・コムでのご注文: 配達受取商品
  KF-C118G-3A [microSDHCカード 8GB Class4]
  BSCR19U2WH [高速カードリーダー/ライター ホワイト]
値段は出力できていないのですが、クレジット明細に出ているのでわざわざ出力しなくても良いかなと思って出力していません。

つづいてソースコードです。

続きを読む
posted by くまなべ at 20:37 | Comment(0) | TrackBack(0) | Python

2017年07月11日

PythonによるAmazon注文履歴取得の拡張

以前に書いたのですが、家計管理上、毎月の自分が使った分は分類でまとめたEXCELを作成して妻に送っています。そのデータには自分のクレジットカードの内容も含まれています。

分類作成時に困ること

クレジットの明細を見れば大抵のものは分類ができるのですが、困ったことにAmazonは本・家電など色々なものが含まれるためクレジット明細だけでは分類ができず、サインインしたりメールを掘り出したりして何を買ったかを確認しないといけません。

対応策

PythonでAmazon注文履歴取得を取得するようにしました。といっても「Pythonクローリング&スクレイピング -データ収集・解析のための実践開発ガイド」を読みつつベースのコードを拡張しただけですが。

改変箇所

元々のコードだと、購入日と合計金額しか出力していません。そのため購入物も分かるようにしました。修正したのはprint_order_histryのみです。

def print_order_history():
"""
現在のページのすべての注文履歴を表示する。
"""
# ページ内のすべての注文履歴について反復する。ブラウザーの開発者ツールでclass属性の値を確認できる。
# 商品名を取得するためにorder-infoからorderに変更する
for line_item in browser.select('.order'):
order = {} # 注文の情報を格納するためのdict。
# 注文の情報のすべての列について反復する。
for column in line_item.select('.a-column'):
label_element = column.select_one('.label')
value_element = column.select_one('.value')
# ラベルと値がない列は無視する。
if label_element and value_element:
label = label_element.get_text().strip()
value = value_element.get_text().strip()
order[label] = value
print(order['注文日'], order['合計']) # 注文の情報を表示する。
# 商品名はhrefを目印にして取得できる。ただし画像からのリンクと区別するためにa-row直後のhrefを用いる
for title_element in line_item.select('.a-row > a[href^="/gp/product"]'):
if(title_element):
print(" " + title_element.get_text().strip())
print("")

出力結果

下記のような出力結果となり、コマンド一発で何を買ったのかが分かるようになりました。昨日頼んだおむつが一番最新の注文として出力されています。
2017年7月10日 ¥ 3,230
  グーン パンツ BIG (12~20kg) 156枚(52枚×3) 女の子 やわらかパンツ 【ケース販売】
 
2017年6月14日 ¥ 367
  uxcell HPノートパソコン用 修復部品 プラスチック トラックポイント ブルーキャップ  2個入り 高さ4.0mm
<<<後略>>>
 
posted by くまなべ at 20:31 | Comment(0) | TrackBack(0) | Python