Python タグの一覧です(49 件)

[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
>>> 

[追記ここまで]


[Python] Twitter in 3D on Ubigraph

先日、Twitterで知り合ったdoyaさんと実際にお会いして、互いの職歴や、地元の話、最近のWebサービスのことなど、色んな話をしたのですが、最近注目している技術やWebサービスは何かという話題で、情報を可視化出来るUbigraphの話になり、付属されているデモンストレーションを見せてもらいながら、Pythonを含めた何種類かの言語で操作が可能なこと、特にPythonで書かれたサンプルスクリプトが多く付属されていることを教えてもらった。
早速、Pythonの勉強にサンプルコードを読もうと思ったのですが、どうせならTwitterを可視化した事例がないかと調べたところ、ブラジルのChristian S. Perone氏のblogでTwitterのFollowingを可視化したTwitter3D.pyというコードを発見。

Twitter in 3D ! – Pyevolve

早速ダウンロードして、動かしてみた。
その動画がこちらです(HQ視聴がおすすめです)



ところが、どうもFollowしているのに表示されない人がいるので、Follow数をカウントしたところ、ちょうど100人。どうやらPython-twitterの仕様で100人までしか取得出来ないっぽい。

【ご参考】 テックノート@ama-ch – python-twitterで遊んでみた 基本編

Twitterのapiでは、page=ページ番号 (オプション)が用意され、ページ番号を指定することで、指定ユーザの friend の一覧を100件単位で取得することが出来るようだが、python-twiterにpageパラメータが用意されていない模様。さらに調べてみるとこのようなページが

python-twitter Issue 20:Only return 100 users

trunk版では一ヶ月前に解決されているようです。
そこでeasy_installでインストールしたpython-twitterをアンインストールし、trunk版をインストール。その後、Twitter3D.pyでFollowingを全て取得するコードを追加して無事100人以上表示させることが出来た。
修正を加えたコードはこちら

#!/usr/bin/env python
# coding: utf-8
#
# This code is forking from twitter3D.py (H.Aoshima). 
# Christian S. Perone makes the original. 
# Please Note it.
# Python-twitter of the trunk version (r137 or higher) is necessary. 
#

import time
import xmlrpclib
import socket
from sets import Set
import random
from optparse import OptionParser

try:
    import twitter
except:
    print "error:\tcan't import python-twitter module, you must install the module:\n"
    print "\tto install: 'easy_install python-twitter'\n"
    exit()

server_url = 'http://127.0.0.1:20738/RPC2'
screenname = ""
api        = ""
G          = ""

GREEN_COLOR  = "#00ff00"
RED_COLOR    = "#ff0000"
YELLOW_COLOR = "#ffff00"

expandedVertices = Set()
vertexes         = {} 
vertexes_invert  = {} 

def get_allfriends(root_name): #get  all friends
    friends, cnt = [], 1
    while not len(friends) % 100:
        friends += api.GetFriends(root_name, page=cnt) 
        cnt += 1
    return friends

def expand_vertex(v): 
    if v in expandedVertices: 
        return 0
  
    expandedVertices.add(v) 
    G.set_vertex_attribute(v, "color", YELLOW_COLOR) 
    root_name = vertexes[v] 

    print "Getting friends of %s..." % root_name
    friends = get_allfriends(root_name) 
#   print len(friends) # debug

    if len(friends) <= 0: 
        color_node = GREEN_COLOR if vertexes[v] != screenname else RED_COLOR
        G.set_vertex_attribute(v, "color", color_node)

    for friend in friends:
        friend_name = friend.GetScreenName()

        if vertexes_invert.get(friend_name) is not None: 
            edge = G.new_edge(v, vertexes_invert[friend_name]) 
            G.set_edge_attribute(edge, "arrow", "true")
        else: 
            new_vertex = G.new_vertex()
            G.set_vertex_attribute(new_vertex, "label", friend_name)
            G.set_vertex_attribute(new_vertex, "shape", "sphere")

            vertexes.update({new_vertex: friend_name}) 
            vertexes_invert.update({friend_name: new_vertex}) 
            edge = G.new_edge(v, new_vertex)
            G.set_edge_attribute(edge, "arrow", "true") 


    color_node = GREEN_COLOR if vertexes[v] != screenname else RED_COLOR
    G.set_vertex_attribute(v, "color", color_node)


    return 0	

if __name__ == "__main__":
    print "Twitter3D - Twitter 3D nodes viewer"
    print "By Christian S. Perone (@tarantulae)"
    print "http://pyevolve.sourceforge.net/wordpress\n"

    parser = OptionParser()
    parser.add_option("-u", "--username", dest="username",
                    help="The twitter username", metavar="USERNAME")

    parser.add_option("-p", "--password", dest="password",
                    help="The twitter password (optional)", metavar="PASSWORD")

    (options, args) = parser.parse_args()

    if (not options.username):
        parser.print_help()
        exit()

    pass_msg = "authenticated" if options.password else "unauthenticated"
    print "Starting the Twiter3D for user %s (%s)..." % (options.username, pass_msg)

    screenname = options.username
    api = twitter.Api(username=options.username, password=options.password)
    server = xmlrpclib.Server(server_url) 

    G = server.ubigraph 

    try:
        G.clear() 
    except socket.error, msg: 
        print "error:\tcan't connected to the Ubigraph server, the server is running ?\n\terror message:%s\n" % msg
        exit()
 
    root = G.new_vertex() 
    vertexes.update({root : screenname}) 
    vertexes_invert.update({screenname : root}) 

    G.set_vertex_attribute(root, "color", "#ff0000") 
    G.set_vertex_attribute(root, "shape", "sphere") 
    G.set_vertex_attribute(root, "label", screenname)
  
    myPort = random.randint(20700,30000) 
    G.set_vertex_style_attribute(0, "callback_left_doubleclick",
    "http://127.0.0.1:" + str(myPort) + "/expand_vertex") 
    from SimpleXMLRPCServer import SimpleXMLRPCServer 
    server = SimpleXMLRPCServer(("localhost", myPort))
    server.register_introspection_functions()
    server.register_function(expand_vertex) 
    print "Listening for callbacks from ubigraph on the port %d..." % (myPort,)
    server.serve_forever() 

Christian S. Perone氏には、Followingを100人以上取得出来るようにしたので、折角なので公開していい?という旨のメールを送り、全然問題ないし、書いたらlink教えてという返事を頂いた(無茶苦茶な英文でやり取りしてもうた><)。
Ubigraphをやったことない人はデモがかっこいいので是非ご覧になってください。


がんばれ! アドミンくん の新作情報を知らせるTwitterBotを作った

@ITで連載中の4コマ漫画がんばれ! アドミンくんは、システム管理者のありがちネタをユーモラスに描いており、とっても面白く、一服の清涼剤という感じで、第一話から欠かさず読んでいます。
今回、がんばれ! アドミンくんの新着を見逃さないように、新着情報を知らせるTwitterBotを作成しました。
http://twitter.com/ad_min_kun
アカウントがadmin_kunでなく、ad_min_kunと細切れになっているのは、下のようにadminという文字は使えないようなので。

image01

がんばれ!アドミンくん はRSSを吐き出していない為(YahooPipes等の外部サービスでRSS化しているものは見かけます)、スクレイピングで対応しました。例によってコードを晒します。
Python2.4と2.5で動作確認をしています。スクレイピングにBeautifulSoupを、Twitter投稿にpython-twitter(依存関係でsimplejsonも必要)を使用しています。

# coding: utf-8
import urllib2
from twitter import Api as TwitterApi
from BeautifulSoup import BeautifulSoup


def file_open(f):
    r = open(f,'r')
    latest_number = r.readline()
    r.close()
    return latest_number

def parse_html(u):
    soup = BeautifulSoup(urllib2.urlopen(u))
    data = []
    for node in soup.findAll('td', {'colspan': '3'}):
        for tag in node('table', {'width': '100%', 'cellpadding': '3', 'border': '0'}):
            for atag in tag('a'):
                data.append([atag['href'], atag.string])
    data.reverse()
    return data

def main(data, latest_number):
    for i in data:
        entry_link, entry_title = i[0], i[1]
        e = entry_link.split('/')
        entry_number = e[4]
        if latest_number < entry_number:
            api = TwitterApi(TWITTER_USERNAME, TWITTER_PASSWORD)
            post = u'%s %s%s' % (entry_title, DOMAIN, entry_link)
            api.PostUpdate(post)
            latest_number = entry_number
    return latest_number

def file_close(f, l):
    w = open(f, 'w')
    w.write(str(l))
    w.close()

if __name__ == '__main__':
    FILE = 'adminkun_status.txt'
    TWITTER_USERNAME = 'TWITTER_ACCOUNT'
    TWITTER_PASSWORD = 'PASSWORD'
    URL = 'http://www.atmarkit.co.jp/fwin2k/itpropower/admin-kun/index/index.html'
    DOMAIN = 'http://www.atmarkit.co.jp'
    latest_number = file_open(FILE)
    data = parse_html(URL)
    latest_number = main(data, latest_number)
    file_close(FILE, latest_number)

実は前回のBotはこれの副産物でした。自分にとってTwitterは、すっかり情報ハブになっているので、有益になりうるTwitterBot候補があれば、ちょくちょく作っていこうかと思います。


ラジオNIKKEI競馬実況webのNEWSを配信するTwitterBotを作りました

17年近く競馬をやっていた私が、結婚してからいうもの、すっかり馬券を買わなくなっていたのですが、去年の年末に東京大賞典だけ購入しました。結果は駄目でしたが、やはり競馬は面白いね!ということで、いつも予想時に参考にしているラジオNIKKEI競馬実況webのニュースをTwitterに配信するBOTを作りました。

http://twitter.com/keiba_news

配信は1時間に1回にしています(レンタルサーバのcronジョブの最短間隔が1時間なので)。例によってコードを晒します。このコードはPython2.4と2.5で動作確認をしています。また、RSSのパースにfeedparserを、Twitter投稿にpython-twitter(依存関係でsimplejsonも必要)を使用しています。

# coding: utf-8
from time import *
import email.Utils
import feedparser
from twitter import Api as TwitterApi

def file_open(f):
    r = open(f,'r')
    latest_date = r.readline()
    r.close()
    return latest_date

def parse_feed(u):
    data = feedparser.parse(u)
    feed = []
    for entry in data.entries:
        feed.append([entry.date, entry.title, entry.link])
    feed.reverse()
    return feed

def main(feed, latest_date):
    for i in feed:
        entry_date, entry_title, entry_link = i[0], i[1], i[2]
        entry_date = localtime(mktime(email.Utils.parsedate(entry_date)) + 32400)
        entry_date = strftime('%Y/%m/%d %H:%M',entry_date)
        if latest_date < entry_date:
            api = TwitterApi(TWITTER_USERNAME, TWITTER_PASSWORD)
            post = u"%s %s %s" % (entry_date, entry_title, entry_link)
            api.PostUpdate(post)
            latest_date = entry_date
    return latest_date

def file_close(f, l):
    w = open(f, 'w')
    w.write(str(l))
    w.close()

if __name__ == '__main__':
    TWITTER_USERNAME = 'TWITTER_ACCOUNT'
    TWITTER_PASSWORD = 'PASSWORD'
    FILE = 'radionikkei_status.txt'
    URL = 'http://keiba.radionikkei.jp/keiba/rss2/news/'
    latest_date = file_open(FILE)
    feed = parse_feed(URL)
    latest_date = main(feed, latest_date)
    file_close(FILE, latest_date)

なんか無理矢理、関数組んじゃったりしてますが、とりあえず動いてます><
というわけで、ついったったーで競馬好きな方がいらっしゃいましたらFollowしてやって下さい。

参考サイト


PAGE TOP