プログラミング素人のはてなブログ

技術屋の末端。プログラミングも電気回路も専門外です。 コードに間違いなど見つけられたら、気軽にコメントください。 VC#、python3、ラズパイ始めました。

Twitterで趣味の似た人を探す

f:id:s51517765:20180103100052j:plain
【画像は趣味のイメージで内容とは特に関係ありません。】

Pythonで趣味の似た人を探すツールを作成しました。
Twitterの”おすすめユーザー”もありますが。
f:id:s51517765:20171118171437j:plain

def serch_new_friend():
 new_friend={}
    keywordlist=['電子工作','ラズパイ','アルディーノ','プログラミング']
    for keyword in keywordlist:
        print(keyword)
        for tweet in api.search(q=keyword, count=200):  # 検索
            if not tweet.user.screen_name in follower: #フォローのList
                if tweet.user.screen_name in new_friend:
                    new_friend[tweet.user.screen_name] += 1
                else:
                    new_friend[tweet.user.screen_name]=1
    for k, v in sorted(new_friend.items(), key=lambda x: -x[1]): #降順ソート
        if v!=1:
            print(str(k) + ": " + str(v))

keywordlistに自分の気になるキーワードを登録し、twitter検索でヒットしたアカウントを辞書(dictiorary)にカウントしていきます。ここでは、キーワードのListは一部省略しています。自分で考えてください。
すでにフォローしているひとは除外します。
twitterの検索はtweepyを利用しています。
フォローのリストはあらかじめ作成しておきます。
s51517765.hatenadiary.jp

辞書はすでにキーがあればカウントを+=1し、なければキーを作成します。
辞書のカウントでソートし、1度しかでてこないアカウントが大量に発生するので、カウントが1のものは除外してprintしました。
ソートした後は、辞書型として使えなくなります。

↓抽出結果例

072_pro: 13
l693g: 5
A7075duralumin: 4
I_HaL: 4
negiiiiii_0xFFF: 4
kentohmm265: 3
neno_n0: 3
Engineerism: 3
mushroom080: 3
rockin_keep: 3
arigayas: 3
progblues: 2
fernyiges: 2
okanao_robot: 2
deluwater: 2
dictators_circ1: 2
arkanal1: 2
kumokosi: 2
PA_information: 2
nomnom3939: 2
miwakuna: 2
hackshone: 2
ieeeic: 2
koron_bike: 2
sm58s: 2
chibaf: 2
zeus3110: 2
AGE43: 2
mascii_k: 2
Katase_sui: 2
IngaSakimori: 2
kazuki13gata: 2
kick_the_blues: 2
zarusoba44: 2
0hukurou0: 2
komegmi: 2
0209KaGaChi: 2
club_are: 2
momotarou_625: 2
ugokazarukoto11: 2
jyomu__: 2
SearEclair: 2
ITpassport_bot5: 2
G_Myake: 2
hisshi_bot: 2
soralis_nem: 2
DaraUmisuke: 2
omae_source_bot: 2
r4tk: 2
jeffi7: 2
herpuretears: 2
mUc3LS4p0JzNeae: 2
funuu: 2
solgrapher: 2
NEWBOOKINFO: 2
NekoAntarctica: 2
Space_kid_Jr: 2
jaialkdanel: 2

pythonでフォロワーの一覧をListとして作成する

フォロワーの一覧を作るのにちょっとListの使い方でハマったので、書いておく。
結局はListのappendを使って加えていけばよい。
tweepyのCursorを使って取得するが、APIのRate limitに引っかからないように 1秒のwaitをいれながら読み込ませる。
(IDを変更すれば他のアカウントのフォロー・フォロワーも取得できるのだが、これでも300でRate limitにかかってしまった。もっと、waitを広げる必要があるのだと思う。)
※2017/11/16追記
 >Rate Limitは15分で300らしい。
 >ということは、1分あたり20で少なくとも3秒のwaitが必要ということか?
 > →4秒のWaitをいれたら、300で引っかかることはなくなった。

最終的に完成したのは↓
コメントアウトのほうではフォローのリストも作成可能。

def friend():
    follower1=[]
    follow = tweepy.Cursor(api.followers, id="s51517765") #自分をフォローしているひと
    #follow = tweepy.Cursor(api.friend, id="s51517765") #自分がフォーローしている人
    print("My follower!")
    for friend in follow.items():
        follower1.append(friend.screen_name)

        time.sleep(4) #apiのRate limitのため
    print(follower1)

