Open21

Twitterのいいね欄を取得してリーディングリストを作る

ピン留めされたアイテム
ryopenguinryopenguin

一通りやりたかったことはできた〜

やったこと

  • Twitterのいいね欄のうち、記事(URL)を含むものから最新10件を抽出、Gmailに自動送信するスクリプトを作成
  • このスクリプトをCloud Schedulerで定期実行した
    • 「いいね」から自動でニュースレターが作られ、送られてくるシステムみたいな感じです

やり方

真似するときは以下をすればOK

  1. このフォルダ構成でファイルを作る
- .env.yaml
- .gcloudignore
- main.py
- requirements.txt

yamalにはTwitterAPIのクレデンシャルを書いている。

main.pyはこれです。いろんなコードの継ぎはぎだからきれいにできるところがあるかもしれない。

import requests
import pandas as pd
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
import functions_framework
import os

bearer_token = os.environ.get("bearer_token")

def create_url():
  """
  API エンドポイントになるurlを生成
  """
  tweet_fields = "tweet.fields=created_at"
  # user_id
  id = "1104275583171624960"
  # API request
  url = "https://api.twitter.com/2/users/{}/liked_tweets".format(id)
  return url, tweet_fields

def bearer_oauth(r):
  """
  oauthトークンの生成
  """
  r.headers["Authorization"] = f"Bearer {bearer_token}"
  r.headers["User-Agent"] = "v2LikedTweetsPython"
  return r

def connect_to_endpoint(url, tweet_fields):
  """
  エンドポイントに接続
  """
  response = requests.request(
      "GET", url, auth=bearer_oauth, params=tweet_fields)
  print(response.status_code)
  if response.status_code != 200:
      raise Exception(
          "Request returned an error: {} {}".format(
              response.status_code, response.text
          )
      )
  return response.json()

def df_to_body_text(df):
  """
  データフレームから文面を作成
  """
  body_text = ""
  for d in df["text"]:
    body_text = body_text + d + "\n\n\n"
  return body_text

def send_mail(body_text):
  """
  メールを送信
  """
  # SMTPサーバー名とポート番号指定
  smtp = smtplib.SMTP("smtp.gmail.com",587)

  # サーバーと接続を確立
  smtp.ehlo()
  smtp.starttls()

  my_mail =  os.environ.get("mail_from")
  app_password = os.environ.get("mail_pw")
  smtp.login(my_mail,app_password)

  charset = "iso-2022-jp"
  From = my_mail
  To = os.environ.get("mail_to")
  Kenmei = "オラッ!今週のリーディングリストだぞ!"
  Body = f'最新のお気に入りを送るよ!ちゃんと読めよ!!\n\n{body_text}'

  #メール本文を読み込み
  msg = MIMEMultipart()
  msg.attach(MIMEText(Body))
  msg["Subject"] = Header(Kenmei.encode(charset),charset)

  smtp.sendmail(From,To,msg.as_string())
  smtp.quit()

@functions_framework.http
def trigger(request):
  url, tweet_fields = create_url()
  json_response = connect_to_endpoint(url, tweet_fields)
  df_latest =  pd.DataFrame(json_response["data"])
  df_latest_with_article = df_latest[df_latest["text"].str.contains("https://")][0:11]
  send_mail(df_to_body_text(df_latest_with_article))

  return "SUCCESS"
  1. 以下のデプロイコマンドでCloud functionsにデプロイ(未認証リクエストをOKにしないとcurlとか通らないので注意)
gcloud functions deploy likes-to-newsletter \
--gen2 \
--region=asia-northeast1         \
--runtime=python310 \
--entry-point=trigger \
--trigger-http \
--env-vars-file=.env.yaml \
--allow-unauthenticated
  1. Cloud Schedulerでジョブ設定。これはGUIでつまらずにできた。UNIX CRON記法はじめてみた。
ryopenguinryopenguin

課題

  • Twitterでシェアされた記事に「いいね」してストックするが、検索性が低かったり既読管理に困ったりする
  • 結局記事を読まずに忘れる
  • 時事ネタっぽいモノもあるのでコンスタントに消費できるようにしたい

やりたいこと

  • Twitterでシェアされた記事を「いいね」したら自動でストックされていき、消化できるような環境を作りたい
ryopenguinryopenguin

さらに課題設定

  • 自分はブラウザで色々するのに快適さを覚えるっぽく、アプリで読もうとするとめんどくさくなってしまう
    • NotionやSpreadsheetでリーディングリストを作ったことがあるが、めんどくさくなってメンテしなくなってしまう
    • FeedlyやPocketもちょっとめんどくさい
  • 常用するアプリで言うと、ブラウザ・Slack・メーラーがあるので、これらに小さいバッチで来ると読むかもしれない
    • どかっと来るとめんどくさくて読まない
  • 大体一週間に一回くらいのペースでいくつかの記事がまとまっていると読めそう
    • ALL STAR SAAS FUNDのSAAS WEEKLYくらいの単位で来てくれると嬉しい
ryopenguinryopenguin

自分をユーザーに見立てて分析すると面白いな

課題設定改

記事の取得元 - Twitter

Twitterのいいね機能でニュースを収集することが多いが、検索性に乏しく、どの記事をストックしたかわからなくなる。

記事の取得 - アプリの利用習慣

もともとめんどくさがりで、複数のアプリを日常的に触るわけではない。よく触るブラウザ/Slack/メーラーといった手段で閲覧できないと記事を抽出しても読まなくなりそう。

取得頻度

毎日といった単位でリマインドされたりするのはちょっと鬱陶しく、大体週次で来ないとうんざりして形骸化してしまう。

ryopenguinryopenguin

ゴール設定

  • Twitterで「いいね」で収集した記事を何らかの手段でリスト化
  • メールにその週いいねした物だけを毎週送信
ryopenguinryopenguin

とりあえずPythonでいいねリストを取得して、Spreadsheetに保存してみるか

ryopenguinryopenguin

ツイートのcreated_atはパラメーターで制御できるっぽい

ryopenguinryopenguin

サンプルコードで一瞬でJSON取得できたのでFlattenしてみる

ryopenguinryopenguin

さっきのサンプルコード、Unicordに変換されてしまい日本語が読めなくなるので、以下のコメント部にオプションを加えると良い。

url, tweet_fields = create_url()
json_response = connect_to_endpoint(url, tweet_fields)
# サンプルのコードにensure_ascii=Falseを追加
print(json.dumps(json_response, indent=4, sort_keys=True, ensure_ascii=False))
ryopenguinryopenguin

呼び出したJSONをPandasでDataFrameにして表示までできた。
最新99件までっぽいな

ryopenguinryopenguin

明日以降やる

  • httpsが含まれるアドレスだけ検索する
  • GメールAPI経由でHTMLメールを送信する
  • Cloud functionsで関数化
ryopenguinryopenguin

基本はチュートリアル通りでOK
環境変数の記述はこちら
https://boul.tech/gcf-env-var/

Cloud functions gen2はCloud run上に構築しているのでCloud run APIをオンにしないといけない