チュートリアル

ツイート検索APIを使ってニューヨークの駐車問題を解決した方法

筆者: Jessica Garson

私はニューヨーク市で車を所有しているため、私の車は市の片側路上駐車規制の対象となります。つまり、ほぼ毎晩、近所で行われる早朝の街路清掃の前に車を移動する必要があります。私は寝る前に車を移動することを夜の習慣にしていました。習慣になりすぎて、必要のない日に車を移動させることもよくあります。休日や悪天候の日は片側路上駐車が中止されることが多いので、1日1回と緊急時に投稿するためのTwitterユーザー名@NYCASPを作りました。

問題を解決するために、TwitterデータとTwilioを使用しました。車を移動する必要がないときにテキストメッセージが届くようにしました。Python用のツイート検索ラッパーを使用して、前述のTwitterユーザー名とTwilioからデータを取得したため、車を移動する必要がないときにテキストメッセージが届くようになりました。ツイートに「suspended」と「tomorrow」という単語が出てくるかどうかを確認し、これらの条件が満たされた場合にテキストメッセージを私宛に配信するスクリプトを作成しました。このチュートリアルでは、私がどのようにしてこのソリューションを作成できたかを説明します。

要件セットの取得

Python 3.6を使用してコードを記述しました。このバージョンも使用することをお勧めします。pipを使用するために、まずpipをインストールする必要があります。このチュートリアルでは、Atomを使用します。コマンドラインツールがインストールされていることを確認してください。

また、コマンドラインで次のコマンドを実行して、正しい依存関係が設定されていることを確認する必要があります。

pip install pandas
pip install twilio
pip install searchtweets

では、コマンドラインでこのプロジェクト用に新しいディレクトリを作成し、移動しましょう。

mkdir parking
cd parking

Jupyter Notebookの設定

Jupyter Notebookを使用してコードを記述したので、インタラクティブな方法でデータを操作できました。自分が探しているツイートを確認できるようにするため、このプロジェクトでは重要なことでした。JupyterがプリインストールされているPythonのAnacondaディストリビューションを使用するか、次の構文を使用します。

pip install jupyter

Jupyterをインストールしたら、コマンドラインに次のように入力してNotebookを実行します。

jupyter notebook

Jupyter Notebookを停止する必要がある場合は、いつでもctrl+cを押して停止できます。

設定が正しく行われていれば、ディレクトリの内容がブラウザーに表示されるはずです。右隅にあるnewと表示されている場所をクリックします。そこから、ドロップダウンオプションのPython 3と表示されている場所をクリックして、Notebookを起動します。起動したら、untitledと表示されている場所をクリックして、Notebookの名前をparkingに変更します。

Twilioへの接続設定

Twilioに接続できるように、スクリプトを作成する必要があります。これを行うには、Twilioアカウントが必要です。詳細については、Twilioの入門ドキュメントを参照してください。Twilioに接続するためのスクリプトを作成します。作業中のディレクトリを開きましょう。

atom .

また、Twilioアカウントの環境変数を設定する必要があります。環境変数は、Twilioアカウントを作成するとコンソールに表示されます。

export 'TWILIO_ACCOUNT_SID'='xxxxxxxxxxxxxxxxxxx'
export 'TWILIO_AUTH_TOKEN'='xxxxxxxxxxxxxxxxxxxxxxx'
export 'TWILIO_PHONE_NUMBER'='xxxxxxxxxxx'
export 'CELL_PHONE_NUMBER'='xxxxxxxxxxx'

環境変数として電話番号を追加する場合は、国コード、市外局番、電話番号を1つの文字列にまとめる必要があります。たとえば、電話番号が(555)555-5555で米国にいる場合、電話番号変数の文字列は'15555555555'になります。

ここから、twilio_connect_demo.pyというファイルを追加します。

import os
from twilio.rest import Client

ここで、Twilio APIに接続するための関数を記述します。

def twilio_connect():
account_sid = os.environ.get('TWILIO_ACCOUNT_SID')
auth_token = os.environ.get('TWILIO_AUTH_TOKEN')
client = Client(account_sid, auth_token)
return client

ここで、テキストメッセージを送信するために、別の関数(python def send_message(client))を作成します。

python
def send_message(client):
return client.messages.create(from_=os.environ.get('TWILIO_PHONE_NUMBER'),
to=os.environ.get('CELL_PHONE_NUMBER'),
body="You don't have to move your car tonight.Enjoy your night!")

これで、テキストメッセージを送信するスクリプトが完成しました。これは、このチュートリアルの後半で役立ちます。

