Twitter タグの一覧です(14 件)

[Twitter]今まで作成したTwitter botのまとめ

Twitter botをOAuth対応させたついでに今まで作ったbotをまとめておきます。
  • @cookpad_recipe
    • クックパッドの話題のレシピを都度配信しています
  • @keiba_news
    • ラジオNIKKEI競馬実況webのニュースを配信しています
  • @ad_min_kun
    • @ITで連載中の4コマ漫画 がんばれ! アドミンくん の新作を配信します
    • ちなみに絶賛文字化け中です(>_<)現在対応中です。ゴメンナサイ

環境について

  • サーバ
    • Prime Magnate GCD(ドスパラWebのBTOです)
  • OS
    • CentOS5.4
  • その他
    • 上記botはすべてPython2.6で動いています
    • TwitterAPIのPythonラッパーはtweepyを使用しています

[Python]Python製Twitter(Wasser)CUIクライアントをOAuth対応にしてみた

Twitter APIは近い将来BASICによる認証が出来なくなるらしいという話を聞き、重い腰をあげて自分が管理しているBotをOAuth対応すべく勉強を始めました。 今回は勉強ついでに少し寄り道して、色々と参考にさせてもらっているPython製Twitter(Wasser)CUIクライアントを基本ベースにOAuth対応に改造してみました。

オリジナルはこちらで
wassr と Twitter への投稿クライアント(清楚なクライアント) - Djangoへの片思い日記
ブランチされているのはこちらでしょうか
tw2改造した - a2c.get.diary

本当はブランチとかするのがいいと思うのですが、
  • Wasserへの対応を削ってしまっている(自分、Wasserは放置しちゃってます><)
  • TwitterAPIのWrapperをすっかり変えている(tweepyを使用)
  • Sqlite3をつかってin_reply_to_id付きreplyに対応している
などなどからこちらのBlogにあげさせてもらいます。何か問題あれば言ってください。

留意事項

使用方法

  • scriptと同じ場所等にdbを作成します。db名はtwit.dbでtable名はtwitlogです。内容はこんな感じでお願いします。
    $ sqlite3 twit.db
    sqlite> .schema twitlog
    CREATE TABLE twitlog
                    (id INTEGER PRIMARY KEY,
                    date INTEGER,
                    repid INTEGER,
                    screen TEXT, body TEXT);
    sqlite> 
    

  • 使用方法は殆どオリジナルと変更ありません。起動後、取得したい情報のkeyや発言内容を入力してリターンキーを押して下さい
  • in_reply_to_id付きreplyは、replyしたい内容の番号を入力してから @screen_name のように入力します(下図ご参照)

  • 20100209_02


コードはこちらです。自分のコードでsqlite3使ったり、SQL文書いたりしたのは実は今回が初めてです。こうしたほうがいいみたいなことありましたら教えてください><
#!/usr/bin/env python
# coding: utf-8
# thanks yoshiori: http://d.hatena.ne.jp/jYoshiori/20081201/1228123623
# thanks a2c: http://d.hatena.ne.jp/a2c/20081221/1229799599

import readline
from pit import Pit
from datetime import timedelta
import sqlite3

# KeyConfig
getFriendsTimeLineKey = ['friends', 'f']
getRepliesKey = ['res', 'r', '']
sendPostKey = ['post', 'p']
searchKey = ['search', 's']
exitKey = ['x', 'ZZ', 'exit', 'bye']

readline.parse_and_bind('tab: complete')

friends = set()

def complete(text, status):
    results = [x for x in friends if x.startswith(text)] + [None]
    return results[status]

def date_jst(utf_date):
    # UTC -> JST
    d = utf_date + timedelta(hours=9)
    return d

def twitPost(input):
    # Post twitterr
    api.update_status(input)
    print 'update : ' + input

def select_repid(num):
    con = sqlite3.connect(db_name)
    sql = 'SELECT repid FROM twitlog WHERE id = ?'
    stid = con.execute(sql, (num,)).fetchone()[0] 
    con.close()
    return stid
    
def twitRepost(input, stid):
    # Repost twitterr
    api.update_status(input, stid)
    print 'update : ' + input
    