以下,失敗例とともにListの使い方を整理しておこうと思います。

読み込んだScreen_nameはstring型なので、そのままListに加えていこうと、

follower1=[]
for friend in follow.items():
    follower1 +=friend.screen_name
>>>error

としてもErrorになった。(ListにListでないものを追加しようとしているため)

test='1111'
test+='2222'
print(test)
>>>11112222

この場合は文字列の結合になる。

test=['1111']
test+=['2222']
print(test)
>>>['1111','2222']

という形に書くことができれば、希望通りなのだが、screen_nameをstring型で取得してもListじゃないからうまくいかない。

ここで、そういえばJoinという関数があったことを思い出す。

test1=['1111','2222']
test=','.join(test1)
print(test)
>>>1111,2222

joinはsplitの逆変換と覚えておけばよい。

#2017/11/23追記
Listの足し算としてのappend関数

test=['1111']
test.append(['333','444'])
print(test)
>>>['1111', ['333', '444']]

これでは”Listの要素にListが入る”のでここでは適切でない。

test=['1111']
test.extend(['333','444'])
print(test)
>>>['1111', '333', '444']

追加されるものがListである場合はextendを使う。

自動水やり機のアップデート

2年弱、ブレッドボードで使っていましたが、基盤を作りました。

ついでに、LEDが明るすぎるとの妻の意見を考慮し、LED(Greenのみ)に可変抵抗(1kΩ)をつなぎ、光量を調整できるようにしました。


f:id:s51517765:20171104205710j:image

 


f:id:s51517765:20171104205720j:image

 

マイコンArduino Unoから↓ Arduino nanoの互換品に変更。

analogWriteや割り込みピンが使えないのでプログラムも変更しました。

380円(購入当時)でほぼ、同等の働き! 

 

JSON形式からのData取得と辞書書式

APIの使い方を調べていくと、Twitterのようにライブラリ(CoreTweetやtweepyなど)が用意されているものはそれをインストールして使うことができますが、かならずしもライブラリがすべてあるとは限りません。一方で"JSON"という共通の方式で提供されているものがたくさん見つけられます。

これも、APIの一種?といっていいとおもいますが、JSONの扱い方がわかると応用も効きそうなので調べてみました。

JSONは"辞書オブジェクト"でDataが提供されています。

辞書オブジェクトは↓のような形式です。

score = {"math":75, "science":82,"english":"98"}
print(score)

とすると、

{"math":75, "science":82,"english":"98"}

と表示され、

print(score["math"])

とすると、

75

と表示されます。

実際のJSON形式を見てみると、データを取得する基本形が↓です。

import urllib
import json

url = 'http://weather.livedoor.com/forecast/webservice/json/v1?city=130010'
html = urllib.request.urlopen(url)
jsonfile = json.loads(html.read().decode('utf-8'))

これで、辞書形式で jsonfile にデータが取り込まれました。

ここではLivedoorのお天気情報を例にとりました。
weather.livedoor.com

APIのリクエスト例を参考にここでは東京を指定しました。

(例)「福岡県・久留米の天気」を取得する場合
下記URLにアクセスしてJSONデータを取得します。
基本URL + 久留米のID(400040)
http://weather.livedoor.com/forecast/webservice/json/v1?city=400040

実際にJSONを取得すると↓のようになります。形式が分かるように中身一部省略。

{'pinpointLocations': ['**省略**'],
'description':
 {'text': ' ※※tex省略※※', 'publicTime': '2017-10-29T10:49:00+0900'}
}

辞書が入れ子になっているようです。
ここでほしいのは、JSONの中の、descriptionキーの中のtextになります。

これは下のように記述します。

text =jsonfile['description']['text']

これで、下のように取得できます。

 前線が日本の南にあって、ゆっくり北上しています。また、台風第22号
が四国の南にあって北東へ進んでいます。

【関東甲信地方】
 関東甲信地方は雨となっており、伊豆諸島では雷を伴い激しく降っている
所があります。
 
 29日は、前線や台風の接近により雨で、伊豆諸島や関東地方南部では雷
を伴い非常に激しく降る所があるでしょう。

 30日は、冬型の気圧配置となるため、おおむね晴れますが、長野県や関
