はじめまして、jhondaです。
入社したばかりでまだまだ勉強することだらけですが、今回はお仕事以外のテーマで書きたいと思います。
以前 Haskell の勉強を兼ねて、おうちで TwitterのBot を作りました。
Twitter の API を 用いて Haskell でタイムラインの取得とツイートの投稿ができるプログラムを作成するところまでまとめてみます。
準備
- stack (Haskell のビルドツール) を入れる。
-
Twitter のアカウントを作成する。
- ホームタイムライン確認のために適当にフォローしておく。
- Application Management で App を登録し API Key を取得する。以下の4つをあとで使用する。
- Consumer Key
- Consumer Secret
- Access Token
- Access Token Secret
プロジェクトの作成
stack new {プロジェクト名}
でプロジェクトの雛形をつくる。
% stack new twitter-bot # プロジェクト作成
% tree twitter-bot # ディレクトリ構造はこんな感じ
twitter-bot
├── ChangeLog.md
├── LICENSE
├── README.md
├── Setup.hs
├── app
│ └── Main.hs
├── package.yaml
├── src
│ └── Lib.hs
├── stack.yaml
├── test
│ └── Spec.hs
└── twitter-bot.cabal
いくつかパッケージを利用するので、package.yaml
のdependenciesに記述を追加する。
library:
source-dirs: src
dependencies:
- http-conduit # HTTPリクエストを投げるのに使う
- authenticate-oauth # OAuth認証に使う
- text # Haskellでは文字列の扱いがやや面倒なので、楽にする
- aeson # JSONパーザ
executables:
twitter-bot-exe:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- twitter-bot
- text # こっちにも追加
コーディング
まずは Lib.hs に。
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
module Lib
( Tweet (..)
, getHomeTL
, tweet
) where
import Data.Text
import Data.Text.Encoding
import Data.Aeson
import GHC.Generics
import Network.HTTP.Conduit
import Web.Authenticate.OAuth
newtype Tweet = Tweet { text :: Text
} deriving (Show, Generic)
instance FromJSON Tweet
instance ToJSON Tweet
myName = "jhonda_bot" -- botのTwitterアカウント名
myOAuth = newOAuth
{ oauthServerName = "api.twitter.com"
, oauthConsumerKey = "your consumer key" -- https://apps.twitter.com/ で取得したやつ
, oauthConsumerSecret = "your consumer secret" -- https://apps.twitter.com/ で取得したやつ
}
myCredential = newCredential
"your access token" -- https://apps.twitter.com/ で取得したやつ
"your access token secret" -- https://apps.twitter.com/ で取得したやつ
getHomeTL :: IO (Either String [Tweet])
getHomeTL = do
response <- do
req <-
parseRequest
$ "https://api.twitter.com/1.1/statuses/home_timeline.json?screen_name="
++ myName
signedReq <- signOAuth myOAuth myCredential req
manager <- newManager tlsManagerSettings
httpLbs signedReq manager
return $ eitherDecode $ responseBody response
tweet :: Text -> IO ()
tweet tw = do
req <- parseRequest "https://api.twitter.com/1.1/statuses/update.json"
manager <- newManager tlsManagerSettings
let postReq = urlEncodedBody [("status", encodeUtf8 tw)] req
signedReq <- signOAuth myOAuth myCredential postReq
httpLbs signedReq manager
return ()
Main.hs も書く。
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Lib
import qualified Data.Text.IO as T
main :: IO ()
main = do
-- ツイートを投稿する
tweet "5000兆円欲しい!"
-- とりあえずホームタイムラインの最新10件を表示する
homeTL <- getHomeTL
case homeTL of
Left err -> error err
Right tl -> mapM_ (T.putStrLn . text) $ take 10 tl
実行
% stack build # ビルドする
% stack exec twitter-bot-exe # 実行する
これで "5000兆円欲しい!" のツイートとホームタイムラインの最新10件が出力されるはずです。
5000兆円欲しい!
— ぼっと (@jhonda_bot) December 15, 2017
最後に
これでHaskellでツイートの取得と投稿ができるようになりました。
ここまでできれば、ツイートを拾って加工して投稿する、という風にしてcronとかで定期実行させてやればBotらしくすることもできると思います。