

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>“南船北馬” &#187; python</title>
	<atom:link href="http://aoshiman.net/weblog/category/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://aoshiman.net/weblog</link>
	<description>不定期更新且つ、最新情報に対して常に周回遅れ気味に追っかけているブログです</description>
	<lastBuildDate>Tue, 20 Oct 2009 11:07:15 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>[Python]CORESERVERのSSH登録を自動化する</title>
		<link>http://aoshiman.net/weblog/2009/09/16/coreserver_ssh/</link>
		<comments>http://aoshiman.net/weblog/2009/09/16/coreserver_ssh/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 13:38:53 +0000</pubDate>
		<dc:creator>aoshiman</dc:creator>
				<category><![CDATA[CORESERVER]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[urllib]]></category>

		<guid isPermaLink="false">http://aoshiman.net/weblog/?p=488</guid>
		<description><![CDATA[				このBlogをホスティングしているCORESERVERは手頃で良いんだけど、SSH接続する前にWeb上の管理画面で、SSH接続のためホスト情報をサーバーに登録する必要があり、この作業が結構面倒くさい。一回登録すれば３０日は有効なのだけど、その間に別の場所からSSH接続したいときは登録しなおさなければならない。なにか良い方法はないかなと捜していたら自動登録スクリプトを作成している方々がいました。
				
				coreserverのSSH登録を自動化するスクリプト &#8211; Geek Not Found
				xrea(coreserver) SSHホスト登録スクリプト &#8211; Kerosoft : Modus Operandi
				
				要はIPアドレス、ID、パスワードなどをPOSTしてあげれば良いみたい。上のエントリーでは、ShellscriptとPerlで書かれていたので、内容を参考にしつつPythonで書きました。
				
#!/usr/bin/env python
# coding: utf-8

import urllib

def get_ip():
    f = urllib.urlopen('http://dyn.value-domain.com/cgi-bin/dyn.fcg?ip')
    ip = f.read()
    return ip

def regist_host(ip, url):
    userid = 'ACCOUNT'
    passwd = 'PASSWORD'
    keyword = u'SSH登録'
   [...]]]></description>
			<content:encoded><![CDATA[				<p>このBlogをホスティングしているCORESERVERは手頃で良いんだけど、SSH接続する前にWeb上の管理画面で、SSH接続のためホスト情報をサーバーに登録する必要があり、この作業が結構面倒くさい。一回登録すれば３０日は有効なのだけど、その間に別の場所からSSH接続したいときは登録しなおさなければならない。なにか良い方法はないかなと捜していたら自動登録スクリプトを作成している方々がいました。</p>
				<ul>
				<li><a href="http://d.hatena.ne.jp/int128/20090113/1231850343">coreserverのSSH登録を自動化するスクリプト &#8211; Geek Not Found</a></li>
				<li><a href="http://mo.kerosoft.com/0119">xrea(coreserver) SSHホスト登録スクリプト &#8211; Kerosoft : Modus Operandi</a></li>
				</ul>
				<p>要はIPアドレス、ID、パスワードなどをPOSTしてあげれば良いみたい。上のエントリーでは、ShellscriptとPerlで書かれていたので、内容を参考にしつつPythonで書きました。</p>
				<pre class="brush: python;">
#!/usr/bin/env python
# coding: utf-8

import urllib

def get_ip():
    f = urllib.urlopen('http://dyn.value-domain.com/cgi-bin/dyn.fcg?ip')
    ip = f.read()
    return ip

def regist_host(ip, url):
    userid = 'ACCOUNT'
    passwd = 'PASSWORD'
    keyword = u'SSH登録'
    encoding = 'shift-jis'
    p = [
        ('id', userid),
        ('pass', passwd),
        ('remote_host', ip),
        ('ssh2', keyword.encode(encoding)),
    ]

    params = urllib.urlencode(p)
    #print params
    up = urllib.urlopen(url, params)
    #print up.read()

if __name__ == '__main__':
   url = 'https://ss1.coressl.jp/www.sXX.coreserver.jp/jp/admin.cgi'
   ip = get_ip()
   regist_host(ip, url)
</pre>
				<p>一応問題なくホスト登録出来たので大丈夫だとは思いますが、使用する場合は自己責任でお願いします。Pythonのバージョンは2.6で確認取っています。useridとpasswdは各自設定したものを、urlのsXXには自分のサーバ番号を入れて下さい。<br />
				<span id="more-488"></span></p>
				<h3>クエリ文字列を作成するところでハマった点</h3>
				<p>クエリ文字列を作成する箇所（urlencode）を<a href="http://www.python.jp/doc/release/lib/node579.html">Python ライブラリリファレンス</a>を参考にして作っていたのですが、どうも辞書で作るとクエリ文字列の順序が意図したように作れないみたい。</p>
				<pre class="brush: python;">
#!/usr/bin/env python
# coding: utf-8

import urllib

#ディクショナリの場合
query = {
    'id': &quot;userid&quot;,
    'pass': &quot;passwd&quot;,
    'remotehost': &quot;ip&quot;,
}

#タプルの場合
query2 = [
    ('id', &quot;userid&quot;),
    ('pass', &quot;passwd&quot;),
    ('remotehost', &quot;ip&quot;),
]

print urllib.urlencode(query)
print urllib.urlencode(query2)
</pre>
				<p>実行結果</p>
				<pre class="brush: bash;">

% python ~/python/bin/encode.py
remotehost=ip&amp;id=userid&amp;pass=passwd #ディクショナリ
id=userid&amp;pass=passwd&amp;remotehost=ip #タプル
</pre>
				<p>これで小一時間悩みました。</p>
]]></content:encoded>
			<wfw:commentRss>http://aoshiman.net/weblog/2009/09/16/coreserver_ssh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Python]ハードディスクの温度を定期的にTwitterにポストする</title>
		<link>http://aoshiman.net/weblog/2009/09/04/python_hdtemp/</link>
		<comments>http://aoshiman.net/weblog/2009/09/04/python_hdtemp/#comments</comments>
		<pubDate>Fri, 04 Sep 2009 11:00:59 +0000</pubDate>
		<dc:creator>aoshiman</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://aoshiman.net/weblog/?p=444</guid>
		<description><![CDATA[				自宅サーバ（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なのに全くインデントしてない>]]></description>
			<content:encoded><![CDATA[				<p>自宅サーバ（CentOS5.3）は極端に熱のこもる場所に設置してあるわけではないので、廃熱に関してはそこそこ大丈夫だと思っているのだけど、それでもハードディスクとかの温度は心配。そこで会社にいても状況を把握出来るように、4時間おきにハードディスクの温度をTwtterにポストしている。以下備忘録的にまとめてみた。</p>
				<h3>hddtempのインストール</h3>
				<p>まずはハードディスクの温度を計測する為にhddtempをインストールする。CentOSの場合はyumでインストール可能。</p>
				<pre class="brush: bash;"># yum -y install hddtemp</pre>
<p>使用する時は、hddtemp disk名をタイプして実行する</p>
<pre class="brush: bash;"># hddtemp /dev/sda
/dev/sda: WDC WD10EADS-00L5B1: 39°C
</pre>
				<h3>hddtempの値を取得してTwitterにポストする</h3>
				<p>以下ソースコード（Pythonなのに全くインデントしてない><）</p>
				<pre class="brush: python;">
#!/usr/bin/env python
# coding: utf-8

import sys
import twitter
from datetime import *

USERNAME = &quot;TWITTER_ACCOUNT&quot;
PASSWORD = &quot;ACCOUNT_PASSWORD&quot;

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

t = sys.stdin.readline()
info = t.rstrip() + &quot; &quot; + &quot;at&quot; + &quot; &quot; +TIME_STR

post = u&quot;%s&quot; % (info)
api.PostUpdate(post)
# print post
</pre>
				<p>Twitterへポストするモジュールは<a href="http://code.google.com/p/python-twitter/">python-twitter</a>を使用。<br />
				注意した点は２つあって、１つは受け取った標準出力に改行がついてきて、そのままではTwitterにうまくポスト出来ないのでrstripしていること。もうひとつは、ポストする内容にその時刻を追加したこと（取得した温度だけをポストする場合、温度が毎回同じだとポストする内容が一緒になってしまい、Twiiter仕様上無効ポストになってしまう）</p>
				<h3>シェルスクリプトの作成</h3>
				<pre class="brush: bash;">
#!/bin/sh
export LANG=ja_JP.utf-8
/usr/sbin/hddtemp /dev/sda | /usr/local/bin/python /usr/local/bin/hdd_info.py
exit
</pre>
				<p>ここでは、/dev/sdaの温度を取得し、先ほどのスクリプト（hdd_info.py）へパイプで繋いでいる。ディスク名は環境によって違うと思うので置き換えて下さい。最初どうしても°CがTwitterにポストされず困っていたのだけど、export LANG=ja_JP.utf-8を記述することでポスト出来るようになった（<a href="http://twitter.com/katsu2000x">katsu2000x</a>さんthanks！）<br />
				このシェルスクリプトをCronで定時実行させるとこのようになる。Twitterアカウントは本人のアカウントを使用するとTLを汚すような気がして、それ用のアカウントを作った。</p>
				<p><a class="" rel="" title="20090904_01" href="http://www.flickr.com/photos/aoshiman/3886938526/"><img src="http://static.flickr.com/3516/3886938526_57daec1c6c.jpg" alt="20090904_01"></a></p>
				<p>
				[2009年9月13日追記]<br />
				twitterでフォローしているmagicalhatさんが、perlでさくっと書いてくれてトラバ貰いました。勉強になります！<br />
				[追記ここまで]</p>
]]></content:encoded>
			<wfw:commentRss>http://aoshiman.net/weblog/2009/09/04/python_hdtemp/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[Python]Twitter版LogWatchのようなもの</title>
		<link>http://aoshiman.net/weblog/2009/05/05/twitter_logwatch/</link>
		<comments>http://aoshiman.net/weblog/2009/05/05/twitter_logwatch/#comments</comments>
		<pubDate>Tue, 05 May 2009 10:53:01 +0000</pubDate>
		<dc:creator>aoshiman</dc:creator>
				<category><![CDATA[Gmail]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[smtplib]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://aoshiman.net/weblog/?p=312</guid>
		<description><![CDATA[				GW期間に３連休（年に２回あるかどうか！というくらい貴重）をもらったので、Pythonのお勉強を兼ねてTwitter版LogWatchのようなものを作ってみました。
				
				
				24時過ぎとかにcronで実行させると、FriendsとFollowersそれぞれのリストを前日に保存しておいたリストと照合し、追加した（された）および削除した（された）Friends/FollowersをリストアップしてGmailで自分宛に送信します。Twitter APIを扱うモジュールはPython-twitterというものを使用していますが、前回と同じく、easy_installで入るものでなくtrunkにあるものを使用しています。
				作ってみて色々思ったこと
				
				結構行数が増えてきたので、Classにまとめようと思ったけど、次回チャレンジする
				Pythonで書いている人は文字列囲むのにダブルクォーテーションとシングルクォーテーションどちらなのか。もしくは使い分けしているのか
				変数命名が納得いかない。どうしたものか。
				自分で書いた英語がそもそも怪しい＞＜
				コードを書き始めてから、このblogを書き始めるまで１３時間くらいかかった。半年前だったら１週間以上かかっただろう。この進歩（牛歩だが）が嬉しい
				
				コードはこちら。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 = &#34;TWITTER_USER&#34;
TWITTER_PASSWD = &#34;TWITTER_PASSWARD&#34;
GMAIL_USER = &#34;GMAIL_ACCOUNT&#34;
GMAIL_PASSWD = &#34;GMAIL_PASSWARD&#34;
api = twitter.Api(TWITTER_USER, TWITTER_PASSWD)
FRIENDS_LIST = &#34;friends.txt&#34;
FOLLOWERS_LIST = &#34;followers.txt&#34;

def get_allfriends(): #friendを取得
    [...]]]></description>
			<content:encoded><![CDATA[				<p>GW期間に３連休（年に２回あるかどうか！というくらい貴重）をもらったので、Pythonのお勉強を兼ねてTwitter版<a href="http://www.atmarkit.co.jp/flinux/rensai/root04/root04c.html"></a>LogWatchのようなものを作ってみました。</p>
				<p><a class="" rel="" title="20090505_02" href="http://www.flickr.com/photos/aoshiman/3503817600/"><img src="http://static.flickr.com/3374/3503817600_a2f23125e6.jpg" alt="20090505_02"></a></p>
				<p><span id="more-312"></span><br />
				24時過ぎとかにcronで実行させると、FriendsとFollowersそれぞれのリストを前日に保存しておいたリストと照合し、追加した（された）および削除した（された）Friends/FollowersをリストアップしてGmailで自分宛に送信します。Twitter APIを扱うモジュールはPython-twitterというものを使用していますが、<a href="http://aoshiman.net/weblog/2009/04/17/python-twitter-in-3d-on-ubigraph/">前回</a>と同じく、easy_installで入るものでなくtrunkにあるものを使用しています。</p>
				<h3>作ってみて色々思ったこと</h3>
				<ul>
				<li>結構行数が増えてきたので、Classにまとめようと思ったけど、次回チャレンジする</li>
				<li>Pythonで書いている人は文字列囲むのにダブルクォーテーションとシングルクォーテーションどちらなのか。もしくは使い分けしているのか</li>
				<li>変数命名が納得いかない。どうしたものか。</li>
				<li>自分で書いた英語がそもそも怪しい＞＜</li>
				<li>コードを書き始めてから、このblogを書き始めるまで１３時間くらいかかった。半年前だったら１週間以上かかっただろう。この進歩（牛歩だが）が嬉しい</li>
				</ul>
				<p>コードはこちら。Python2.6（MacOSX dmg）で動作確認は取れています。但しcronでの運用はまだ行っていません（先日セッティングした自鯖に入れるつもり）。</p>
				<pre class="brush: python;">
#!/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 = &quot;TWITTER_USER&quot;
TWITTER_PASSWD = &quot;TWITTER_PASSWARD&quot;
GMAIL_USER = &quot;GMAIL_ACCOUNT&quot;
GMAIL_PASSWD = &quot;GMAIL_PASSWARD&quot;
api = twitter.Api(TWITTER_USER, TWITTER_PASSWD)
FRIENDS_LIST = &quot;friends.txt&quot;
FOLLOWERS_LIST = &quot;followers.txt&quot;

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 + &quot;\n&quot;
        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 + &quot;\n&quot;
        follower.append(user)
    return follower

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

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

def set_followers(): #followerリストのマッチング
    FLW, RMV = &quot;%(flws)s&quot;, &quot;%(rmv)s&quot;
    follower = get_allfollowers()
    flw_list = flw_list_open(FOLLOWERS_LIST)
    fl = open(FOLLOWERS_LIST, &quot;w&quot;)
    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 = &quot;%(frds)s&quot;, &quot;%(rmv)s&quot;
    friend = get_allfriends()
    frd_list = frd_list_open(FRIENDS_LIST)
    fl = open(FRIENDS_LIST, &quot;w&quot;)
    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), &quot;plain&quot;, encoding)
    msg[&quot;Subject&quot;] = Header(subject, encoding)
    msg[&quot;From&quot;] = from_addr
    msg = MIMEText(body.encode(encoding), &quot;plain&quot;, encoding)
    msg[&quot;Subject&quot;] = Header(subject, encoding)
    msg[&quot;From&quot;] = from_addr
    msg[&quot;To&quot;] = to_addr
    msg[&quot;Date&quot;] = formatdate()
    return msg

def send_via_gmail(from_addr, to_addr, msg):
    s = smtplib.SMTP(&quot;smtp.gmail.com&quot;, 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(&quot;%Y/%m/%d% %H:%M:%S&quot;)
    STR_YESTERDAY = YESTERDAY.strftime(&quot;%Y/%m/%d&quot;)

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

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

if __name__ == &quot;__main__&quot;:
    main()
</pre>
				<p>[2009年5月6日追記]<br />
				送られてきたメールを確認すると、改行されたくないところで改行されてたりするので、時間見つけて修正します。<br />
				[追記ここまで]</p>
				<p>[2009年6月20日追記]<br />
				最近Follower数がかなり少なくカウントされていると思っていて、時間がとれたので調べてみたんだけど、page=1が97になっていてカウントが止まってしまっている。100で割り切れなくなるまでカウントされるロジックなので、本当に97ならしかたがないのだけど、page=2にもFollowerがちゃんとある。調べた結果がこちら。うーん変だなあ・・</p>
				<pre class="brush: python;">
[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 &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&gt;&gt;&gt; import twitter
&gt;&gt;&gt; api = twitter.Api('ACCOUNT', 'PASSWORD')
&gt;&gt;&gt; f = api.GetFollowers(page=2)
&gt;&gt;&gt; print len(f)
58
&gt;&gt;&gt; f = api.GetFollowers(page=1)
&gt;&gt;&gt; print len(f)
97
&gt;&gt;&gt; f = api.GetFollowers(page=3)
&gt;&gt;&gt; print len(f)
0
&gt;&gt;&gt;
</pre>
				<p>[追記ここまで]</p>
]]></content:encoded>
			<wfw:commentRss>http://aoshiman.net/weblog/2009/05/05/twitter_logwatch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Python] Twitter in 3D on Ubigraph</title>
		<link>http://aoshiman.net/weblog/2009/04/17/python-twitter-in-3d-on-ubigraph/</link>
		<comments>http://aoshiman.net/weblog/2009/04/17/python-twitter-in-3d-on-ubigraph/#comments</comments>
		<pubDate>Fri, 17 Apr 2009 14:44:56 +0000</pubDate>
		<dc:creator>aoshiman</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://aoshiman.net/weblog/?p=243</guid>
		<description><![CDATA[				先日、Twitterで知り合ったdoyaさんと実際にお会いして、互いの職歴や、地元の話、最近のWebサービスのことなど、色んな話をしたのですが、最近注目している技術やWebサービスは何かという話題で、情報を可視化出来るUbigraphの話になり、付属されているデモンストレーションを見せてもらいながら、Pythonを含めた何種類かの言語で操作が可能なこと、特にPythonで書かれたサンプルスクリプトが多く付属されていることを教えてもらった。
				早速、Pythonの勉強にサンプルコードを読もうと思ったのですが、どうせならTwitterを可視化した事例がないかと調べたところ、ブラジルのChristian S. Perone氏のblogでTwitterのFollowingを可視化したTwitter3D.pyというコードを発見。
				
				Twitter in 3D ! &#8211; Pyevolve
				
				早速ダウンロードして、動かしてみた。
				その動画がこちらです（HQ視聴がおすすめです）
				
				
				
				ところが、どうもFollowしているのに表示されない人がいるので、Follow数をカウントしたところ、ちょうど100人。どうやらPython-twitterの仕様で100人までしか取得出来ないっぽい。
				
				【ご参考】  テックノート＠ama-ch &#8211; 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 [...]]]></description>
			<content:encoded><![CDATA[				<p>先日、Twitterで知り合った<a href="http://twitter.com/doya">doya</a>さんと実際にお会いして、互いの職歴や、地元の話、最近のWebサービスのことなど、色んな話をしたのですが、最近注目している技術やWebサービスは何かという話題で、情報を可視化出来る<a href="http://ubietylab.net/ubigraph/">Ubigraph</a>の話になり、付属されているデモンストレーションを見せてもらいながら、Pythonを含めた何種類かの言語で操作が可能なこと、特にPythonで書かれたサンプルスクリプトが多く付属されていることを教えてもらった。<br />
				早速、Pythonの勉強にサンプルコードを読もうと思ったのですが、どうせならTwitterを可視化した事例がないかと調べたところ、ブラジルのChristian S. Perone氏のblogでTwitterのFollowingを可視化したTwitter3D.pyというコードを発見。<br />
				<br />
				<a href="http://pyevolve.sourceforge.net/wordpress/?p=203">Twitter in 3D ! &#8211; Pyevolve</a><br />
				<br />
				早速ダウンロードして、動かしてみた。<br />
				その動画がこちらです（HQ視聴がおすすめです）<br />
				<br />
				<a href="http://www.youtube.com/watch?v=WUCf61k_j5s"><img src="http://img.youtube.com/vi/WUCf61k_j5s/default.jpg" width="130" height="97" border=0></a><br />
				<br />
				ところが、どうもFollowしているのに表示されない人がいるので、Follow数をカウントしたところ、ちょうど100人。どうやらPython-twitterの仕様で100人までしか取得出来ないっぽい。<span id="more-243"></span><br />
				<br />
				<a href="http://d.hatena.ne.jp/ama-ch/20080519/1211178876">【ご参考】  テックノート＠ama-ch &#8211; python-twitterで遊んでみた 基本編</a><br />
				<br />
				Twitterのapiでは、page=ページ番号 (オプション)が用意され、ページ番号を指定することで、指定ユーザの friend の一覧を100件単位で取得することが出来るようだが、python-twiterにpageパラメータが用意されていない模様。さらに調べてみるとこのようなページが<br />
				<br />
				<a href="http://code.google.com/p/python-twitter/issues/detail?id=20">python-twitter  Issue 20:Only return 100 users</a><br />
				<br />
				trunk版では一ヶ月前に解決されているようです。<br />
				そこでeasy_installでインストールしたpython-twitterをアンインストールし、trunk版をインストール。その後、Twitter3D.pyでFollowingを全て取得するコードを追加して無事100人以上表示させることが出来た。<br />
				修正を加えたコードはこちら</p>
				<pre class="brush: python;">
#!/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 &quot;error:\tcan't import python-twitter module, you must install the module:\n&quot;
    print &quot;\tto install: 'easy_install python-twitter'\n&quot;
    exit()

server_url = 'http://127.0.0.1:20738/RPC2'
screenname = &quot;&quot;
api        = &quot;&quot;
G          = &quot;&quot;

GREEN_COLOR  = &quot;#00ff00&quot;
RED_COLOR    = &quot;#ff0000&quot;
YELLOW_COLOR = &quot;#ffff00&quot;

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, &quot;color&quot;, YELLOW_COLOR)
    root_name = vertexes[v] 

    print &quot;Getting friends of %s...&quot; % root_name
    friends = get_allfriends(root_name)
#   print len(friends) # debug

    if len(friends) &lt;= 0:
        color_node = GREEN_COLOR if vertexes[v] != screenname else RED_COLOR
        G.set_vertex_attribute(v, &quot;color&quot;, 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, &quot;arrow&quot;, &quot;true&quot;)
        else:
            new_vertex = G.new_vertex()
            G.set_vertex_attribute(new_vertex, &quot;label&quot;, friend_name)
            G.set_vertex_attribute(new_vertex, &quot;shape&quot;, &quot;sphere&quot;)

            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, &quot;arrow&quot;, &quot;true&quot;) 

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

    return 0	

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

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

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

    (options, args) = parser.parse_args()

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

    pass_msg = &quot;authenticated&quot; if options.password else &quot;unauthenticated&quot;
    print &quot;Starting the Twiter3D for user %s (%s)...&quot; % (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 &quot;error:\tcan't connected to the Ubigraph server, the server is running ?\n\terror message:%s\n&quot; % msg
        exit()

    root = G.new_vertex()
    vertexes.update({root : screenname})
    vertexes_invert.update({screenname : root}) 

    G.set_vertex_attribute(root, &quot;color&quot;, &quot;#ff0000&quot;)
    G.set_vertex_attribute(root, &quot;shape&quot;, &quot;sphere&quot;)
    G.set_vertex_attribute(root, &quot;label&quot;, screenname)

    myPort = random.randint(20700,30000)
    G.set_vertex_style_attribute(0, &quot;callback_left_doubleclick&quot;,
    &quot;http://127.0.0.1:&quot; + str(myPort) + &quot;/expand_vertex&quot;)
    from SimpleXMLRPCServer import SimpleXMLRPCServer
    server = SimpleXMLRPCServer((&quot;localhost&quot;, myPort))
    server.register_introspection_functions()
    server.register_function(expand_vertex)
    print &quot;Listening for callbacks from ubigraph on the port %d...&quot; % (myPort,)
    server.serve_forever()
</pre>
				<p>
				Christian S. Perone氏には、Followingを100人以上取得出来るようにしたので、折角なので公開していい？という旨のメールを送り、全然問題ないし、書いたらlink教えてという返事を頂いた（無茶苦茶な英文でやり取りしてもうた＞＜）。<br />
				Ubigraphをやったことない人は<a href="http://ubietylab.net/ubigraph/content/Demos/index.html">デモがかっこいい</a>ので是非ご覧になってください。</p>
]]></content:encoded>
			<wfw:commentRss>http://aoshiman.net/weblog/2009/04/17/python-twitter-in-3d-on-ubigraph/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>がんばれ！ アドミンくん の新作情報を知らせるTwitterBotを作った</title>
		<link>http://aoshiman.net/weblog/2009/01/07/adminkun-twitter/</link>
		<comments>http://aoshiman.net/weblog/2009/01/07/adminkun-twitter/#comments</comments>
		<pubDate>Wed, 07 Jan 2009 14:12:09 +0000</pubDate>
		<dc:creator>aoshiman</dc:creator>
				<category><![CDATA[Beautifulsoup]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://aoshiman.net/weblog/?p=120</guid>
		<description><![CDATA[				@ITで連載中の４コマ漫画がんばれ！ アドミンくんは、システム管理者のありがちネタをユーモラスに描いており、とっても面白く、一服の清涼剤という感じで、第一話から欠かさず読んでいます。
				今回、がんばれ！ アドミンくんの新着を見逃さないように、新着情報を知らせるTwitterBotを作成しました。
				http://twitter.com/ad_min_kun
				アカウントがadmin_kunでなく、ad_min_kunと細切れになっているのは、下のようにadminという文字は使えないようなので。
				
				がんばれ！アドミンくん は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 [...]]]></description>
			<content:encoded><![CDATA[				<p>@ITで連載中の４コマ漫画<a href="http://www.atmarkit.co.jp/fwin2k/itpropower/admin-kun/index/index.html">がんばれ！ アドミンくん</a>は、システム管理者のありがちネタをユーモラスに描いており、とっても面白く、一服の清涼剤という感じで、第一話から欠かさず読んでいます。<br />
				今回、がんばれ！ アドミンくんの新着を見逃さないように、新着情報を知らせるTwitterBotを作成しました。<span id="more-120"></span><br />
				<a href="http://twitter.com/ad_min_kun">http://twitter.com/ad_min_kun</a><br />
				アカウントがadmin_kunでなく、ad_min_kunと細切れになっているのは、下のようにadminという文字は使えないようなので。</p>
				<p><img src="http://aoshiman.net/weblog/wp-admin/user-images/20090106_01.png" alt="image01" /></p>
				<p>がんばれ！アドミンくん はRSSを吐き出していない為（YahooPipes等の外部サービスでRSS化しているものは見かけます）、スクレイピングで対応しました。例によってコードを晒します。<br />
				Python2.4と2.5で動作確認をしています。スクレイピングにBeautifulSoupを、Twitter投稿にpython-twitter（依存関係でsimplejsonも必要）を使用しています。</p>
				<pre class="brush: python;">
# 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 &lt; 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)
</pre>
				<p>実は<a href="http://aoshiman.net/weblog/2009/01/04/radinikkei-twitterbot/">前回のBot</a>はこれの副産物でした。自分にとってTwitterは、すっかり情報ハブになっているので、有益になりうるTwitterBot候補があれば、ちょくちょく作っていこうかと思います。</p>
]]></content:encoded>
			<wfw:commentRss>http://aoshiman.net/weblog/2009/01/07/adminkun-twitter/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>ラジオNIKKEI競馬実況webのNEWSを配信するTwitterBotを作りました</title>
		<link>http://aoshiman.net/weblog/2009/01/04/radinikkei-twitterbot/</link>
		<comments>http://aoshiman.net/weblog/2009/01/04/radinikkei-twitterbot/#comments</comments>
		<pubDate>Sun, 04 Jan 2009 11:13:08 +0000</pubDate>
		<dc:creator>aoshiman</dc:creator>
				<category><![CDATA[Keiba]]></category>
		<category><![CDATA[feedparser]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://aoshiman.net/weblog/?p=131</guid>
		<description><![CDATA[				17年近く競馬をやっていた私が、結婚してからいうもの、すっかり馬券を買わなくなっていたのですが、去年の年末に東京大賞典だけ購入しました。結果は駄目でしたが、やはり競馬は面白いね！ということで、いつも予想時に参考にしているラジオNIKKEI競馬実況webのニュースをTwitterに配信するBOTを作りました。
				
				http://twitter.com/keiba_news
				
				配信は１時間に１回にしています（レンタルサーバのcronジョブの最短間隔が１時間なので）。例によってコードを晒します。このコードは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:
 [...]]]></description>
			<content:encoded><![CDATA[				<p>17年近く競馬をやっていた私が、結婚してからいうもの、すっかり馬券を買わなくなっていたのですが、去年の年末に<a href="http://www.tokyocitykeiba.com/01/2008/index.php?Date=20081229">東京大賞典</a>だけ購入しました。結果は駄目でしたが、やはり競馬は面白いね！ということで、いつも予想時に参考にしている<a href="http://keiba.radionikkei.jp/">ラジオNIKKEI競馬実況web</a>のニュースをTwitterに配信するBOTを作りました。<br />
				<span id="more-131"></span><br />
				<a href="http://twitter.com/keiba_news">http://twitter.com/keiba_news</a><br />
				<br />
				配信は１時間に１回にしています（レンタルサーバのcronジョブの最短間隔が１時間なので）。例によってコードを晒します。このコードはPython2.4と2.5で動作確認をしています。また、RSSのパースにfeedparserを、Twitter投稿にpython-twitter（依存関係でsimplejsonも必要）を使用しています。</p>
				<pre class="brush: python;">
# 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 &lt; entry_date:
            api = TwitterApi(TWITTER_USERNAME, TWITTER_PASSWORD)
            post = u&quot;%s %s %s&quot; % (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)
</pre>
				<p>なんか無理矢理、関数組んじゃったりしてますが、とりあえず動いてます＞＜<br />
				というわけで、ついったったーで競馬好きな方がいらっしゃいましたらFollowしてやって下さい。</p>
				<h2>参考サイト</h2>
				<ul>
				<li><a href="http://d.hatena.ne.jp/wakizaka/20080208/1202443369">Absolute Territory：twitterボット「ZAWATTER」を作ったよー＼(＾o＾)／</a></li>
				<li><a href="http://aoshiman.net/weblog/2008/09/30/google_search_history/">南船北馬：Pythonで１日のGoogle検索履歴の一覧を作成してGmailから送信する</li>
				</ul>
]]></content:encoded>
			<wfw:commentRss>http://aoshiman.net/weblog/2009/01/04/radinikkei-twitterbot/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MacBookのモーションセンサーでテトリスをやってみた</title>
		<link>http://aoshiman.net/weblog/2008/10/21/macbook_tetris/</link>
		<comments>http://aoshiman.net/weblog/2008/10/21/macbook_tetris/#comments</comments>
		<pubDate>Tue, 21 Oct 2008 13:18:06 +0000</pubDate>
		<dc:creator>aoshiman</dc:creator>
				<category><![CDATA[AMSTracker]]></category>
		<category><![CDATA[MacBook]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://aoshiman.net/weblog/?p=18</guid>
		<description><![CDATA[				昨年の11月にLet&#8217;s Note W5からMacBookにチェンジした時に、最後までMacBookとThinkpadどちらにするか悩んだのですが、Thinkpadいいなあと思ってたのはこちらの記事を以前から読んでいたから。
				もちろんMacBookにも緊急モーションセンサーがあるのは知っていて、購入した時から、いつかモーションセンサーを使って何かやってみようと思っていました。で、ようやくやってみたのがこの動画です（ちょっと見難いです>]]></description>
			<content:encoded><![CDATA[				<p>昨年の11月にLet&#8217;s Note W5からMacBookにチェンジした時に、最後までMacBookとThinkpadどちらにするか悩んだのですが、Thinkpadいいなあと思ってたのは<a href="http://e8y.net/blog/2006/10/26/p135.html">こちらの記事</a>を以前から読んでいたから。<br />
				もちろんMacBookにも緊急モーションセンサーがあるのは知っていて、購入した時から、いつかモーションセンサーを使って何かやってみようと思っていました。で、ようやくやってみたのがこの動画です（ちょっと見難いです><）。</p>
				<p><a href="http://www.youtube.com/watch?v=N1PXuAwFQk0"><img src="http://img.youtube.com/vi/N1PXuAwFQk0/default.jpg" width="130" height="97" border=0></a></p>
				<p>このblogで数回ネタとして書いていますが、このところPythonが楽しくて、今回もぜひPythonでやろうと思い、緊急モーションセンサーの挙動をPythonで取得するものを捜してたら次のサイトにたどり着きました。<span id="more-18"></span></p>
				<ul>
				<li><a href="http://journal.mycom.co.jp/column/osx/241/index.html">マイコミジャーナル：Macを揺さぶれ! Wiiリモコン的入力装置を考える</a></li>
				<li><a href="http://interconnected.org/home/2005/03/04/apples_powerbook">http://interconnected.org/home/2005/03/04/apples_powerbook</a></li>
				</ul>
				<p>MacBookの緊急モーションセンサーの情報を取得するにはAMSTrackerを使用します。インストール等については上記マイコミジャーナルのサイトをご確認下さい。AMSTrackerを次のように実行すると</p>
				<pre>AMSTracker -u 0.5</pre>
<p>このように３つの数字が表示されます。一番左の数字が左右、真ん中の数字が垂直、右の数字が前後と、それぞれの動きを表示しています。MacBookを動かすと、それぞれの数字が動くことがわかります（終了する場合はControl-C）。<br />
<img src="http://aoshiman.net/weblog/wp-admin/user-images/20081020_01.png" alt="amstracker_01" /></p>
<p>また、次のように -s を付けて実行すると</p>
<pre>AMSTracker -u 0.5 -s</pre>
				<p>0.5秒毎に数値が出力されます（終了する場合はControl-C）。<br />
				<img src="http://aoshiman.net/weblog/wp-admin/user-images/20081020_02.png" alt="amstracker_02" /></p>
				<p>この数値をPythonスクリプトで読み取り、AppleScript経由でキーストロークをコントロールしています。</p>
				<pre>AMSTracker -u 0.3 -s | python  tilt_control_osx.py</pre>
<p>このように実行してから、<a href="http://www.lostjungle.com/play.php?id=99">ここにある</a>フラッシュ版テトリスを操作しています。終了はターミナル上でControl-Cを押します。<br />
作成したコードは、へっぽこですが一応掲載させていただきます（スクリプトは何度も実行して成功しているものですが、実施は自己責任でお願いします）。<br />
実際に実行する場合、気を付けていただきたいことは</p>
<ul>
<li>AMSTracker のセンサー値の取得間隔は0.3秒にしていますが、うまくいかないようでしたら、0.1〜0.5くらいで調整してみて下さい。</li>
<li>THRESHOLD（しきい値）の数値30は私の経験に基づく数値で、それ以下にして実行すると敏感になりすぎてMacBookをコントロール出来なくなる可能性があります。</li>
<li>DOWNキーはMacBookを手前に引く（AMSTrackerの３番目の数値がプラス値になる）のですが、時々高いマイナス値が出ます。それによってDOWNコントロールをするつもりで逆にUPする場合があります。</li>
<li>コードにdebug用キーストロークをコメントアウトしてあります。そちらの挙動をターミナル上で確認してから実行するとわかりやすいかもです。</li>
</ul>
<p>Geekな方々には、いまさら感のあるネタかもしれませんが、自分でもなんとか出来たのでうれしいです。コードに関してはもっとうまく書けると思うので、もう少し考えてみようと思います。</p>
<pre class="brush: python;">
# coding: utf-8
# thanks Matt Webb: http://interconnected.org/home/2005/03/04/apples_powerbook
# thanks Naoki Tomita: http://e8y.net/blog/2006/10/26/p135.html
# Download AMSTracker from http://www.osxbook.com/software/sms/amstracker/
# Put AMSTracker and tilt_control_osx.py in the same directory. Go to this directory
# in the Terminal and type:
# ./AMSTracker -u 0.3 -s | python tilt_control_osx.py
# Hit ctrl-c to exit.

THRESHOLD = 30 # lower numbers makes this more sensitive
X_AXCIS = 0 # three dimensions: sideways: 0, vertical: 1, forward/back: 2
Y_AXCIS = 2 # three dimensions: sideways: 0, vertical: 1, forward/back: 2

import sys, os

def run_command(command):
    script = os.popen('osascript', &quot;w&quot;)
    script.write('tell application &quot;System Events&quot;\r\n')
    script.write('%s\r\n' % command)
    script.write('end tell\r\n')
    script.close()

while 1:
    try:
        line = sys.stdin.readline()
        x, y = int(line.split()[X_AXCIS]), int(line.split()[Y_AXCIS])
        if abs(x) &gt; THRESHOLD or abs(y) &gt; THRESHOLD:
            if x &gt; 0 and abs(x) &gt; abs(y):
                run_command('keystroke(ASCII character 28)') # move left
                #run_command('keystroke &quot;l&quot;')
            elif x &lt; 0 and abs(x) &gt; abs(y):
                run_command('keystroke(ASCII character 29)') # move right
                #run_command('keystroke &quot;r&quot;')
            elif y &gt; 0 and abs(y) &gt; abs(x):
                #run_command('keystroke &quot;d&quot;')
                run_command('keystroke(ASCII character 31)') # move down
            elif y &lt; 0 and abs(y) &gt; abs(x):
                #run_command('keystroke &quot;u&quot;')
                run_command('keystroke(ASCII character 30)') # move up
    except KeyboardInterrupt:
        sys.exit(0)
    except:
        pass
</pre>
				<h3>その他参考させていただいたサイト</h3>
				<ul>
				<li><a href="http://web.sfc.keio.ac.jp/~shokai/archives/2008/02/apple_script.html">s.h.log ： Apple Scriptでキーストロークを送る</a></li>
				<li><a href="http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-217.html">Supporting Keyboard Navigation of Lists</a></li>
				</ul>
]]></content:encoded>
			<wfw:commentRss>http://aoshiman.net/weblog/2008/10/21/macbook_tetris/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pythonで１日のGoogle検索履歴の一覧を作成してGmailから送信する</title>
		<link>http://aoshiman.net/weblog/2008/09/30/google_search_history/</link>
		<comments>http://aoshiman.net/weblog/2008/09/30/google_search_history/#comments</comments>
		<pubDate>Tue, 30 Sep 2008 14:21:56 +0000</pubDate>
		<dc:creator>aoshiman</dc:creator>
				<category><![CDATA[Gmail]]></category>
		<category><![CDATA[feedparser]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[smtplib]]></category>
		<category><![CDATA[urllib]]></category>
		<category><![CDATA[RSS]]></category>

		<guid isPermaLink="false">http://aoshiman.net/weblog/?p=17</guid>
		<description><![CDATA[				今の私にとって（他の人もそうだと思いますが）、仕事プライベートに関係なく、Google検索は無くてはならないものですが、はたして１日にどのくらい検索しているのか知りたくて、リストを作成してみました。併せて前回のYahoo!天気情報のRSSと同様にGmailで送信しています。役に立つか分かりませんが、作成したコードを掲載します（スクリプトは何度も実行して成功しているものですが、実施は自己責任でお願いします）。尚、Google検索の履歴（Google Search History）はGoogleアカウントでログインしている状態で有効になります。
				作成した時のポイントとしては
				
				Google Search History は RSS で取得出来るので、feedparserを利用した
				RSS は Basic認証がかかる為、urllibのFancyURLopenerを使用した
				RSSのURLは件数のパラメータ（&#038;num=）が無い場合、25件しか取得出来ないようなので（自分調べ）、１日で必要な件数を設定した
				取得出来る日時がGMTなので、日本時間（＋9h）にする方法に悩んだ
				
				
# coding:utf-8

import urllib
import feedparser
import email.Utils
from time import *

import smtplib
from email.MIMEText import MIMEText
from email.Header import Header
from email.Utils import formatdate

class MyURLopener(urllib.FancyURLopener):
    def prompt_user_passwd(self, host, realm):
        return ('YOUR_GMAIL_ADDRESS', 'YOUR_PASSWORD')

def feed_parse(u):
    f = opener.open(u)
    [...]]]></description>
			<content:encoded><![CDATA[				<p>今の私にとって（他の人もそうだと思いますが）、仕事プライベートに関係なく、Google検索は無くてはならないものですが、はたして１日にどのくらい検索しているのか知りたくて、リストを作成してみました。併せて前回の<a href="http://aoshiman.net/weblog/2008/09/21/yahoo_rss_gmail/">Yahoo!天気情報のRSS</a>と同様にGmailで送信しています。役に立つか分かりませんが、作成したコードを掲載します（スクリプトは何度も実行して成功しているものですが、実施は自己責任でお願いします）。尚、Google検索の履歴（Google Search History）はGoogleアカウントでログインしている状態で有効になります。<br />
				作成した時のポイントとしては<span id="more-17"></span></p>
				<ul>
				<li>Google Search History は RSS で取得出来るので、feedparserを利用した</li>
				<li>RSS は Basic認証がかかる為、urllibのFancyURLopenerを使用した</li>
				<li>RSSのURLは件数のパラメータ（&#038;num=）が無い場合、25件しか取得出来ないようなので（自分調べ）、１日で必要な件数を設定した</li>
				<li>取得出来る日時がGMTなので、日本時間（＋9h）にする方法に悩んだ</li>
				</ul>
				<pre class="brush: python;">
# coding:utf-8

import urllib
import feedparser
import email.Utils
from time import *

import smtplib
from email.MIMEText import MIMEText
from email.Header import Header
from email.Utils import formatdate

class MyURLopener(urllib.FancyURLopener):
    def prompt_user_passwd(self, host, realm):
        return ('YOUR_GMAIL_ADDRESS', 'YOUR_PASSWORD')

def feed_parse(u):
    f = opener.open(u)
    d = feedparser.parse(f)
    TEMPLATE = '* %(entry_date)s : %(entry_title)s'
    feed = []
    for entry in d.entries:
        feed.append([entry.date, entry.title])
    feed.reverse()

    item_list = []
    today = localtime(time())[0:3]
    for i in feed:
        entry_date, entry_title = i[0], i[1]
        entry_date = localtime(mktime(email.Utils.parsedate(entry_date)) + 32400)
        if entry_date[0:3] == today:
            entry_date = strftime('%Y/%m/%d %H:%M:%S',entry_date)
            item_list.append(TEMPLATE % locals())
    items = '\n'.join(item_list)

    return items

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['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('YOUR_GMAIL_ADDRESS', 'YOUR_PASSWORD')
    s.sendmail(from_addr, to_addr, msg.as_string())
    s.close()

if __name__ == '__main__':
    number = '200'
    URL = 'http://www.google.com/searchhistory/?output=rss&amp;amp;amp;num=%s' % number
    opener = MyURLopener({})
    subject = 'Google search history'
    body = feed_parse(URL)
    from_addr = 'YOUR_GMAIL_ADDRESS'
    to_addr = 'xxxxxxxxxxxxx@gmail.com'
    msg = create_message(from_addr, to_addr, subject, body, 'UTF-8')
    send_via_gmail(from_addr, to_addr, msg)
</pre>
				<p>
				実際に送ってみるとこんなかんじです。これは一部分で、調べものが多いときは100件以上／日は検索していました。<br />
				<img src="http://aoshiman.net/weblog/wp-admin/user-images/20080930_01.png" alt="Gmail" /><br />
				<br />
				少しとはいえ、自分の検索を晒すのは恥ずかしい＞＜。Typoとか（笑。<br />
				これを応用すれば、twitterで検索履歴をポストすることも出来そう。とっても恥ずかしいけどね。</p>
				<h3>参考サイト</h3>
				<ul>
				<li><a href="http://d.hatena.ne.jp/mzp/20070616/twitter">みずぴー日記 今日のTwitter</a></li>
				<li><a href="http://itpro.nikkeibp.co.jp/article/COLUMN/20080407/298191/?P=2">第3回 スクレイピングにチャレンジ！</a></li>
				<li><a href="http://labs.unoh.net/2007/06/python_2.html">ウノウラボ Pythonでメールを送信したい人のためのサンプル集 </a></li>
				</ul>
]]></content:encoded>
			<wfw:commentRss>http://aoshiman.net/weblog/2008/09/30/google_search_history/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PythonでYahoo!天気情報のRSSをパースしてGmailから送信する</title>
		<link>http://aoshiman.net/weblog/2008/09/21/yahoo_rss_gmail/</link>
		<comments>http://aoshiman.net/weblog/2008/09/21/yahoo_rss_gmail/#comments</comments>
		<pubDate>Sun, 21 Sep 2008 11:49:56 +0000</pubDate>
		<dc:creator>aoshiman</dc:creator>
				<category><![CDATA[Gmail]]></category>
		<category><![CDATA[feedparser]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[smtplib]]></category>

		<guid isPermaLink="false">http://aoshiman.net/weblog/?p=16</guid>
		<description><![CDATA[				最近、Web上の色々なコードを写経したり、変更を加えたりして少しずつPythonの勉強をしていますが、今回Setomitsさんのblogで拝見した天気予報の定期送信スクリプトを自分なりにアレンジし、Gmailから送信出来るように変更してみました。パースした内容の加工は何もしていません（したいけどまだ勉強中）。使用方法は、第１引数に送信先のメールアドレス、第２引数に地域コード（静岡県中部は5010）を与えます。書いたコードは下記の様になりました。
				
# coding: utf-8

to_addr = sys.argv[1]
area = sys.argv[2]

def create_contents(u):
    data = feedparser.parse(u)
    f = [data.feed.title] + [entry.title for entry in data.entries]
    s, b = f[0], f[1:]

    return '\n'.join(b), s

def create_message(from_addr, to_addr, subject, body, encoding):
    msg = MIMEText(body.encode(encoding), 'plain', encoding)
   [...]]]></description>
			<content:encoded><![CDATA[				<p>最近、Web上の色々なコードを写経したり、変更を加えたりして少しずつPythonの勉強をしていますが、今回Setomitsさんのblogで拝見した<a href="http://matatabi.homeip.net/blog/setomits/1335">天気予報の定期送信スクリプト</a>を自分なりにアレンジし、Gmailから送信出来るように変更してみました。パースした内容の加工は何もしていません（したいけどまだ勉強中）。使用方法は、第１引数に送信先のメールアドレス、第２引数に地域コード（静岡県中部は5010）を与えます。書いたコードは下記の様になりました。<span id="more-16"></span></p>
				<pre class="brush: python;">
# coding: utf-8

to_addr = sys.argv[1]
area = sys.argv[2]

def create_contents(u):
    data = feedparser.parse(u)
    f = [data.feed.title] + [entry.title for entry in data.entries]
    s, b = f[0], f[1:]

    return '\n'.join(b), s

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['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('YOUR_GMAIL_ADDRESS', 'YOUR_PASSWORD')
    s.sendmail(from_addr, to_addr, msg.as_string())
    s.close()

def main():
    from_addr = 'YOUR_GMAIL_ADDRESS'
    url = 'http://rss.weather.yahoo.co.jp/rss/days/%s.xml' % area
    body, subject = create_contents(url)
    msg = create_message(from_addr, to_addr, subject, body, 'UTF-8')
    send_via_gmail(from_addr, to_addr, msg)

if __name__ == '__main__':
    main()
</pre>
				<p><del datetime="2008-09-30T05:35:42+00:00">ここで問題（というか不思議な現象）が発生。携帯（SoftBank）やISPのアドレスに送ったメール内容はこのような感じになりますが</del><br />
				<br />
				<img src="http://aoshiman.net/weblog/wp-admin/user-images/2008092103.png" alt="webmail" /><br />
				<del datetime="2008-09-30T05:35:42+00:00">Gmailへ送った場合は途中で内容が切れてしまいます。またFromアドレスであるGmailの送信済みメール内容は、どの送信アドレスに送ったにも関わらず同じように途中で内容が切れてしまっています。</del><br />
				<br />
				<img src="http://aoshiman.net/weblog/wp-admin/user-images/2008092102.png" alt="gmail" /><br />
				<br />
				<del datetime="2008-09-30T05:35:42+00:00">とりあえずメールは携帯へ送ることになるので困りませんが、この現象については継続して調べていきます。</del><br />
				[2008年9月30日追記]<br />
				時間が掛かりましたが、コメントあったようにエンコード関係だったようで、コードの修正をしました。<br />
				[追記ここまで]</p>
				<h3>参考サイト</h3>
				<ul>
				<li><a href="http://labs.unoh.net/2007/06/python_2.html">ウノウラボ Pythonでメールを送信したい人のためのサンプル集 </a>
				</li>
				<li><a href="http://matatabi.homeip.net/blog/setomits/1335">blogSetomits 定期メール送信スクリプトのリカバリ</a></li>
				</ul>
]]></content:encoded>
			<wfw:commentRss>http://aoshiman.net/weblog/2008/09/21/yahoo_rss_gmail/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>クックパッドの話題のレシピをtwitterにPOSTするBOTを作った</title>
		<link>http://aoshiman.net/weblog/2008/08/28/cookpad_recipe/</link>
		<comments>http://aoshiman.net/weblog/2008/08/28/cookpad_recipe/#comments</comments>
		<pubDate>Thu, 28 Aug 2008 13:29:58 +0000</pubDate>
		<dc:creator>aoshiman</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[BOT]]></category>
		<category><![CDATA[cookpad]]></category>

		<guid isPermaLink="false">http://aoshiman.net/weblog/?p=15</guid>
		<description><![CDATA[				うちの家庭でなくてはならないクックパッドのレシピですが、ふと思い立ってクックパッドの話題のレシピをtwitterにPOSTするcookpad_recipeというBOTを作りました。よければfollowしてやって下さい。本家からクレーム入ったり、小遣いを減らされてサーバ代が払えなくならない限り続けます。
				作成の経緯は、pythonの勉強をしている際にどんぴしゃな情報があったので発作的に作って、レンタルサーバにアップしちゃったというのが本当のところです。
				BOTの説明
				
				クックパッドのメインページにある”話題のレシピ”からレシピタイトルとURLを取得します。
				レシピごとにtwitterにPOSTします。
				POSTは一日一回で、今のところ１７時に実施します（夕飯の献立を考える頃合いを狙ってます？）
				
				pythonの環境
				
				レンタルサーバのユーザ領域にvirtual-pythonをインストール
				python-twitterが必要（依存関係でsimplejsonも）
				HTML解析にBeautifulSoupが必要
				
				モジュールはeasy_installがあればすんなり入ります。で、作ったBOTのコードがこちら
				
import urllib2

from twitter import Api as TwitterApi
from BeautifulSoup import BeautifulSoup

TWITTER_USERNAME = 'twitterのscreen_name'
TWITTER_PASSWORD = 'password'

COOKPAD_URL = 'http://cookpad.com/'
soup = BeautifulSoup(urllib2.urlopen(COOKPAD_URL))

def fetch_data():
        for node in soup.findAll('div', {'id': 'wadai-recipe-inner'}):
                for tag in node('a', {'class': 'recipe-title'}):
   [...]]]></description>
			<content:encoded><![CDATA[				<p>うちの家庭でなくてはならない<a href="http://cookpad.com/">クックパッド</a>のレシピですが、ふと思い立ってクックパッドの話題のレシピをtwitterにPOSTする<a href="http://twitter.com/cookpad_recipe">cookpad_recipe</a>というBOTを作りました。よければfollowしてやって下さい。本家からクレーム入ったり、小遣いを減らされてサーバ代が払えなくならない限り続けます。<br />
				作成の経緯は、pythonの勉強をしている際に<a href="http://humming.via-kitchen.com/2008/05/17/python-twitte-bot/">どんぴしゃ</a>な情報があったので発作的に作って、レンタルサーバにアップしちゃったというのが本当のところです。</p>
				<h2>BOTの説明</h2>
				<ul>
				<li>クックパッドのメインページにある”話題のレシピ”からレシピタイトルとURLを取得します。</li>
				<li>レシピごとにtwitterにPOSTします。</li>
				<li>POSTは一日一回で、今のところ１７時に実施します（夕飯の献立を考える頃合いを狙ってます？）</li>
				</ul>
				<h2>pythonの環境</h2>
				<ul>
				<li>レンタルサーバのユーザ領域にvirtual-pythonをインストール</li>
				<li>python-twitterが必要（依存関係でsimplejsonも）</li>
				<li>HTML解析にBeautifulSoupが必要</li>
				</ul>
				<p>モジュールはeasy_installがあればすんなり入ります。で、作ったBOTのコードがこちら<span id="more-15"></span></p>
				<pre class="brush: python;">
import urllib2

from twitter import Api as TwitterApi
from BeautifulSoup import BeautifulSoup

TWITTER_USERNAME = 'twitterのscreen_name'
TWITTER_PASSWORD = 'password'

COOKPAD_URL = 'http://cookpad.com/'
soup = BeautifulSoup(urllib2.urlopen(COOKPAD_URL))

def fetch_data():
        for node in soup.findAll('div', {'id': 'wadai-recipe-inner'}):
                for tag in node('a', {'class': 'recipe-title'}):
                        yield tag['title'], tag['href']

def main():
        api = TwitterApi(TWITTER_USERNAME, TWITTER_PASSWORD)
        for recipe_title, recipe_url in fetch_data():
                post = u&quot;%s %s&quot; % (recipe_title, recipe_url)
                api.PostUpdate(post)

if __name__ == '__main__':
        main()
</pre>
				<p>
				コードは<a href="http://humming.via-kitchen.com/2008/05/17/python-twitte-bot/">こちらの方</a>とそっくりになってしまいましたが、オリジナルコードがすばらしいということで（汗。<br />
				それにしてもBeautifulSoupはとっても面白くて、適当なサイトを見つけてはスクレイピングの練習をしています。インタラクティブシェルで結果が即反映するので楽しいですよ。<br />
				<br />
				尚、virtual-pythonなどpython環境については後日もう少し書きたいと思います。<br />
				<br />
				[2008年12月23日追記]<br />
				クックパッドのトップページに若干の修正あったようで、それに合うようにコードを若干修正しました。</p>
				<pre class="brush: python;">
import urllib2

from twitter import Api as TwitterApi
from BeautifulSoup import BeautifulSoup

TWITTER_USERNAME = 'twitterのscreen_name'
TWITTER_PASSWORD = 'password'

COOKPAD_URL = 'http://cookpad.com'
soup = BeautifulSoup(urllib2.urlopen(COOKPAD_URL))

def fetch_data():
        for node in soup.findAll('div', {'id': 'wadai-recipe-inner'}):
                for tag in node('a', {'class': 'recipe-title'}):
                        yield tag['title'], tag['href']

def main():
        api = TwitterApi(TWITTER_USERNAME, TWITTER_PASSWORD)
        for recipe_title, recipe_url in fetch_data():
                post = u&quot;%s %s%s&quot; % (recipe_title, COOKPAD_URL, recipe_url)
                api.PostUpdate(post)

if __name__ == '__main__':
        main()
</pre>
				<p>[追記ここまで]<br />
				[2009年3月22日追記]<br />
				レシピの配信方法を、17時に一括から都度配信にしました。そこらへんについては後述します（つもり）<br />
				[追記ここまで]</p>
]]></content:encoded>
			<wfw:commentRss>http://aoshiman.net/weblog/2008/08/28/cookpad_recipe/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