def getReplies(maxid):
    # Get twitter friends Replies
    insert_data(api.mentions(count=maxid))
    con = sqlite3.connect(db_name)
    cur = con.cursor()
    cur.execute('select * from twitlog')

    print '\n\ttwitter replies\t'
    for row in cur:
        print ('%s :%s : %s %s' % (row[0], row[1], row[3], row[4]))
        friends.add(row[3])
    cur.close()
    con.close()

def getFriensTimeLine(maxid):
    # Get FriendsTimeLine
    insert_data(api.friends_timeline(count=maxid))
    con = sqlite3.connect(db_name)
    cur = con.cursor()
    cur.execute('select * from twitlog')

    print '\n  -----  twitter Friends Time Line  -----'
    for row in cur:
        print ('%s :%s : %s %s' % (row[0], row[1], row[3], row[4]))
        friends.add(row[3])
    cur.close()
    con.close()

def twitSearch(word):
    # Twitter Search
    insert_search_data(api.search(word))
    con = sqlite3.connect(db_name)
    cur = con.cursor()
    cur.execute('select * from twitlog')

    print '\n  -----  twitter search  -----'
    for row in cur:
        print ('%s :%s : %s %s' % (row[0], row[1], row[3], row[4]))
        friends.add(row[3])
    cur.close()
    con.close()

def insert_data(api):
    sql = 'insert into twitlog values(null,?,?,?,?)' 
    con = sqlite3.connect(db_name)
    con.execute('delete from twitlog')       
    for data in reversed(api):
        con.execute(sql, (date_jst(data.created_at), data.id, data.user.screen_name, data.text))
    con.commit()
    con.close()

def insert_search_data(api):
    sql = 'insert into twitlog values(null,?,?,?,?)' 
    con = sqlite3.connect(db_name)
    con.execute('delete from twitlog')       
    for data in reversed(api):
        con.execute(sql, (date_jst(data.created_at), data.id, data.from_user, data.text))
    con.commit()
    con.close()

def create_twitdb():
    # DBがぶっ壊れた時用
    db = sqlite3.connect(db_name)
    sql = (
            '''CREATE TABLE twitlog
                (id INTEGER PRIMARY KEY,
                date INTEGER,
                repid INTEGER,
                screen TEXT, body TEXT);'''
          )
    db.execute(sql)
    db.commit()
    db.close()

if __name__ == "__main__":
    db_name = 'twit.db'
   # create_twitdb()
    try:
        import tweepy
    except:
        print "error:\tcan't import tweepy module, you must install the module:\n"
        print "\tto install: 'easy_install tweepy'\n"
        exit()
    # OAuth setting
    consumer_config = Pit.get('twoauth')
    auth = tweepy.OAuthHandler(consumer_config['consumer_key'], consumer_config['consumer_secret'])
    access_config = Pit.get('access_key')
    auth.set_access_token(access_config['access_token'], access_config['access_secret'])

    readline.set_completer(complete)
    prompt = '\n cmd: Friendstimeline[f] Search[s] Post[p] Repost[num + @] Replies[r] Exit[x] \n> '
    maxid = 20
    api = tweepy.API(auth)

    while True:
        all_input = raw_input(prompt)
        input = all_input.split(" ")
        if input[0] != '':
            if input[0] in getFriendsTimeLineKey: 
                getFriensTimeLine(maxid)
                continue
            elif input[0] in sendPostKey:
                twitPost(unicode(' '.join(input[1:]), 'utf-8'))
                continue
            elif input[0].isdigit():
                sid = select_repid(input[0])
                #print sid
                twitRepost(unicode(' '.join(input[1:]), 'utf-8'), sid)
                continue
            elif input[0] in getRepliesKey:
                getReplies(maxid)
                continue
            elif input[0] in searchKey:
                twitSearch(' '.join(input[1:]))
                continue
            elif input[0] in exitKey:
                print 'bye ;-)'
                break
            else:
                twitPost(unicode('%s'%(all_input), 'utf-8'))
                continue
        else: 
            getReplies(maxid)

pit使うとID、パスワードを書き換えてから貼付け...とか考えなくていいのが嬉しいです:)

