作ったもの
特定のTwitterアカウントをRSSリーダBot化するLambdaファンクションを作ってみました。CDKで構成を管理&デプロイします。
仕組み
- AWS LambdaでRSSフィードを読み込み、ツイートします
- CloudWatch Eventsで定期実行します
- RSSフィードのURLはLambdaファンクションのコードで管理します(他に手軽な方法が思いつかなかった)
準備
Twitterアカウントを準備する
Botとするアカウントを準備し、Developer Portalで以下のキーを取得します。
取得には電話番号の登録や、メールの返信等が必要なようです。
- consumer_key
- consumer_secret
- access_token
- access_token_secret
RSSフィードを読み込みツイートするRubyスクリプト
全体のコードはこちらのリポジトリに置いていますが、ポイントだけ抜粋します。
RSSの読み込み
RSSの読み込みには以下のライブラリを使います。
Ruby3以上ではGemとしてのインストールが必要だったので、Gemfileに gem "rss"
を指定して bundle install
します。
::RSS::Parser.pars
で読み込むと形式によってオブジェクトの種類が変わるようですので、形式に合った方法でタイトルやURLを取得します。
rss = ::RSS::Parser.parse(@url)
if rss.instance_of?(::RSS::RDF)
# RSS1.0用の処理
elsif rss.instance_of?(::RSS::Rss)
# RSS2.0用の処理
elsif rss.instance_of?(::RSS::Atom::Feed)
# ATOM用の処理
end
RSS をパースしたい場合は RSS::Parser クラスを使います。 RSS::Parser.parse は String の RSSを パースします(使用するXMLパーサによっては File や IO オブジェクトなどでもパース可能です)。
RSS 1.0をパースした場合は RSS::RDF オブジェクト
RSS 0.9x/2.0をパースした場合は RSS::Rss オブジェクト
Atom をパースした場合は RSS::Atom::Feed オブジェクト
をそれぞれ返します。
ツイート数&間隔
投稿は300投稿/3時間というレートリミットがあるため、リミットをオーバーしない&1度のLambdaファンクション内の実行で完結する範囲でツイート間隔を最大ツイート数を調整します。
今回は1時間に1実行のため、100回までは投稿できそうですが、余裕を見て1度に80回までの投稿上限としてみています。
CDKでデプロイ
CDKでLambdaファンクションをデプロイします。以下のような仕様を満たすよう構成を管理します。
- Lambdaファンクションのタイムアウト: 15分
- 1時間毎に実行
- Twitter関連キーをLambdaファンクションの環境変数に設定
- デプロイする実行環境で環境変数にあらかじめ設定しておくこと
export class CdkStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const lambdaFn = new lambda.Function(this, 'Lambda', {
runtime: lambda.Runtime.RUBY_2_7,
handler: 'handler.handler',
functionName: "rss2witter",
code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/')),
timeout: Duration.seconds(60*15),
environment: {
TWITTER_CUNSUMER_KEY: process.env.TWITTER_CUNSUMER_KEY || "",
TWITTER_CONSUMBER_SECRET: process.env.TWITTER_CONSUMBER_SECRET || "",
TWITTER_ACCESS_TOKEN: process.env.TWITTER_ACCESS_TOKEN || "",
TWITTER_ACCESS_TOKEN_SECRET: process.env.TWITTER_ACCESS_TOKEN_SECRET || "",
},
});
const rule = new events.Rule(this, 'Rule', {
schedule: events.Schedule.expression('rate(1 hour)')
});
rule.addTarget(new targets.LambdaFunction(lambdaFn));
参考