必要なものをインポート

Notebook内の最初のセルで、使用するライブラリをインポートする必要があります。datetimeを使用します。これはPython標準ライブラリの一部で、日付を操作して検索を実行できます。また、データを取得してデータフレームに変換するPandasも使用する必要があります。ツイート検索APIを使用するために、検索ツイートのPythonラッパーをインポートします。このライブラリから、ResultStreamgen_rule_playloadload_credentials関数が必要になります。また、後ほどコードでテキストメッセージを送信するために、先ほど作成したスクリプトの2つの関数をインポートします。

python
import datetime
import pandas as pd
from searchtweets import ResultStream, gen_rule_payload, load_credentials

from twilio_connect_demo import twilio_connect, send_message

このコードを実行するには、再生ボタンを押すか、キーボードショートカット(shift-enter)を使用します。

Twitter APIへの接続

APIに接続できるTwitterアプリを作成する必要があります。その前に、承認された開発者アカウントが必要になります。初期設定が完了したら、開発者アカウントを作成する必要があります。こちらで開発者アカウントに申し込むことができます。

アカウントが承認されたら、アプリを作成します。次に、そのアプリをツイート検索用に設定します。30日環境用に設定し、開発環境のラベル名を設定します。

初期設定が完了したら、TwitterアプリからコンシューマーAPIキーとAPIシークレットキーを探す必要があります。設定からキーを見つけるための詳細については、関連するドキュメントを参照してください。

Atomでは、アプリキーとシークレットを含む新しいファイルを追加する必要があります。以下を含むsecret.yamlというファイルを作成してみましょう。

search_tweets_api:
account_type: premium
endpoint: https://api.x.com/1.1/tweets/search/30day/env_name.json
consumer_key: xxxxxxxxxxxxxxxxxxx
consumer_secret: xxxxxxxxxxxxxxxxxxx

エンドポイントのenv_nameは、developer.twitter.comで作成した開発環境の名前です。これを自分の開発環境の名前に変更する必要があります。

GitHubにプッシュする前に、このファイルを.gitignoreに追加しておきましょう。gitignoreファイルの使用方法の詳細については、こちらのページを参照してください。トークンを安全に保つためのガイドも参照してください。

Twitterデータの操作

Jupyter Notebookを実行しているブラウザーに戻ると、search_argsという変数を作成して、Twitter APIに接続するための認証情報を読み込むことができます。

search_args = load_credentials(filename="secret.yaml",
yaml_key="search_tweets_api",
env_overwrite=False)

日付を入力する必要がないように検索する日付を動的にするため、変数をいくつか作成する必要があります。まず、先ほどインポートしたdatetimeライブラリから今日の日付を取得するtodayという変数を作成してみましょう。

today = datetime.date.today()
print(today)

このコード行を実行すると、今日の日付を取得できます。今日から30日前の開始日を取得するために、開始日という変数を作成します。これには今日の日付を取得し、datetimeライブラリに内蔵されているtimedeltaメソッドを使用して30日を差し引きます。

start_date = today + datetime.timedelta(-30)
print(start_date)

これを実行すると、今日から30日前の開始日を取得できます。これで、ツイート検索のPythonラッパーからインポートしたgen_rule_payloadに渡す日付が手に入りました。このメソッドを使用すると、Twitterユーザー名@NYCASPから過去30日間のデータを取得できるルールを作成できます。

rule = gen_rule_payload("from:NYCASP",
from_date=str(start_date),
to_date=str(today),
results_per_call=500,
) print(rule)

このコード行を実行した後、PostmanInsomniaなどのRESTクライアントのボディに貼り付けて、事前にデータを表示できるルールを取得できます。

{"query": "from:NYCASP", "maxResults":500, "toDate":"201811060000", "fromDate":"201810070000"}

次に、ツイートの結果ストリームを作成するため、rs(ResultStreamの略)という変数を作成しましょう。これを行うには、先ほど作成したルールを認証情報とその他のパラメーターとともにこの変数に渡します。

rs = ResultStream(rule_payload=rule,
max_results=500,
max_pages=1,
**search_args)

print(rs)

rsという変数を出力すると、渡した情報を確認できます。次のように出力されます。

ResultStream:
{
"username": null,
"endpoint": "https://api.x.com/1.1/tweets/search/30day/env_name.json",
"rule_payload": {
"query": "from:NYCASP",
"maxResults":500,
"toDate":"201811060000",
"fromDate":"201810070000"
},
"tweetify": true,
"max_results":500
}

