素人が今更Twitter APIで遊ぶ　〜その４：インコ迷子情報bot作成編〜

こんにちは。
世間は夏休みムード。私は研究頑張るんご（泣）

今回は[前回](https://qiita.com/masahiro_isono/items/1af75a5fdfd18323238d)に引き続き、Twitter APIを用いて遊んでみる。
嘘、遊ばない。

今回はこれまでに学んだことを活かして、「インコの迷子情報をリツイートする」botチックなものを作成する。

#環境
Python3

#crontab
以前までに、特定のクエリを含むtweetのサーチ及びリツイートができるようになった。
これを実際にTwitterのアカウントとして、そしてbotとして定期的に稼働していきたい。

Python3上でbotを実装するのも良いが、あれこれ考えるのも面倒であったので、便利な機能であるcrontabを使ってみることにした。以下で、crontabの概要及びその使用方法について記述する。

crontab(クロンタブ？クーロンタブ？)コマンドはUnix系OSにおいて、コマンドの定時実行及びそのスケジュール管理を行うためのコマンドである。(絶賛wikiコピペ選手権)
つまり簡単にいうと、ターミナル上からcrontabを呼び出し、vim上でスケジュールを編集することで、そのコマンドを定期的に実行してくれる便利なコマンドであるということだ。

使い方は簡単で、ターミナルでcrontabと打てばいいだけだ。オプションは以下の通り。

| オプション | 説明 |
|-----------|------------|
| -e | cronを編集(設定)する |
| -r | cronを全削除する |
| -l | 設定されているcronを表示する |
| -u | ユーザを指定する |

注意する点はただ一つ。-eと-rだ。というのも、eとrはキーボード上で隣り合わせであるため、-eを打とうと思ってうっかり-rを打ってしまうとcronが全削除されてしまうからだ。

この点に注意して、

```
$ crontab -e
```

とすると、コマンドライン上でvimが起動し編集が可能になる。vimの操作に関しては他の記事を参照していただきたい。
書き方は

```vim
#分　時　日　月　曜日　実行したいコマンド
0 8,20 1-10 * * ls
```

このような感じ。「分」「時」「日」「月」「曜日」「実行したいコマンド」の順に記述する。*はワイルドカードであり、上の記述の場合、「毎月1〜10日の８、２０時ちょうどにlsを実行せよ」という意味になる。他にも色々設定できるので、試してみたい方は「crontab 書き方」でググってね。

今回はとりあえず、retweet.pyを毎日８、２０時に実行して欲しいので

```vim
0 8,20 * * * /usr/local/bin/python3 Desktop/Python/twitter/retweet.py
```

とした。

```
$ crontab -l
```

で確認すると、

![スクリーンショット 2018-08-08 19.42.25.png](https://qiita-image-store.s3.amazonaws.com/0/253596/c2ac1af2-1287-0aeb-c3d5-977c4368baf2.png)

となっており、しっかりと反映されていることがわかった。

これでcrontabの使い方はOK。
ちなみに定時実行するたびに、「ちゃんと実行しておいたぞー」というmailが届く。

![スクリーンショット 2018-08-08 19.44.17.png](https://qiita-image-store.s3.amazonaws.com/0/253596/d2f6ac9e-01bc-8030-7982-aa8f3b1d5512.png)

エラーが出た場合もこのmailに記載されている。mailは/var/mailにあり、

```
$ cat /var/mail/ユーザ名
```

で見ることができる。

これで実質botチックのようなものを作成することができた。
次に、「インコの迷子情報をリツイートする」ここを実装しよう。

#実装
まあ以前の記事となんら変わりはない。
メインコードはこんな感じ。

```python:retweet.py

import json,config_inko
import random as rd
from requests_oauthlib import OAuth1Session
from twitter_function import search, oauth, retweet

# key
ck = config_inko.consumer_key
cs = config_inko.consumer_secret
at = config_inko.access_token
ats = config_inko.access_token_secret

# parameter
q_cand1 = rd.choice(['迷子', '逃げ', '行方不明', '保護', '探し'])
q = 'インコ 東京都 ' + q_cand1
cnt = 10
res_type = 'recent'

# search
res = search(q, cnt, res_type, ck, cs, at, ats)

# retweet
for i in range(cnt):
    
    if not res[i]['user']['name'] == '東京都インコ迷子情報':
        
        tid = res[i]['id_str']

        retweet(tid, ck, cs, at, ats)
        
    else:
        
        print('Overlapped')
```

引用しているtwitter_function.pyはこんな感じ。

```python:twitter_function.py
# Twitterの各種関数

import json
from requests_oauthlib import OAuth1Session

def oauth(ck, cs, at, ats):
    twitter = OAuth1Session(ck, cs, at, ats)
    
    return twitter


def search(q, cnt, result_type, ck, cs, at, ats):
    twitter = oauth(ck, cs, at, ats)
    
    url = 'https://api.twitter.com/1.1/search/tweets.json'

    params = {'q' : q, 'count' : cnt, 'result_type': result_type}

    res = twitter.get(url, params = params)

    try:
        timelines = json.loads(res.text)
        timelines = timelines['statuses']
    
    except:
        print(type(json.loads(res.text)))
        print('Error')

    return timelines


def tweet(status, ck, cs, at, ats):
    twitter = oauth(ck, cs, at, ats)
    
    url = 'https://api.twitter.com/1.1/statuses/update.json'
    params = {'status' : status}

    res = twitter.post(url, params = params)

    if res.status_code == 200:
        print('Posted')
    else:
        print('Failed. : %d'% res.status_code)


def get_usr_tl(cnt, ck, cs, at, ats):
    twitter = oauth(ck, cs, at, ats)
    
    url = 'https://api.twitter.com/1.1/statuses/user_timeline.json'
    params ={'count' : cnt}
    
    res = twitter.get(url, params = params)

    timelines = json.loads(res.text)
              
    for line in timelines:
          print(line['user']['name']+'::'+line['text'])
          print(line['created_at'])
          print('*******************************************')
              
    return timelines


def retweet(tid, ck, cs, at, ats):
    twitter = oauth(ck, cs, at, ats)
    
    url = 'https://api.twitter.com/1.1/statuses/retweet/' + tid + '.json'
    params = {'id' : tid}
    
    res  = twitter.post(url, params = params)
    
    if res.status_code == 200:
        print('Success')
        
    else:
        print('Failed. : %d'% res.status_code)
        
        
def search_usr(q, cnt, ck, cs, at, ats):
    twitter = oauth(ck, cs, at, ats)
    
    url = 'https://api.twitter.com/1.1/users/search.json'
    params = {'q' : q, 'count' : cnt}
    
    res = twitter.get(url, params=params)
    
    usr_list = json.loads(res.text)
    
    return usr_list
    
    
def follow(usr_id, ck, cs, at, ats):
    twitter = oauth(ck, cs, at, ats)
    
    url = 'https://api.twitter.com/1.1/friendships/create.json'
    params = {'user_id' : usr_id}
    
    res = twitter.post(url, params = params)
    
    if res.status_code == 200:
        print('Success')
    else:
        print('Failed. : %d'% res.status_code)     
```

現状、どのような文言を用いて迷子情報が発信されているかを分析していないため、インコ＋東京都＋（迷子、逃げ、行方不明、保護、探し）のいずれかをサーチクエリとして設定している。テキストマイニング等を用いれば何かわかってきそうだが、悲しいことに未だそういった技術を習得しきれていないため、今回はこのような形にした。

#終わりに
そんなこんなで素人ながらも、インコの迷子情報をリツイートするbotチックなものを動かしている。

![写真 2018-08-08 23 27 27.jpg](https://qiita-image-store.s3.amazonaws.com/0/253596/5cdba29f-7393-7960-1846-8c56c3c6a305.jpeg)

フォロワー少なすぎワロタとか、プロフ写真ださすぎワロタなど様々な意見があるかと思うが、とりあえず許して。これからだから。

現状、リツイートする元tweetに偏りが生じていること、フォロワー数が圧倒的に少ないことが対処すべき問題である。前者については、サーチする際のパラメータをいじれば解決できそう。後者については、まずは「信頼できるアカウント」であることを示す必要があると考えており、初めは情報の量で攻めている。一定数のフォロワーを獲得でき次第、また何か新しいことをやってみようかな。

ありがとうございました。