Twitter公式Widgetがリニューアルしてた

ここ一週間ほど、ブログに貼り付けていたTwitterWidgetがまったく反映しなくてまあツイッターだったら色々事情があるんだろうなくらいに思っていたのですが、どうやらWidgetが新しくなっているようです(いつからだろう?)。どうりで動かないはずです。
http://twitter.com/goodies/widgets
今までは、FlashバージョンとJavascriptバージョンの二種類で自分の発言を表示出来たのですが、今回は自分の発言版はもちろんですが、Search、FavesのWidgetがあります。 favesWidgetがいいなと思ったのですが、残念なことに「ふぁぼり」のようで「ふぁぼられ」ではないようです。 SearchWidgetは自分宛言及の表示など色々使えそうです。
自分が管理しているcookpad_recipeの言及を表示するWigdetはこのようになります。


[Python]ハードディスクの温度を定期的にTwitterにポストする

自宅サーバ(CentOS5.3)は極端に熱のこもる場所に設置してあるわけではないので、廃熱に関してはそこそこ大丈夫だと思っているのだけど、それでもハードディスクとかの温度は心配。そこで会社にいても状況を把握出来るように、4時間おきにハードディスクの温度をTwtterにポストしている。以下備忘録的にまとめてみた。

hddtempのインストール

まずはハードディスクの温度を計測する為にhddtempをインストールする。CentOSの場合はyumでインストール可能。

# yum -y install hddtemp

使用する時は、hddtemp disk名をタイプして実行する

# hddtemp /dev/sda
/dev/sda: WDC WD10EADS-00L5B1: 39°C

hddtempの値を取得してTwitterにポストする

以下ソースコード(Pythonなのに全くインデントしてない><)

#!/usr/bin/env python
# coding: utf-8

import sys
import twitter
from datetime import *

USERNAME = "TWITTER_ACCOUNT"
PASSWORD = "ACCOUNT_PASSWORD"

DATETIME = datetime.now()
TIME_STR = DATETIME.strftime("%I:%M %p")
api = twitter.Api(USERNAME, PASSWORD)

t = sys.stdin.readline()
info = t.rstrip() + " " + "at" + " " +TIME_STR

post = u"%s" % (info)
api.PostUpdate(post)
# print post

Twitterへポストするモジュールはpython-twitterを使用。
注意した点は2つあって、1つは受け取った標準出力に改行がついてきて、そのままではTwitterにうまくポスト出来ないのでrstripしていること。もうひとつは、ポストする内容にその時刻を追加したこと(取得した温度だけをポストする場合、温度が毎回同じだとポストする内容が一緒になってしまい、Twiiter仕様上無効ポストになってしまう)

シェルスクリプトの作成

#!/bin/sh
export LANG=ja_JP.utf-8
/usr/sbin/hddtemp /dev/sda | /usr/local/bin/python /usr/local/bin/hdd_info.py
exit

ここでは、/dev/sdaの温度を取得し、先ほどのスクリプト(hdd_info.py)へパイプで繋いでいる。ディスク名は環境によって違うと思うので置き換えて下さい。最初どうしても°CがTwitterにポストされず困っていたのだけど、export LANG=ja_JP.utf-8を記述することでポスト出来るようになった(katsu2000xさんthanks!)
このシェルスクリプトをCronで定時実行させるとこのようになる。Twitterアカウントは本人のアカウントを使用するとTLを汚すような気がして、それ用のアカウントを作った。

20090904_01

[2009年9月13日追記]
twitterでフォローしているmagicalhatさんが、perlでさくっと書いてくれてトラバ貰いました。勉強になります!
[追記ここまで]


[Python]Twitter版LogWatchのようなもの

GW期間に3連休(年に2回あるかどうか!というくらい貴重)をもらったので、Pythonのお勉強を兼ねてTwitter版LogWatchのようなものを作ってみました。

20090505_02


24時過ぎとかにcronで実行させると、FriendsとFollowersそれぞれのリストを前日に保存しておいたリストと照合し、追加した(された)および削除した(された)Friends/FollowersをリストアップしてGmailで自分宛に送信します。Twitter APIを扱うモジュールはPython-twitterというものを使用していますが、前回と同じく、easy_installで入るものでなくtrunkにあるものを使用しています。

