LoginSignup
20
23

More than 5 years have passed since last update.

Go言語でTwitter Bot

Last updated at Posted at 2012-11-28

mrjones氏のGoで実装したOAuthライブラリでTwitterAPIを利用するサンプルが公開されていますが、そのままではBotとして利用できないので、ソースを見ながらつぶやきとホームタイムラインが取得できるまでをやってみました。


最初に、ライブラリをインストールします。環境によっては先頭にsudoをつける必要があります。

terminal
go get github.com/mrjones/oauth

OAuthに必要なoauth.Consumerとoauth.AccessTokenを保持するstructと、その生成関数です。

main.go
package main

import (
    "encoding/json"
    "fmt"
    "github.com/mrjones/oauth"
    "io/ioutil"
    "log"
)

type Twitter struct {
    consumer    *oauth.Consumer
    accessToken *oauth.AccessToken
}

func NewTwitter(consumerKey, consumerSecret, accessToken, accessTokenSecret string) *Twitter {
    twitter := new(Twitter)
    twitter.consumer = oauth.NewConsumer(
        consumerKey,
        consumerSecret,
        oauth.ServiceProvider{
            RequestTokenUrl:   "http://api.twitter.com/oauth/request_token",
            AuthorizeTokenUrl: "https://api.twitter.com/oauth/authorize",
            AccessTokenUrl:    "https://api.twitter.com/oauth/access_token",
        })
    twitter.accessToken = &oauth.AccessToken{accessToken, accessTokenSecret}
    return twitter
}

次に、GETとPOSTを行う関数です。関数の最初の行以外は同じコードになっています。
responseを取得し、ioutil.ReadAllで読み込んだ後、jsonデコードを行います。
戻り値として、なんでもあり?のinterface{}を返します。

func (t *Twitter) Get(url string, params map[string]string) (interface{}, error) {
    response, err := t.consumer.Get(url, params, t.accessToken)
    if err != nil {
        return nil, err
    }
    defer response.Body.Close()

    b, err := ioutil.ReadAll(response.Body)
    if err != nil {
        return nil, err
    }

    // decode
    var result interface{}
    err = json.Unmarshal(b, &result)
    return result, err
}

func (t *Twitter) Post(url string, params map[string]string) (interface{}, error) {
    response, err := t.consumer.Post(url, params, t.accessToken)
    /* 以下Getと同じため省略 */
}

やっと、つぶやきます。NewTwitterの引数には各自値を入れて下さい。
twitter.Postの第1引数は、使用するAPIのURL Twitter APIを参照してください
第2引数は、パラメータです。testとつぶやくので、keyにstatus、valueにtestとなっています。

func main() {
    twitter := NewTwitter("CONSUMER_KEY", "CONSUMER_SECRET", "ACCESS_TOKEN", "ACCESS_TOKEN_SECRET")

    // testとつぶやく
    res, err := twitter.Post(
        "https://api.twitter.com/1.1/statuses/update.json", // Resource URL
        map[string]string{"status": "test"})                // Parameters
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(res)
}

最後に、ホームタイムラインを取得します。今回はGet関数を使用します。
第2引数は、何も指定しないので空のmapにしています。
タイムラインの表示では、resをinterface{}の配列である[]interface{}に変換し、forでまわしています。forの中ではさらに、interface{}をmap[string]interface{}に変換した後、textを取り出して表示しています。

func main() {
    twitter := NewTwitter("CONSUMER_KEY", "CONSUMER_SECRET", "ACCESS_TOKEN", "ACCESS_TOKEN_SECRET")

    res, err := twitter.Get(
        "https://api.twitter.com/1.1/statuses/home_timeline.json", // Resource URL
        map[string]string{})                                       // Parameters
    if err != nil {
        log.Fatal(err)
    }

    // タイムラインを表示
    for _, val := range res.([]interface{}) { 
        tweet, _ := val.(map[string]interface{})
        fmt.Println(tweet["text"])
    }
}

JSONをdecodeするときに、あらかじめ定義したstructを渡せば、最後のinterface{}の面倒な処理はいらないのですが、APIごとに結果がことなる場合にそれぞれstructを作るのは大変なのでこのような処理にしました。
interfaceの使い方が間違っていたら、じゃんじゃんツッコミください。

20
23
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
23