Green Day – Wake Me Up When September Ends

アメリカのパンクバンド Green Day の 名曲 Wake Me Up When September Ends のPVは、とても美しく、哀しく、まるで映画のワンシーンのように作成されていますが、そのPVに日本語字幕を付けてくれた方がいました。感謝。

[youtube:http://jp.youtube.com/watch?v=3g_27bYN4lY]

Summer has come and passed
The innocent can never last
wake me up when september ends
like my father’s come to pass
twenty years has gone so fast
wake me up when september ends
wake me up when september ends
wake me up when september ends

9月の全てが終わった時、僕を起こしてくれ
9月が終わったら僕を起こしてくれ

ラストの訳が、とてもいいと思いました。「9月」はまだ現在進行形であり、「9月」はまだ終わっていないんですね。

グリーン・デイ ¥ 2,520
良いですね!
なーんか・・・
素晴らしい歌詞。
ほほう
ケチのつけようがないすげーアルバム

MacBookのモーションセンサーでテトリスをやってみた

昨年の11月にLet’s Note W5からMacBookにチェンジした時に、最後までMacBookとThinkpadどちらにするか悩んだのですが、Thinkpadいいなあと思ってたのはこちらの記事を以前から読んでいたから。
もちろんMacBookにも緊急モーションセンサーがあるのは知っていて、購入した時から、いつかモーションセンサーを使って何かやってみようと思っていました。で、ようやくやってみたのがこの動画です(ちょっと見難いです><)。




このblogで数回ネタとして書いていますが、このところPythonが楽しくて、今回もぜひPythonでやろうと思い、緊急モーションセンサーの挙動をPythonで取得するものを捜してたら次のサイトにたどり着きました。

MacBookの緊急モーションセンサーの情報を取得するにはAMSTrackerを使用します。インストール等については上記マイコミジャーナルのサイトをご確認下さい。AMSTrackerを次のように実行すると

AMSTracker -u 0.5

このように3つの数字が表示されます。一番左の数字が左右、真ん中の数字が垂直、右の数字が前後と、それぞれの動きを表示しています。MacBookを動かすと、それぞれの数字が動くことがわかります(終了する場合はControl-C)。
amstracker_01

また、次のように -s を付けて実行すると

AMSTracker -u 0.5 -s

0.5秒毎に数値が出力されます(終了する場合はControl-C)。
amstracker_02

この数値をPythonスクリプトで読み取り、AppleScript経由でキーストロークをコントロールしています。

AMSTracker -u 0.3 -s | python  tilt_control_osx.py

このように実行してから、ここにあるフラッシュ版テトリスを操作しています。終了はターミナル上でControl-Cを押します。
作成したコードは、へっぽこですが一応掲載させていただきます(スクリプトは何度も実行して成功しているものですが、実施は自己責任でお願いします)。
実際に実行する場合、気を付けていただきたいことは

  • AMSTracker のセンサー値の取得間隔は0.3秒にしていますが、うまくいかないようでしたら、0.1〜0.5くらいで調整してみて下さい。
  • THRESHOLD(しきい値)の数値30は私の経験に基づく数値で、それ以下にして実行すると敏感になりすぎてMacBookをコントロール出来なくなる可能性があります。
  • DOWNキーはMacBookを手前に引く(AMSTrackerの3番目の数値がプラス値になる)のですが、時々高いマイナス値が出ます。それによってDOWNコントロールをするつもりで逆にUPする場合があります。
  • コードにdebug用キーストロークをコメントアウトしてあります。そちらの挙動をターミナル上で確認してから実行するとわかりやすいかもです。

Geekな方々には、いまさら感のあるネタかもしれませんが、自分でもなんとか出来たのでうれしいです。コードに関してはもっとうまく書けると思うので、もう少し考えてみようと思います。

# 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', "w")
    script.write('tell application "System Events"\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) > THRESHOLD or abs(y) > THRESHOLD:
            if x > 0 and abs(x) > abs(y):
                run_command('keystroke(ASCII character 28)') # move left
                #run_command('keystroke "l"')
            elif x < 0 and abs(x) > abs(y):
                run_command('keystroke(ASCII character 29)') # move right
                #run_command('keystroke "r"')
            elif y > 0 and abs(y) > abs(x):
                #run_command('keystroke "d"')
                run_command('keystroke(ASCII character 31)') # move down
            elif y < 0 and abs(y) > abs(x):
                #run_command('keystroke "u"')
                run_command('keystroke(ASCII character 30)') # move up
    except KeyboardInterrupt:
        sys.exit(0)
    except:
        pass

その他参考させていただいたサイト


Pythonで1日のGoogle検索履歴の一覧を作成してGmailから送信する

今の私にとって(他の人もそうだと思いますが)、仕事プライベートに関係なく、Google検索は無くてはならないものですが、はたして1日にどのくらい検索しているのか知りたくて、リストを作成してみました。併せて前回のYahoo!天気情報のRSSと同様にGmailで送信しています。役に立つか分かりませんが、作成したコードを掲載します(スクリプトは何度も実行して成功しているものですが、実施は自己責任でお願いします)。尚、Google検索の履歴(Google Search History)はGoogleアカウントでログインしている状態で有効になります。
作成した時のポイントとしては

  • Google Search History は RSS で取得出来るので、feedparserを利用した
  • RSS は Basic認証がかかる為、urllibのFancyURLopenerを使用した
  • RSSのURLは件数のパラメータ(&num=)が無い場合、25件しか取得出来ないようなので(自分調べ)、1日で必要な件数を設定した
  • 取得出来る日時が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)
    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;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)

