プログラミング素人のArduino

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

janome(蛇の目)でマルコフ連鎖

マルコフ連鎖を使って文の生成をします。
自分のtimelineのtweetを参考に、電子工作やプログラミングっぽいtweetを生成するのが目標です。

↓参考
こちらには、urlやmenshonを正規表現でdeleteする方法も記載されています。
qiita.com

マルコフ連鎖については↓を参考に。
qiita.com

まずは、自分のタイムラインを取得します。
ここで、URL、返信、ハッシュタグ正規表現で抽出し削除します。
これが、マルコフ連鎖のソースになります。

def login(acount):
    if acount=="s":  #アカウントの切り替え用
        CONSUMER_KEY = "####"
        CONSUMER_SECRET = "####"
        ACCESS_TOKEN = "####"
        ACCESS_SECRET = "####"
    else:
        exit()

    auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
    api = tweepy.API(auth)
    return api

def my_tweet(acount):
    file = open('markov_sorce.txt', 'w', encoding='utf')  # 書き込みモードでオープン
    count=0
    api =login(acount)
    for tweet in api.home_timeline(count=100): #タイムライン
        if count>100: #タイムラインを100tweet取得
            break
        text = tweet.text
        text = tweet.text.replace('\r', ' ')  # 改行コードを削除
        text = text.replace('\n', ' ')  # 改行コードを削除
        replypattern = '@[\w]+'
        urlpattern = 'https?://[\w/:%#\$&\?\(\)~\.=\+\-]+'
        hashpattern = r'[##]([\w一-龠ぁ-んァ-ヴーa-z]+)'
        text = re.sub(replypattern, '', text)
        text = re.sub(urlpattern, '', text)
        text = re.sub(hashpattern, '', text)
        text = text.replace('RT : ', '')
        #print(text)
        file.write(text)
        file.write("\n")
        count+=1
        time.sleep(0.2)

次にマルコフ連鎖の中身になります。
元記事を参考に、もうすこし簡単なLogicにしました。
tweetごとに単語に区切りlistに格納し、tweetの終わりには’EOS’という文字列を識別子として入れて、これを見つけたら文の終わりという意味がわかるようにしました。
また、参考元の記事では、単語の連続数を3にしてますが、より自然になるように4にしました。
自然になりすぎても面白くないので、ここら辺は感性です。
ランダムでlistにアクセスし、文(tweet)の先頭('EOS'の次の単語)をさがし、4つ続けて単語を取得。
4つめと同じ単語を次の単語列の先頭として探します。
取得した単語列の中に’EOS’がみつかればそれで終了です。

# -*- coding: utf-8 -*-
from janome.tokenizer import Tokenizer
import random
import re #正規表現

def markov():
    text="1" #適当に初期化
    sentence=[]
    file = open('markov_sorce.txt', 'r', encoding='utf')  # UTFを指定する

    while text != "":
        text = file.readline()
        for token in t.tokenize(text):
            sentence.append(str(token.surface))    # 単語、表示形
        sentence.append('EOS') # 1つのtweetごとに区切りを入れる

    tweet=''
    rand=random.randint(1,len(sentence)-4) #乱数を生成し、listから単語を選択
    while sentence[rand]!='EOS': #'EOS'を探し
        rand+=1
    rand+=1 #'EOS'の次の単語をスタートとする
        word3=sentence[rand+3] #選択した最後の単語を記憶
    tweet=sentence[rand]+sentence[rand+1]+sentence[rand+2]+sentence[rand+3]
    rand = random.randint(1,len(sentence)-4)
    while sentence[rand+3]!='EOS' and sentence[rand+2]!='EOS' and sentence[rand+1]!='EOS': #'EOS'が出現するまで
        rand = random.randint(1, len(sentence)-4)
        if rand > len(sentence)-4: #listのサイズを超えたら0(listの先頭)に戻る
            rand = 0
        while sentence[rand]!=word3: #最後の単語と同じ単語を探す
            rand+=1
            if rand>len(sentence)-4:
                rand=0
        tweet=tweet+sentence[rand + 1] + sentence[rand + 2]+ sentence[rand + 3]
        word3 = sentence[rand + 3]
   if len(tweet) > 180: #長すぎるときは中断してRetry
            print('Error! Too long sentence.')
            markov()
    fd=tweet.find('EOS')
    tweet = tweet[:fd] #'EOS'より前をスライスで取得
    if len(tweet)<23: #tweetが短いときはRetry
        print('Error! Too short sentence.')
        markov()
    print(tweet)

