Twitter BOT の作成 第3回 — WordPress RSS の投稿情報をツイートする

2015/02/15DevelopmentTwitter

今回は、WordPress の RSS を読み込み、投稿情報をツイートします。

先日から運用している WordPress の RSS から記事を取得してツイートする BOT を作ります。Azure Web サイトの Web ジョブを使います。

  • Visual Basic コンソールアプリ(LinqToTwitter 利用)
  • Microsoft Azure スケジューラによるジョブの実行

というニッチな内容です。無償の Visual Studio Express 2013 for Desktop で作れます。Azure は……。

WordPress のプラグインや Web サービスなどで良いものが見つからなかったので、手短に作ってみました。

目次

  1. BOT 用 Twitter アプリの作成
  2. ツイート コンソールアプリの作成
  3. WordPress RSS から投稿のツイート(今回)
  4. Azure スケジューラによるジョブの実行

WordPress の RSS フィードの構造

WordPress の出力する RSS フィードの URL は当サイトの場合、https://pronama.jp/feed/ です。フィードは、次のような構造になっています(不要な部分は省略しています)。


<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" … >
<channel>
<item>
<title>[Web Comic] 情報処理研究会漫画 すぱこー Ver. 14</title>
<link>http://pronama.azurewebsites.net/2014/07/22/web-comic-spaco-14/</link>
<comments>http://pronama.azurewebsites.net/2014/07/22/web-comic-spaco-14/#comments</comments>
<pubDate>Tue, 22 Jul 2014 13:50:22 +0000</pubDate>
<dc:creator><![CDATA[jz5]]></dc:creator>
<category><![CDATA[Pronama-chan]]></category>
<category><![CDATA[Web Comic]]></category>
<guid isPermaLink="false">http://pronama.azurewebsites.net/?p=48991</guid>
<description><![CDATA[…]]></description>
<content:encoded><![CDATA[…]]></content:encoded>
<wfw:commentRss>http://pronama.azurewebsites.net/2014/07/22/web-comic-spaco-14/feed/</wfw:commentRss>
<slash:comments>0</slash:comments>
</item>
<item>…</item>
</channel>
</rss>

view raw

feed.xml

hosted with ❤ by GitHub

ポイントとして、

  • 投稿は、<item> 要素ひとつで表されていて、複数個ある
  • タイトルは、<title> 要素
  • パーマリンクは、<link> 要素 もしくは、<guid> 要素(?=xxx 形式)
  • 日付は <pubDate> 要素
  • カテゴリーとタグは、どちらも <category> 要素(複数個)になっている

……という感じです。

今回は、各 <item> 内の <title> と <guid> の値を使います。?=xxx 形式の URL の方が短いので、こちらを使います。

追記: ツイート中の URL は、一定の文字数としてカウントされます。何文字分として扱われるかは、GET help/configuration | Twitter Developers の short_url_length と short_url_length_https の値からわかります。

WordPress の RSS フィードを読み込む

コードから RSS フィードを読み込みます。Visual Basic の場合はこんな感じ。


Dim items = New List(Of String)
Dim d = XDocument.Load("http://pronama.azurewebsites.net/feed/")
For Each i In d…<item>
Dim msg = String.Format("old post: {0} {1}", i.<title>.Value, i.<guid>.Value)
items.Add(msg)
Next

view raw

gistfile1.vb

hosted with ❤ by GitHub

<item> の数だけ繰り返し、<title>, <guid> の値から「old post: タイトル URL」の形式の文字列を作り、List に追加しています。

List から 1個だけランダムに返す関数にします。


Private Function GetMessage() As String
Dim items = New List(Of String)
Dim d = XDocument.Load("http://pronama.azurewebsites.net/feed/")
For Each i In d…<item>
Dim msg = String.Format("old post: {0} {1}", i.<title>.Value, i.<guid>.Value)
items.Add(msg)
Next
Dim r = New Random
Return items(r.Next(items.Count))
End Function

view raw

gistfile1.vb

hosted with ❤ by GitHub

以上で、RSS フィードを読み取り、ツイートメッセージを作る関数ができました。

ツイート部分の修正

前回 の Main 部分を、今回の GetMessage 関数を利用した形に修正します。また Try-Catch を付け例外処理もしています(単にコンソールにメッセージを出力しているだけですが)。


Sub Main()
Dim t = Task.Factory.StartNew(
Async Function()
Dim msg = GetMessage()
Await Tweet(msg)
End Function).Unwrap
Try
t.Wait()
Catch aEx As AggregateException
For Each e In aEx.InnerExceptions
Console.WriteLine(e.Message)
Next
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End Sub

view raw

Module.vb

hosted with ❤ by GitHub

以上で、1度起動すると、WordPress の投稿をランダムに選んで、1回ツイートして終了するプログラムの完成です。

プログラムで留意していないこと

今回作成したプログラムは、定期的に実行し、WordPress の投稿をツイートするために使います。その際、考慮していないことがいろいろあります。改良の参考にしてください。

同一のツイート

2回以上実行して、ランダムに選択した投稿が同じ場合、重複ツイートとなり、ツイートできない可能性があります。

今回は、重複したらあきらめる運用とします。プログラムの修正案としては、日付やランダムな数値をメッセージに付けたし重複しないメッセージの作成などがあります。

140 文字より長いツイート

タイトルと URL の長さが140文字より長い場合、ツイートできません。

今回は、長いタイトルを投稿しないという前提とします。プログラムの修正案は、タイトルが長い場合、メッセージが140文字に収まるよう、短く省略する方法があります。

その他のエラー

WordPress のフィード読み込み時や、ツイート時のエラーは何も考慮していません。ツイート時に何かしらエラーが発生した場合は、リトライ等せず、その回はあきらめる運用とします。

ツイートしたくない投稿の除外

今回、RSS フィードに含まれるすべての投稿が、ツイート対象です。より細かな動作ができる BOT のためには、ツイートから除外したい投稿(たとえばイベント告知で期限切れなど)は、カテゴリーやタグで判別したり、別途 除外用のリストを作成して対応が必要です。

古い投稿のツイート

RSS フィードには最新の投稿しか含まれていないため、古い投稿をツイートできません。古い投稿に対応するには、フィード内容を保存しておくなどの対応が必要です。

今回はここまでです。第4回 へ。

DevelopmentTwitter

Posted by jz5