東地方北部の山沿いは、曇りで雨や雷雨となる所があり、標高の高い所では
次第に雪に変わる見込みです。

 関東近海では、30日にかけてうねりを伴い大しけとなるでしょう。船舶
は高波に警戒してください。

【東京地方】
 29日は、雨で、夜は雷を伴い激しく降る所があるでしょう。
 30日は、晴れる見込みです。

台風が来ていますね。(2017/10/29 11時現在)
これではすこし長いので、「東京地方」から後ろだけを取得します。

def weather():
    tdatetime = dt.now()
    url = 'http://weather.livedoor.com/forecast/webservice/json/v1?city=130010'
    html = urllib.request.urlopen(url)
    jsonfile = json.loads(html.read().decode('utf-8'))
    weather_txt = jsonfile['description']['text']
    try:
        index = weather_txt.find("【東京地方】")
        weather_txt = (weather_txt)[index:]
        weather_txt = '◆ラズパイ天気予報 ' + weather_txt
        api.update_status(weather_txt)  # tweet
    except:
        pass

クリップボードの中身を取得

以前作ったスクレイピングアプリなのだが、ChromeからURLをコピペして…実行し、ということを延々と行っていた。
s51517765.hatenadiary.jp

f:id:s51517765:20171021223347j:plain

この本を読んでいたら、クリップボードのテキストを取得する方法が載っているのを見つけました。

もしかしたら、C#でもできるんじゃないか?と思い調べたら、もちろんできたので紹介します。

これを組み込めば、

Chromeで必要なPageを探す。
②①のURLをコピー
スクレイピングアプリをアクティブに
クリップボードの中身をペースト
⑤ボタンクリックで必要な情報ゲット!

という工程が、

Chromeで必要なPageを探す。
②①のURLをコピー
③ボタンクリックで必要な情報ゲット!

とすることができます。

ボタンクリックも省略することも可能ですが、必要なURLを取得しているかどうか確認する必要があるので、やりすぎは逆効果になることもあると思い今回は組み込みません。

ボタンクリックの時にクリップボードの中身を取得し、web取得を走らせることもできるが、ここでは、クリップボードにURLが取り込まれたらアプリにURLを入力するようにしました。
このためには定期的にクリップボードを確認し、URLが取り込まれたら、URL boxに取り込み、アプリをアクティブにする、というようにします。
(省略しますが、URLであるかどうかをクリップボードのテキストが"http"で始まるかどうかを確認することでURL以外では動作させないということもできます。)

これにはタイマーイベントを利用します。

Visual StudioのForm1.cs[デザイン]のツールボックスから、Timerコンポーネントを追加すします。
デザイン画面のフォーム外にタイマーコンポーネントが追加されるので、タイマーコンポーネントをダブルクリックします。
すると、タイマーイベント private void timer1_Tick() が作成されます。

f:id:s51517765:20171021225237j:plain

Form1_Loadでtimer1を起動し、Intervalをセットします。これが、クリップボードのチェック間隔になります。
Form1起動時に、クリップボードの中身を取得し、初期化。これを変数”clp_text0”としました。
timer1_Tick()がInterval毎に実行され、クリップボードの中身が変化していれば、textBoxURLに中身をテキストで入力されます。
bool check_clp というbool型変数を設定し、一度しか実行されないようにします。これをつけないと何度も起動されてしまいます。
異なるURLを連続して取得したいので、テキストの取得が完了したら、この変数は初期化します。

private void Form1_Load(object sender, EventArgs e)
    {
        InitializeComponent();
        string clp_text0;
        bool check_clp=false;
        timer1.Interval = 1000; //タイマーインターバル
        timer1.Start();
        clp_text0 = Clipboard.GetText(); //クリップボードの中身を取得、初期化
     }
       private void timer1_Tick(object sender, EventArgs e)
        {
            if (clp_text0 != Clipboard.GetText()&&check_clp==false)
            {
                textBoxURL.Text(Clipboard.GetText());
                check_clp = true;
                this.TopMost = !this.TopMost;  //フォームを最前面に
            }
        }

Pythonの  "if __name__ == ‘__main__’:" とモジュール化

pythonでよく使う処理を関数として作成し、他のプログラムから呼び出すことができます。

main.py