if __name__ == '__main__':
    razpiTweet.my_tweet('s')
    markov()

このようにして、5回生成したのが↓。
twitterの仕様が変わって280文字までTweetできるはずだが、180文字で切ってもOverすることがある。
twitterの文字カウントの仕様がよくわからないと最適化できないなぁ。

【ITIL】   マック・ケンタ・回転寿司のスマホ代「3千円」を節約する方法まとめ』 格安SIMでドコモアドレスを維持しながら手軽に毎月の話、世の中の親御さんを必殺技に使ってるんだろう Elm 先日発表に使うかよくわからんの転職成功者忘年会!

ArduinoをVisual Studio Code ローカライズ え、もしかしてサンタさんに現れたゴミUIImageView

【定期ツイート】 HTMLのは私です。再配布や改変の偉くね

静電容量方式タッチパネルとは、世界を理解しているものである。  &gt;もしもいまのようなくらいブレブレ。そうだ、今回はそれを上回る53量子ビットの品 ゲーミングノートPC 外でもゲームをやりたい方や、それを公に発言します。 [電子ボルト]

()は、当フロアでのニュースをついて「サンタより」を節約する考えは、同時にバイファムが、今回は電流の単位アンペアから組み立てられた組立単位であり、代理行為」は立派な「代理といえそうなおっさんがなかった時代に作られ、タッチして欲しいという定義は必ずしも成り立たない。1989年に使うかよくある話。 お味はお土産として及第点だけどラスクとしてはもう少し。


次にラズパイにマルコフ環境をセットアップします。
ラズパイにjanomeをインストールしようとしたら、ラズパイゼロではできなかった。

$pip install janome

*だれかたすけて下さい。 (pip3も試しました)

Command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-4ppLvZ/janome/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-eQlIyU-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /tmp/pip-build-4ppLvZ/janome
Storing debug log for failure in /home/pi/.pip/pip.log

あきらめてラズパイ3でインストールしたら、インストールは成功したのにパスが通らないという状況に陥った。
そんなライブラリ無いよ的な感じで、プログラムを走らせようとしても、Errorで止まってしまいます。

pip showというコマンドでインストールが確認できる。

$ pip show janome
Name: Janome
Version: 0.3.5
Summary: Japanese morphological analysis engine.
Home-page: http://mocobeta.github.io/janome/
Author: Tomoko Uchida
Author-email: tomoko.uchida.1111@gmail.com
License: AL2
Location: /home/pi/.local/lib/python2.7/site-packages
Requires:

python2のフォルダ名だが???
と思って、もしや!!

$pip3 install janome

でインストールしなおしたら動いた。
明示的にpip3にしなきゃダメなんですね~。

$ pip3 show janome
Name: Janome
Version: 0.3.5
Summary: Japanese morphological analysis engine.
Home-page: http://mocobeta.github.io/janome/
Author: Tomoko Uchida
Author-email: tomoko.uchida.1111@gmail.com
License: AL2
Location: /home/pi/.local/lib/python3.5/site-packages
Requires:

python3でもっとも簡単に言語解析を使う

s51517765.hatenadiary.jp

twitterから趣味の似たユーザーを探すために、もっと多くのキーワードを抽出したいと思い、言語解析に挑戦しました。

Pythonで使える言語解析パッケージとしては、mecab(めかぶ)が有名なようです。
しかし、Windowsではなかなかインストールが一筋縄ではいかないということで、↓の記事のように簡単にできるよ、と書かれていても私にはやり遂げることはできませんでした。
qiita.com

