TwitterSearchAPIを使用して、グーグルドライブにTweetを毎日貯める方法

TwitterAPIを利用し、特定のキーワードを含むTweetを毎日、自動取得するコードをGASで実装してみました！

#背景
内定先が本来有料の動画アーカイブを無料公開していたので、その効果どんなもんなのかなぁー→Twitterから分析してみよう！と思い、、
まずはサービス名を含むTweetを取得してみました！

最初はPythonで書いてGCPで回してBigqueryにと思ってたんですが、
①個人用でデータが大きくならないこと
②研究室のGoogleアカウントが有料で容量の制限がないこと
***③お金がかからないこと***
と何個か理由があり、GCPでいいやとなったのでそれで書きました！
（pythonで書いた時間、、、）

内定先のschooのキャンペーン
https://schoo.jp/news/2020/2020-12-30
(どうせなのでリンク踏んで会員登録ぐらいしてやってください)

#やりたいこと
①Twitterから特定のキーワードを含むTweetを取得
②毎日クローリング
③グーグルドライブ上にJsonで保存
(またどこかの記事で)→④colabで分析

#まずはTwitterAPIの取得
これはいっぱい記事あるので割愛します。
以下の記事なんか良さそう？
https://www.itti.jp/web-direction/how-to-apply-for-twitter-api/

自分の場合は研究目的を指定して、やりたい研究(DeepL製の英語)を添えたら、日本語でメールが帰ってきたのでそれに何通か応答したら1,2日で権限もらえました。

#GoogleDriveでの操作
GoogleDrive上でスクリプトファイルを作成
グーグルドライブで、
新規>その他→GoogleAppsScript
を選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688794/7b67515e-a08b-eb04-cd3e-45e2f995f025.png)

ここに色々書いていくだけです！

#Twitter SearchAPIについて
今回は特定後の検索がしたかったので、StandardSearchAPIを利用しました。
今回使う分くらいですが引数はこんな感じ

|   param |出来ること                                | 補足                                                                     | 
| ----- | ------------------------------ | -------------------------------------------------------------------- | 
| q     | 検索したいキーワードを           | 今回はここで時間指定してる                                           | 
| lang  | 言語                           | 今回は国内向けサービスなのでjaで                                     | 
| count | 取得するTweetの個数(100個まで) | 少なすぎる、、、max_idとかで頑張ればいっぱい取れそうだけど今回は妥協 | 
| result_type| Tweetのソート方法(popular,recent,mixed)            | popularにすると空配列が返ってくるのでmixedにしました               | 
| until | 取得するTweetの期限            | リファレンスを見ると、untilはあるのにsinceがない、、、               | 

で、今回はqで取得したいTweetの期限を設定しています。というのもリファレンスを見るとuntilはあるのにsinceはsinceIDになってるんですよね。恐らく100件以上のデータを集めたいってなったらこれのほうが都合がいいと思うんですが、今回はめんどくさかったので妥協。
またsinceってパラメーターも使えるっぽいんですが、まぁqで設定した後に知ったのでいいかなと。

難しいことゼロなので詳しくはここらへん見てください。
SearchAPIのリファレンス
https://developer.twitter.com/en/docs/twitter-api/v1/tweets/search/api-reference/get-search-tweets

Twitter検索コマンド
https://mag.app-liv.jp/archive/81735/

#コード
さてコードについて紹介していきます。
最後に全体のコードも載せてるので、動かすだけならそちらを。
(実は拾い物のコードを結構使っているんですが、取得場所忘れました、、qiitaだったはず)

まずは取得したTwitterAPIのkeyを保存しておきましょー

```key.js
const consumer_key = '****************';
const consumer_secret = '****************';
const access_token_key = '****************'
const access_token_secret = '****************'
```

今回は毎日、一日前のTweetを取得することにしました。
昨日と今日の日付をyyyy-MM-ddの形式でyesterday,todayに格納。
それをテキスト形式にしたものが、since_date,until_dateになります！
(検索コマンドでsince,untilを制限するために文字にして、タイムゾーンを日本時間にしてあります)

```date.js
var yesterdayObj = new Date()
yesterdayObj.setDate(yesterdayObj.getDate() - 1);
yesterday = Utilities.formatDate(yesterdayObj,'JST','yyyy-MM-dd');
var todayObj = new Date()
today = Utilities.formatDate(todayObj,'JST','yyyy-MM-dd');
const since_date = yesterday + 'T09:00:00Z'
const until_date = today + 'T09:00:00Z'
```

基本的に以下のFuncでほぼ全ての処理が回っています。
TwitterAPIのOAuthを行って、API用のパラメータを指定して、呼び出すってだけですね。
呼び出し用のqについてだけ説明します。

今回はschooというサービスに関するTweetを抽出したかったのでqは「schoo」です。
ただschoolという名詞も呼び出されそうなので、検索コマンドを使ってschoolを含まず、schooを含むものを対象としました。
ここは個別違うと思うので、よしなに変更してください。