作ってみて色々思ったこと

  • 結構行数が増えてきたので、Classにまとめようと思ったけど、次回チャレンジする
  • Pythonで書いている人は文字列囲むのにダブルクォーテーションとシングルクォーテーションどちらなのか。もしくは使い分けしているのか
  • 変数命名が納得いかない。どうしたものか。
  • 自分で書いた英語がそもそも怪しい><
  • コードを書き始めてから、このblogを書き始めるまで13時間くらいかかった。半年前だったら1週間以上かかっただろう。この進歩(牛歩だが)が嬉しい

コードはこちら。Python2.6(MacOSX dmg)で動作確認は取れています。但しcronでの運用はまだ行っていません(先日セッティングした自鯖に入れるつもり)。

#!/usr/bin/env python
# coding: utf-8
# 
# Please Note it.
# Python-twitter od the trunk version(r137 or higher)in necessary.
# svn checkout http://python-twitter.googlecode.com/svn/trunk/ python-twitter
#

import smtplib
from email.MIMEText import MIMEText
from email.Header import Header
from email.Utils import formatdate
import twitter
from datetime import *


TWITTER_USER = "TWITTER_USER"
TWITTER_PASSWD = "TWITTER_PASSWARD"
GMAIL_USER = "GMAIL_ACCOUNT"
GMAIL_PASSWD = "GMAIL_PASSWARD"
api = twitter.Api(TWITTER_USER, TWITTER_PASSWD)
FRIENDS_LIST = "friends.txt"
FOLLOWERS_LIST = "followers.txt"

def get_allfriends(): #friendを取得
    friends, cnt = [], 1
    while not len(friends) % 100:
        friends += api.GetFriends(page=cnt) 
        cnt += 1
    friend = []
    for i in friends:
        user = i.screen_name
        user = user + "\n"
        friend.append(user)
    return friend


def get_allfollowers(): #followerを取得
    followers, cnt = [], 1
    while not len(followers) % 100:
        followers += api.GetFollowers(page=cnt) 
        cnt += 1
    follower = []
    for i in followers:
        user = i.screen_name
        user = user + "\n"
        follower.append(user)
    return follower


def flw_list_open(FOLLOWERS_LIST): #前回のfollowerリスト読込
    flw = open(FOLLOWERS_LIST, "r") 
    flw_list = flw.readlines() 
    flw.close() 
    return flw_list


def frd_list_open(FRIENDS_LIST): #前回のfriendリスト読込
    frd = open(FRIENDS_LIST, "r") 
    frd_list = frd.readlines() 
    frd.close() 
    return frd_list


def set_followers(): #followerリストのマッチング
    FLW, RMV = "%(flws)s", "%(rmv)s"
    follower = get_allfollowers()
    flw_list = flw_list_open(FOLLOWERS_LIST)
    fl = open(FOLLOWERS_LIST, "w") 
    new_flw = []
    for flws in follower:
        if flws not in flw_list:
            new_flw.append(FLW % locals())
        fl.write(flws)

    rm_flw = []
    for rmv in flw_list:
        if rmv not in follower: 
            rm_flw.append(RMV % locals()) 
    return new_flw, rm_flw, follower


def set_friends(): #friendリストのマッチング
    FRD, RMV = "%(frds)s", "%(rmv)s"
    friend = get_allfriends()
    frd_list = frd_list_open(FRIENDS_LIST)
    fl = open(FRIENDS_LIST, "w") 
    new_frd = []
    for frds in friend:
        if frds not in frd_list:
            new_frd.append(FRD % locals())
        fl.write(frds)

    rm_frd = []
    for rmv in frd_list:
        if rmv not in friend:
            rm_frd.append(RMV % locals())
    return new_frd, rm_frd, friend


def create_message(from_addr, to_addr, subject, body, encoding):
    msg = MIMEText(body.encode(encoding), "plain", encoding)
    msg["Subject"] = Header(subject, encoding)
    msg["From"] = from_addr
    msg = MIMEText(body.encode(encoding), "plain", encoding)
    msg["Subject"] = Header(subject, encoding)
    msg["From"] = from_addr
    msg["To"] = to_addr
    msg["Date"] = formatdate()
    return msg