例に漏れず、文字コードが分からないよ^^というErrorでくじけました。

C:\Users\****>pip install mecab-python3
Collecting mecab-python3
  Downloading mecab-python3-0.7.tar.gz (41kB)
    100% |████████████████████████████████| 51kB 1.1MB/s
Exception:
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\lib\site-packages\pip\compat\__init__.py", line 73, in console_to_str
    return s.decode(sys.__stdout__.encoding)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 15: invalid start byte

During handling of the above exception, another exception occurred:

Traceback (most recent call last):

そこで、重いのでお勧めしないという声がありますが、janome(蛇の目)をインストールすることにしました。
こちらは、数分かかりましたがインストールできました。

C:\Users\***>pip install janome
Collecting janome
  Downloading Janome-0.3.5.tar.gz (20.0MB)
    100% |████████████████████████████████| 20.0MB 137kB/s
Building wheels for collected packages: janome
  Running setup.py bdist_wheel for janome ... done
  Stored in directory: C:\Users\nakas\AppData\Local\pip\Cache\wheels\35\26\c9\43f2970612ffeda9113bd1c345d7d39216fdfe5118c40a18b3
Successfully built janome
Installing collected packages: janome
Successfully installed janome-0.3.5

早速試してみます。

from janome.tokenizer import Tokenizer
t = Tokenizer()
for token in t.tokenize('今日はpythonが終わったら、夕ご飯に餃子を食べようと思っている。'):
    print(token)
今日	名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
python	名詞,固有名詞,組織,*,*,*,python,*,*
が	助詞,格助詞,一般,*,*,*,が,ガ,ガ
終わっ	動詞,自立,*,*,五段・ラ行,連用タ接続,終わる,オワッ,オワッ
たら	助動詞,*,*,*,特殊・タ,仮定形,た,タラ,タラ
、	記号,読点,*,*,*,*,、,、,、
夕	名詞,副詞可能,*,*,*,*,夕,ユウ,ユー
ご飯	名詞,一般,*,*,*,*,ご飯,ゴハン,ゴハン
に	助詞,格助詞,一般,*,*,*,に,ニ,ニ
餃子	名詞,一般,*,*,*,*,餃子,ギョウザ,ギョーザ
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
食べよ	動詞,自立,*,*,一段,未然ウ接続,食べる,タベヨ,タベヨ
う	助動詞,*,*,*,不変化型,基本形,う,ウ,ウ
と	助詞,格助詞,引用,*,*,*,と,ト,ト
思っ	動詞,自立,*,*,五段・ワ行促音便,連用タ接続,思う,オモッ,オモッ
て	助詞,接続助詞,*,*,*,*,て,テ,テ
いる	動詞,非自立,*,*,一段,基本形,いる,イル,イル
。	記号,句点,*,*,*,*,。,。,。

とりあえず、ただしく動作しているようです。
ちなみにここで、ファイル名を"janome.py"にしたら、Errorになりました。

ModuleNotFoundError: No module named 'janome.Tokenizer';'janome' is not a package

こんな罠があるんですよ。
Errorが出る場合は、その中で一番最後に出てくるもののなかに、一番重要なものがありますので、そのメッセージでぐぐるとqiitaやstackoverflow、teratermの該当記事にたどりつくことができます。
Python 3.x - janomeを使った形態素解析が出来ない(84652)|teratail

ここからが、本題。
まず、解析にかけるテキストとしては、自身のtimeLineを約3時間分取得しました。
タイムラインはtweepyで以下のように指定すれば取得できます。
最大取得数が100のようなので、30分ごとに取得します。
これをテキストファイルとして保存しておきます。

for tweet in api.home_timeline(count=100): #タイムライン

このファイルをjanomeにかけます。

# -*- coding: utf-8 -*-
from janome.tokenizer import Tokenizer
t = Tokenizer()

file = open('s51517765_timeline.txt', 'r', encoding='utf')  # UTFを指定する
text=file.read()
dict={} #カウント用の辞書の初期化