```apiFunc.js
function searchTweetsApps() {
  //APIのOAuth
  var blob = Utilities.newBlob(consumer_key + ':' + consumer_secret);
  var credential = Utilities.base64Encode(blob.getBytes());
  var formData = {
    'grant_type': 'client_credentials'
  };
  var basic_auth_header = {
    'Authorization': 'Basic ' + credential
  };
  var options = {
    'method': 'post',
    'contentType': 'application/x-www-form-urlencoded;charset=UTF-8',
    'headers':  basic_auth_header,
    'payload': formData,
  };
  var oauth2_response = UrlFetchApp.fetch('https://api.twitter.com/oauth2/token', options);  
  var bearer_token = JSON.parse(oauth2_response).access_token; 

  //KWの設定
  var search_keyword = 'schoo -school since:' + since_date +' until:' + until_date;
  var bearer_auth_header = {
    'Authorization': 'Bearer ' + bearer_token
  };
  //APIの呼び出し
  var search_response = UrlFetchApp.fetch(
    'https://api.twitter.com/1.1/search/tweets.json?q=' + search_keyword + '&lang=ja&result_type=mixed&count=100',
    { 'headers': bearer_auth_header});
  result = JSON.parse(search_response);
  
  //jsonに変換してグーグルドライブに保存
  output = JSON.stringify(result['statuses'])
  create_file(output)
}
```

あとはjsonとして保存する用の設定です。
getFolderByIDではグーグルドライブの保存先ファイルIDを記載すると、そこに保存してくれます。
(正直blobの処理の理解完璧ではなく、体感時間ここが一番でした、、)

```toJson.js
function create_file(json) {
  var content_type = "text/plain";
  var file_name = since_date;
  var blob = Utilities.newBlob("", content_type, file_name);
  var file = blob.setDataFromString(json, "UTF-8");
  var folder = DriveApp.getFolderById("グーグルドライブの保存先ファイルID");
  folder.createFile(file);
}
```

#あとはトリガーの設定をするだけ！
あとは毎日動かすようにトリガーの設定をするだけです！
無料で24時間何時でも回せる、便利な世の中ですねぇ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688794/2957ca2b-1771-bc08-ed47-2b4d3cbee1b0.png)

#最後に
色々書いてきましたが、まぁ難しいことは特に有りませんね。
何個か記事漁ればできます。
とはいえ、何個か漁るのもだるいのでここにまとめておいたって感じです。

さて背景として内定先の分析としましたが、個人的にはテキスト分析について詳しくなりたいなと思って初めたことだったりします。
そういう意味でここからが本番。色々やって、それについても記事にするつもりなので楽しみにしていてください！
ちなみにある会社で2月からTwitterテキスト分析→マーケティングに活かす。みたいなのをやることになっているので、色々調べながらがんばります！

#余談ですが、、、
内定先のSchoo,Qiitaの記事が2年前とかそんな感じ、、、
別の場所でTechBlogやってるのかな、どうなんだろう。
データドリブンなイメージはそんなに無いので、色々動いていきたいなって感じです！
特にデータ分析に強い訳ではない事業会社に入った(マーケ*)データサイエンス希望がどうなるのか、見守ってください...!

#AllCode

```all.js
const consumer_key = '****************';
const consumer_secret = '****************';
const access_token_key = '****************'
const access_token_secret = '****************'

var yesterdayObj = new Date()
yesterdayObj.setDate(yesterdayObj.getDate() - 1);
yesterday = Utilities.formatDate(yesterdayObj,'JST','yyyy-MM-dd');
var todayObj = new Date()
today = Utilities.formatDate(todayObj,'JST','yyyy-MM-dd');
const since_date = yesterday + 'T09:00:00Z'
const until_date = today + 'T09:00:00Z'

function searchTweetsApps() {
  var blob = Utilities.newBlob(consumer_key + ':' + consumer_secret);
  var credential = Utilities.base64Encode(blob.getBytes());
  var formData = {
    'grant_type': 'client_credentials'
  };
  var basic_auth_header = {
    'Authorization': 'Basic ' + credential
  };
  var options = {
    'method': 'post',
    'contentType': 'application/x-www-form-urlencoded;charset=UTF-8',
    'headers':  basic_auth_header,
    'payload': formData,
  };
  var oauth2_response = UrlFetchApp.fetch('https://api.twitter.com/oauth2/token', options);  
  var bearer_token = JSON.parse(oauth2_response).access_token; 


  var search_keyword = 'schoo -school since:' + since_date +' until:' + until_date;
  Logger.log(search_keyword)

  var bearer_auth_header = {
    'Authorization': 'Bearer ' + bearer_token
  };

  var search_response = UrlFetchApp.fetch(
    'https://api.twitter.com/1.1/search/tweets.json?q=' + search_keyword + '&lang=ja&result_type=mixed&count=100',
    { 'headers': bearer_auth_header});
  result = JSON.parse(search_response);
  output = JSON.stringify(result['statuses'])
  create_file(output)
}

function create_file(json) {
  var content_type = "text/plain";
  var file_name = since_date;
  var blob = Utilities.newBlob("", content_type, file_name);
  var file = blob.setDataFromString(json, "UTF-8");
  var folder = DriveApp.getFolderById("*************************");
  folder.createFile(file);
}
```