def send_via_gmail(from_addr, to_addr, msg):
    s = smtplib.SMTP("smtp.gmail.com", 587)
    s.ehlo()
    s.starttls()
    s.ehlo()
    s.login(GMAIL_USER, GMAIL_PASSWD)
    s.sendmail(from_addr, to_addr, msg.as_string())
    s.close()


def main():
    DATETIME = datetime.now()
    YESTERDAY = DATETIME + timedelta(hours=-24)
    DATESTR = DATETIME.strftime("%Y/%m/%d% %H:%M:%S") 
    STR_YESTERDAY = YESTERDAY.strftime("%Y/%m/%d")

    subject = "Logwatch for %s's Twitter" % TWITTER_USER 
    from_addr = GMAIL_USER
    to_addr = GMAIL_USER
    new_flw, rm_flw, follower = set_followers()
    new_frd, rm_frd, friend = set_friends()

    """
    メールの本文にあたるところ
    もうちょっとうまく書けないものか
    あとそもそも英語があやしい
    """
    body = "################ Logwatch for %s's Twitter ################" % TWITTER_USER + "\n"
    body += "Processing Initiated:%s" % DATESTR + "\n"
    body += "Date Range Processed:%s" % STR_YESTERDAY + "\n"
    body += "Period is day." + "\n"
    body += "\n"
    body += "--------------------- Followers Begin ---------------------" + "\n"
    body += "%s Users Followers" % len(follower) + "\n"
    body += "Followed by ..." + "\n"
    if new_flw == []:
        body += "Nobody followed you yesterday." + "\n"
    else:
        for nfl in new_flw:
            body += "%s is followed you yesterday" % nfl + "\n"
    body += "Rmoved by ..." + "\n"
    if rm_flw == []:
        body += "Nobody Removed you yesterday." + "\n"
    else:
        for rfl in rm_flw:
            body += "%s is Removed you yesterday" % rfl + "\n"
    body += "---------------------- Followers End ---------------------" + "\n"
    body += "\n"
    body += "--------------------- Friends Begin ---------------------" + "\n"
    body += "%s Users Friends" % len(friend) + "\n"
    body += "Following ..." + "\n"
    if new_frd == []:
        body += "No follow yesterday" + "\n"
    else:
        for nfr in new_frd:
            body += "following %s yesterday" % nfr + "\n"
    body += "Rmoving ..." + "\n"
    if rm_frd == []:
        body += "No Remove yesterday." + "\n"
    else:
        for rfr in rm_frd:
            body += "Removing %s yesterday" % rfr + "\n"
    body += "---------------------- Friends End ---------------------" + "\n"
    body += "\n"
    body += "############## Logwatch for %s's Twitter End ##############" % TWITTER_USER + "\n"
    msg = create_message(from_addr, to_addr, subject, body, "utf-8")
    send_via_gmail(from_addr, to_addr, msg)

if __name__ == "__main__":
    main()

[2009年5月6日追記]
送られてきたメールを確認すると、改行されたくないところで改行されてたりするので、時間見つけて修正します。
[追記ここまで]

[2009年6月20日追記]
最近Follower数がかなり少なくカウントされていると思っていて、時間がとれたので調べてみたんだけど、page=1が97になっていてカウントが止まってしまっている。100で割り切れなくなるまでカウントされるロジックなので、本当に97ならしかたがないのだけど、page=2にもFollowerがちゃんとある。調べた結果がこちら。うーん変だなあ・・

[root@centos ~]# python
Python 2.6.2 (r262:71600, May 14 2009, 20:12:16)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import twitter
>>> api = twitter.Api('ACCOUNT', 'PASSWORD')
>>> f = api.GetFollowers(page=2)
>>> print len(f)
58
>>> f = api.GetFollowers(page=1)
>>> print len(f)
97
>>> f = api.GetFollowers(page=3)
>>> print len(f)
0
>>> 

[追記ここまで]


PAGE TOP