for token in t.tokenize(text):
    hinshi = token.part_of_speech.split(',')[0]
    isNum = token.part_of_speech.split(',')[1]
    word = token.base_form #単語
    if hinshi == '名詞' and (isNum!='数' and isNum!='サ変接続'):
        print(token)
        if word in dict:
            dict[word] += 1
        else:
            dict[word] = 1

    elif hinshi == '動詞':
        print(token)
        if word in dict:
            dict[word] += 1
        else:
            dict[word] = 1
for k, v in sorted(dict.items(), key=lambda x: -x[1]): #降順ソート
    if v>3:
        print(str(k) + " : " + str(v))

f:id:s51517765:20171125181815p:plain
ここで、品詞を確認し、名詞と動詞だけを抽出します。ただし、名詞の中の”数”と”サ変接続”は除外します。
"数"はいわゆるアラビア数字でサ変接続は:(コロン)や;(セミコロン)などの記号を除外します。
elif hinshi=='動詞'のところは、うまく記述すればifの中に含めることも可能だとは思いますが、ここでは視認性を重視し分割しました。

これで、欲しい単語のみを抽出できました。
これを辞書に登録しながらカウントし、降順ソートします。

する : 156
https : 133
t : 133
co : 128
RT : 94
いる : 46
の : 41
てる : 35
なる : 34
人 : 31
こと : 29
れる : 28
ある : 26
やる : 21
ん : 20
できる : 18
ブログ : 17
くる : 16
思う : 15
さん : 15
見る : 14
的 : 14
よう : 13
化 : 12
中 : 12
時間 : 12
これ : 12
使う : 11
記事 : 11
今日 : 11
みる : 10
そう : 10
フレーム : 10
暗号 : 10
x : 9
電子 : 9
者 : 9
出る : 9
ため : 9
方 : 8
自分 : 8
言う : 8
私 : 8
わかる : 8
年 : 8
それ : 8
時 : 8
せる : 7
駅 : 7
A : 7
ー : 7
方式 : 7
られる : 7
出す : 7
日 : 7
みたい : 7
鍵 : 7
くれる : 6
作る : 6
書く : 6
系 : 6
電気 : 6
さ : 6
持つ : 6
つく : 6
前 : 6
知る : 6
映画 : 6
気 : 6
危険 : 6
物 : 6
ケーブル : 6
学生 : 6
code : 6
festival : 6
しまう : 5
以外 : 5
しれる : 5
コード : 5
アプリ : 5
人間 : 5
Android : 5
技術 : 5
m : 5
C : 5
回路 : 5
回 : 5
読む : 5
PC : 5
手 : 5
いう : 5
たち : 5
情報 : 5
ロボット : 5
普通 : 5
英語 : 5
機器 : 5
企業 : 5
おる : 5
買う : 5
綺麗 : 5
問題 : 4
切る : 4
いただく : 4
w : 4
インターネット : 4
すぎる : 4
可能 : 4
y : 4
穴 : 4
ちゃう : 4
県 : 4
u : 4
日本 : 4
何 : 4
s : 4
全体 : 4
見える : 4
r : 4
食べる : 4
GitLab : 4
数学 : 4
ガール : 4
秘密 : 4
分 : 4
頭 : 4
以上 : 4
もの : 4
対象 : 4
度 : 4
T : 4
聞く : 4
思い出す : 4
姿 : 4
アニメ : 4
死ぬ : 4
でる : 4
つける : 4
ツイート : 4
画像 : 4
車 : 4
ぶつ : 4
森 : 4
どこ : 4
定期 : 4
経済 : 4
今 : 4
本 : 4
必要 : 4
ナイフ : 4
Excel : 4
アクセサリー : 4

まだ、一般的すぎる単語が多い気がしますが、うまく組み合わせれば使えそうな単語が拾えているようにも思います。
このListを見たら何となく理系っぽいイメージが出ているのではないでしょうか?

辞書型の使い方は↓を参考。

Twitterで趣味の似た人を探す

Pythoneで趣味の似た人を探すツールを作成しました。
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;  //フォームを最前面に
            }
        }