【Pythonコード】Twitter APIによりTwitter検索ツールを作成してみた①
どうも、こじまるです。
私はTwitterの運用にSocialDogを使っています。キーワードモニター機能が割と便利で利用しているのですが、無料アカウントの場合だとフォロー、いいね、リツイートの回数に制限があります。
SocialDogで有料アカウントになり余計な出費をするのは嫌なので、Twitter検索ツールを自作してみました。
1.はじめに
対象読者
・Twitter APIの使い方を知りたい方
・python・Twitter APIで何か作ってみたい方
この記事を見てわかること
・Twitter APIの使い方、実装方法
2. システム概要
要件定義
要件1. キーワードからTweetの検索ができること
要件2. 検索結果よりいいね、リツイートができること
要件3. ユーザが操作できること
環境構築
今回の実装では、下記を使用しました。
・フロントエンド : HTML, JavaScript
・サーバーサイド : Python(Flask)
HTML、JavaScriptではCDNでJQueryなどを取得しています。そのため、必要なものは特にありません。Pythonでは、pipで下記のパッケージをインストールしています。
pip install flask
pip install requests
pip install requests-oauthlib
3. 実装
要件を満たすために、下記の機能を実現する必要があります。
1.キーワードからTweetの検索
2.検索結果よりいいね、リツイートの実行
1. キーワードからTweetの検索
キーワードからTweetの検索の流れ
キーワードからTweetの検索の流れ
①Flaskへの検索依頼
②キーワードの検索依頼
③検索結果の表示依頼
①Flaskへの検索依頼
HTMLからFlaskに対して、POST /searchTweetという形で検索依頼を投げます。
Flaskでは、POST /searchTweetでルーティングできるように、app.routeで定義する必要があります。この関数ではリクエストの内容を解析し、リクエストから検索条件を取得しています。
@app.route('/searchTweet',methods=["POST"])
def getTweet():
print('Enter getTweet')
data = request.get_data().decode('utf-8')
tmp,query = data.split('=')
q = "q={}".format(query)
lang = "lang=ja"
result_type = "result_type=recent"
count = "count=10"
entities = "include_entities=true"
②Tweeter APIにキーワードの検索依頼
①で説明した、getTweetの続きになります。①で取得した検索条件に基づき、Twitter API : GET search/tweetsを使ってTwitterからTweetを取得します。
twitter = OAuth1Session(settings.CONSUMER_KEY,settings.CONSUMER_SECRET,settings.ACCESS_TOKEN,settings.ACCESS_TOKEN_SECRET)
endpoint = "https://api.twitter.com/1.1/search/tweets.json?{}&{}&{}&{}&{}".format(q,lang,result_type,count,entities)
res = twitter.get(endpoint)
Twitter API : GET search/tweetsとGET statuses/lookupで取得したデータから、下記の情報を抽出し、リストに格納します。
ここで、retweeted_statusは引用なし(公式)リツイートの場合のみ取得できます。userオブジェクト・Tweetオブジェクトの内容はこちらの記事を参考にしました。
③検索結果の表示依頼
②で取得したuserオブジェクト・Tweetオブジェクトの情報を集積したリスト(tweet_list)をrender_templateメソッドの引数に指定します。
@app.route('/searchTweet',methods=["POST"])
def getTweet():
...
print("Exit getTweet")
return render_template('searchTweet.html', tweet_list=tweet_list)
今回は②で取得した検索結果を表示するために、tweet_listの配列数分ループさせるように実装しています。{{list.profile_image_url_https}}と記述することで、list内の要素にアクセスできます。
{% extends "layout.html" %}
{% block content %}
{% for list in tweet_list %}
<div class="twitter__block">
<figure>
<img src={{list.profile_image_url_https}} />
</figure>
...
</div>
{% endfor %}
{% endblock %}
いいね、リツイートは、検索実行時のいいね、リツイートの状態に基づきON、あるいはOFFにして表示する必要があります。そのため、下記のようにlist.favoritedの値に応じて、spanタグのclass属性の値を切り替えるようにしました。
{% if list.favorited %}
<span id={{list.tweet_id}} class="LikesIcon on">
<i class="fas fa-heart LikesIcon-fa-heart heart">{{list.favorite_count}}</i>
</span>
{% else %}
<span id={{list.tweet_id}} class="LikesIcon">
{% if list.favorite_count > 0 %}
<i class="far fa-heart LikesIcon-fa-heart">{{list.favorite_count}}</i>
{% else %}
<i class="far fa-heart LikesIcon-fa-heart"></i>
{% endif %}
</span>
{% endif %}
2.検索結果よりいいね、リツイートの実行
いいね・リツイートを行うために、下記のようにクリックイベントを使用します。(いいねとリツイートの実装はあまり変わらないため、今回はいいねの場合のみ説明します。)検索結果のあるツイートのいいねの状態がONであれば、いいねを外します。いいねの状態がOFFであれば、いいねを行います。
$('.LikesIcon').on('click', function() {
let $btn = $(this);
tweet_id = $btn.attr('id')
// Likeボタンがonクラス持っていたら
if ($btn.hasClass('on')) {
$btn.removeClass('on');
// 白抜きアイコンに戻す
$btn.children("i").attr('class', 'far fa-heart LikesIcon-fa-heart');
$.ajax({
url: 'favorites',
type:'DELETE',
dataType: 'json',
data : {'tweet_id' : tweet_id},
timeout:3000,
}).done(function(data) {
if(data['favorite_count'] != 0)
$btn.children("i").text(data['favorite_count'])
else
$btn.children("i").text("")
})
} else {
$btn.addClass('on');
// ①アイコンを変更する
// far fa-heart(白抜きアイコン)
// ⇒ fas fa-heart(背景色つきアイコン)
// ②アニメーション+アイコン色変更用のheartクラスを付与する
$btn.children("i").attr('class', 'fas fa-heart LikesIcon-fa-heart heart');
$.ajax({
url: 'favorites',
type:'POST',
dataType: 'json',
data : {'tweet_id' : tweet_id},
timeout:3000,
}).done(function(data) {
$btn.children("i").text(data['favorite_count'])
})
}
});
JavaScript側で細々した操作をしたくないので、Ajaxでリクエストを送る先をFlaskにしています。Flaskでは、いいねを行う場合にはPOST favorites/createを実行し、いいねを外す場合にはPOST favorites/destroyを実行します。
@app.route('/favorites',methods=["POST"])
def setFavorites():
twitter = OAuth1Session(settings.CONSUMER_KEY,settings.CONSUMER_SECRET,settings.ACCESS_TOKEN,settings.ACCESS_TOKEN_SECRET)
tweet_id = request.form.get('tweet_id')
endpoint = "https://api.twitter.com/1.1/favorites/create.json?id={}".format(tweet_id)
res = twitter.post(endpoint)
json_res = res.json()
status = getStatus(tweet_id)
return status
@app.route('/favorites',methods=["DELETE"])
def deleteFavorites():
twitter = OAuth1Session(settings.CONSUMER_KEY,settings.CONSUMER_SECRET,settings.ACCESS_TOKEN,settings.ACCESS_TOKEN_SECRET)
tweet_id = request.form.get('tweet_id')
endpoint = "https://api.twitter.com/1.1/favorites/destroy.json?id={}".format(tweet_id)
res = twitter.post(endpoint)
json_res = res.json()
status = getStatus(tweet_id)
return status
Twitterのハートボタンのアニメーションはこちらの記事を参考にさせていただきました。
ソースコード
ソースコードはこちらに配置しています。
https://github.com/cojimaru3/management_tweet_tool
結果
GUIは簡易的なものしか用意できていませんが、要件を満たす振る舞いを実現できました。下記から実行結果をご確認ください。
4.まとめ
今回Twitter APIを使用して、Twitter検索ツールを作成してみました。自動実行だと実装が楽だったのですが、UIを持たせる仕様にしたかったので、それに余計に時間がかかってしまったと思います。また、普段使用しないTwitter APIの仕様を理解し、実装するのは結構難しいと感じました。
現状のツールでは、使用出来る機能が少なかったり、UIなども完全なものではないので今後改善を図りたいと思います。こちらの関連で何か出来上がりましたら、続編という形で掲載しますので、ご期待ください。