rs.stream()属性を使用して結果のストリームをtweetsという変数に渡すことができます。

tweets = rs.stream()

ここから結果ストリームをリストに変換できるので、このデータはより扱いやすくなります。ここで、取得したツイートが見られるようにます。リストの内包表記を使用して最初の5行を出力し、作業が正しく進んでいることを確認しましょう。

list_tweets = list(tweets)
[print(tweet.all_text, end=' ') for tweet in list_tweets[0:5]] ;

このコードを実行すると、次のように出力されます。

#NYCASP rules will be suspended tomorrow, Wednesday, November 7 for Diwali.Parking meters will be in effect.

#NYCASP rules are suspended today, November 6 for Election Day.Parking meters are in effect.

#NYCASP rules will be suspended tomorrow, Tuesday, November 6 for Election Day.Parking meters will be in effect.

#NYCASP rules are in effect today, November 5.

#NYCASP rules will be in effect tomorrow, Monday, November 5.

 

これでデータが正しく受信されていることがわかったので、日付用とツイートテキスト用の2つのリストを作成します。空のリストを2つ作成し、forループを使用してデータを反復処理します。

tweet_text = []
tweet_date = []


for tweet in list_tweets:
tweet_text.append(tweet['text'] )
tweet_date.append(tweet['created_at'])

ここで、Pandasを使用して、これら2つの列で構成されるデータフレームを作成します。

df = pd.DataFrame({'tweet':tweet_text, 'date':tweet_date})

head属性を使用して、データフレームの最初の5行を確認できます。

df.head()

次のように表示されます。

  ツイート 日付
0 #NYCASP rules will be in effect tomorrow, Mond... Sun Oct 21 20:00:34 +0000 2018
1 #NYCASP rules are in effect today, October 20. Sun Oct 20 11:30:14 +0000 2018
2 #NYCASP rules will be in effect tomorrow, Satu... Fri Oct 19 20:01:14 +0000 2018
3 #NYCASP rules are in effect today, October 19. Fri Oct 19 11:30:28 +0000 2018
4 #NYCASP rules will be in effect tomorrow, Fri... Thu Oct 18 20:01:06 +0000 2018

ツイートの完全なリストを表示したい場合は、次の構文を使用します。

df

メッセージの送信

これで、Twitterのデータが正しい形になりました。正しい条件を満たしている場合にメッセージを送信するように設定します。まず、Twilioに接続するためのclientという変数を作成する必要があります。

client = twilio_connect()

ここから、最後のツイートに「suspended」と「tomorrow」という単語が出てきた場合に、テキストメッセージを送信するロジックを設定します。

if 'suspended' in df['tweet'].values[0] :
if 'tomorrow' in df['tweet'].values[0]:
send_message(client=client)
print('text sent')
else:
print('suspended but not tomorrow, no text sent')
else:
print('not suspended, no text sent')

このようにすると、明日の片側路上駐車規制が中止されるかどうかに応じて、対応する出力メッセージを受け取れます。これにより、必要な場合はコマンドラインからデバッグできます。

最後のツイートに「suspended」と「tomorrow」という単語が出てきた場合、以下のようなテキストメッセージを受け取ります。

このスクリプトを.pyファイルとしてダウンロードするには、右隅にファイルと表示されている場所をクリックし、[download as] オプションを選択します。そこからフォーマットを選択するように求められます。必ずPythonを選択してください。

デプロイ

現在のところ、サーバーにデプロイしない限り、このテキストメッセージが届くのはこのときだけです。車を移動する必要がないときにテキストメッセージを受け取りたい場合は、cronジョブを使うとサーバーでこのスクリプトが毎日実行されるように設定できます。私は、このスクリプトが毎日午後7時30分に実行されるように設定しています。

次の手順

完全なコードはこちらを参照してください。ロンドンオフィスにいる同僚が、このコードをこのユーザー名で簡単に応用して、Oxford Tubeで遅延が発生したことを確認するようにできたと教えてくれました。他の人と話したときは、このプロジェクトは車を移動する必要がないときではなく、車を移動する必要があるときに教えてくれる方が理にかなっているかもしれないと言っていました。コードにいくつかの変更を加えれば、簡単に実現できます。現状では、このコードは他の同様のアイデアを構築するためのテンプレートになるかもしれません。


これが何かを構築するきっかけになった場合は、フォーラムでお知らせいただくか、@TwitterDevでツイートしてください。

ソリューション作成の準備が整った方は

開発者アクセスに申し込んで利用を開始しましょう