実際に送ってみるとこんなかんじです。これは一部分で、調べものが多いときは100件以上/日は検索していました。
Gmail

少しとはいえ、自分の検索を晒すのは恥ずかしい><。Typoとか(笑。
これを応用すれば、twitterで検索履歴をポストすることも出来そう。とっても恥ずかしいけどね。

参考サイト


PythonでYahoo!天気情報のRSSをパースしてGmailから送信する

最近、Web上の色々なコードを写経したり、変更を加えたりして少しずつPythonの勉強をしていますが、今回Setomitsさんのblogで拝見した天気予報の定期送信スクリプトを自分なりにアレンジし、Gmailから送信出来るように変更してみました。パースした内容の加工は何もしていません(したいけどまだ勉強中)。使用方法は、第1引数に送信先のメールアドレス、第2引数に地域コード(静岡県中部は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)
    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()

ここで問題(というか不思議な現象)が発生。携帯(SoftBank)やISPのアドレスに送ったメール内容はこのような感じになりますが

webmail
Gmailへ送った場合は途中で内容が切れてしまいます。またFromアドレスであるGmailの送信済みメール内容は、どの送信アドレスに送ったにも関わらず同じように途中で内容が切れてしまっています。

gmail

とりあえずメールは携帯へ送ることになるので困りませんが、この現象については継続して調べていきます。
[2008年9月30日追記]
時間が掛かりましたが、コメントあったようにエンコード関係だったようで、コードの修正をしました。
[追記ここまで]

参考サイト


クックパッドの話題のレシピをtwitterにPOSTするBOTを作った

うちの家庭でなくてはならないクックパッドのレシピですが、ふと思い立ってクックパッドの話題のレシピをtwitterにPOSTするcookpad_recipeというBOTを作りました。よければfollowしてやって下さい。本家からクレーム入ったり、小遣いを減らされてサーバ代が払えなくならない限り続けます。
作成の経緯は、pythonの勉強をしている際にどんぴしゃな情報があったので発作的に作って、レンタルサーバにアップしちゃったというのが本当のところです。

BOTの説明

  • クックパッドのメインページにある”話題のレシピ”からレシピタイトルとURLを取得します。
  • レシピごとにtwitterにPOSTします。
  • POSTは一日一回で、今のところ17時に実施します(夕飯の献立を考える頃合いを狙ってます?)

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'}):
                        yield tag['title'], tag['href']

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

if __name__ == '__main__':
        main()

コードはこちらの方とそっくりになってしまいましたが、オリジナルコードがすばらしいということで(汗。
それにしてもBeautifulSoupはとっても面白くて、適当なサイトを見つけてはスクレイピングの練習をしています。インタラクティブシェルで結果が即反映するので楽しいですよ。

尚、virtual-pythonなどpython環境については後日もう少し書きたいと思います。

[2008年12月23日追記]
クックパッドのトップページに若干の修正あったようで、それに合うようにコードを若干修正しました。

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"%s %s%s" % (recipe_title, COOKPAD_URL, recipe_url)
                api.PostUpdate(post)

if __name__ == '__main__':
        main()

[追記ここまで]
[2009年3月22日追記]
レシピの配信方法を、17時に一括から都度配信にしました。そこらへんについては後述します(つもり)
[追記ここまで]


PAGE TOP