import a  #a.pyをモジュールとして読み込む
import b  #b.pyをモジュールとして読み込む

a.function()
print("a is done.")
b.function()
print("b is done.")

a.py

print("start a.")
def function():
  print("This is a.")
if __name__ == ‘__main__’:
  print("a is main.")
  function()

b.py

print("start b.")
def function():
  print("This is b.")
if __name__ == ‘__main__’:
  print("b is main.")
  function()

このように、3つのpythonプログラムを作成し、同じフォルダに格納します。
a.py を実行すれば、

start a.
a is main.
This is a.

という風に実行されます。b.pyも同様。

main.py を実行すると、main.pyが実行され、a.pyとb.pyが呼び出されます。

start a.
start b.
This is a.
a is done.
This is b.
a is done.

しかし、単独にa.pyとb.pyを実行したときと異なり、main.pyを実行したときは、"a is main."、"b is main."は実行されません。
これは、"if __name__ == '__main__':"の中にあるためです。
"if __name__ == '__main__':"は直接a.pyまたはb.pyを実行したときに実行されます。

qiita.com

一方、main.pyを見ると

a.function()
print("a is done.")
b.function()
print("b is done.")

a.function()、b.function()と直接、a.py、b.pyのfunction()を実行しているように見えますが、
実は、これらの前に記述されている

print("start a.")、 print("start b.")は実行されます。

実は、

import a  #a.pyをモジュールとして読み込む
import b  #b.pyをモジュールとして読み込む

#a.function()
print("a is done.")
#b.function()
print("b is done.")

とすると、

start a.
start b.
a is done.
b is done.

モジュールとして呼び込むと、その時点で、
if __name__ == ‘__main__’:
以外の部分が実行されるのです。

通常、pythonのプログラムを同時に複数実行することはできませんが、このようなことに気をつけさえすれば、main.py(親プロセスと呼ぶ)から呼び出すことで、2つ以上のプログラムを実行させることができます。
それぞれの起動条件はmain.pyの中でfunction()の起動条件として設定します。

Raspberry Pi 3を一からインストール

Raspberry Pi3を購入し、一からのインストールに挑戦しました。


f:id:s51517765:20171010215412j:plain

日経Linux 2017年 09 月号

日経Linux 2017年 09 月号

Windowsで実施しているこちらの記事を参考にしました。
qiita.com

公式サイトからNoobsをダウンロードします。
f:id:s51517765:20171009091241j:plain
ダウンロードは30分ぐらいかかります。
感覚的には、とても遅いです。
Zip圧縮ですが、7-zipというソフトを利用し解凍します。
このソフトも重要なようで、始め7-zipがうまく動作せず、「解凍レンジ」というものを使って解凍したのですが、うまくいきませんでした。
インストールは始まるものの、99%で止まって「パーティション」がどうこう~というErrorになってしまいました。

7-zipを実行するとエクスプローラのようなものが出てくるので、ここで、問題のzipを右クリックで解答します。
たぶんこれでOK。
f:id:s51517765:20171009112113j:plain

SD Cardはぐぐると動作確認されているものがいくつか出ているので、この中から選びました。

SD CardはSD Cdard Formatterを使用します。
ver.4で実施している記事しか見つからないのですが、Downloadは"ver.5"しかありません。
仕方なく5で試します。結果的には問題なかったようです。
クイックフォーマットで可です。
f:id:s51517765:20171009091244j:plain

zipの解凍とSD Cardのフォーマットができたら、zipの中身をSD Cardにドラックドロップでコピーし、ラズパイに差し込み電源を入れます。
前回のスターターキットの時と同じインストールするOSを選択する画面がでてきます。
ここからは前回と同じです。
もう、できたも同然。

インストールができたら、wi-fiを設定し、SSHを有効にしようとするが
前回のときのraspi-config\advanced OptionにSSHがない!
Raspberry PiをWindowsで操作する(SSH) | S2

Interfacing Optionsにありました。
qiita.com

こんなトラップが次々と出てくるんですね…。

Teratermを使い始めてから、使うことはないですが、念のためリモートデスクトップ接続もできるように、xrdpの再インストールもしておきます。
何かの時に役に立つかも。
ここまで、約3時間。前回と同じくらいかかりました。

s51517765.hatenadiary.jp
s51517765.hatenadiary.jp
s51517765.hatenadiary.jp