[Python] メール送信

Pythonでメールを送信したかったのでやってみた

基本的には以下のページのコピペなのですが、1点引っかかったのでメモ
Pythonでメールを送信したい人のためのサンプル集

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

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

def SendMail(to_addr, subject, body, from_addr=None):
if from_addr is None:
from_addr = "hoge@maesan.jp"
msg = MIMEText(body)
msg["Subject"] = subject
msg["From"] = from_addr
msg["To"] = to_addr
msg["Date"] = formatdate()

s = smtplib.SMTP()
s.sendmail(from_addr, [to_addr], msg.as_string())
s.close()

if __name__ == '__main__':
from_addr = 'hoge@maesan.jp'
to_addr = 'foo@maesan.jp'
subject = 'test mail'
body = 'test'
SendMail(to_addr, subject, body, from_addr)

これでおkだと思ってたのですが、実行すると

AttributeError: SMTP instance has no attribute ‘sock’

ってエラーがでた。

多分メールサーバーとの接続に失敗したのかなと思い、明示的にサーバーとポートを指定したら動いた。

# s = smtplib.SMTP() # ↓こんな感じに変更
s = smtplib.SMTP("localhost", 25)

参考ページ

Pythonでメールを送信したい人のためのサンプル集
[ mailman-Bugs-1315417 ] SMTP problem

Filed under: Programming,Python — maesan 11:29 AM

[Django] 同じモデルに対して複数の外部キーを設定したい

Django で同じモデルに対して複数の外部キーを設定したかったのですが、ちょとハマったのでメモ

例えば、試合モデルとチームモデルがあって、試合モデルにホームチームとアウェイチームを関連付けたい

DB的に言うとこんな感じ

CREATE TABLE `team` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`name` varchar(80) NOT NULL
);
CREATE TABLE `game` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`game_date` datetime NOT NULL,
`home_team_id` integer NOT NULL,
`away_team_id` integer NOT NULL
);

んでモデルの定義はこんな感じにしてみた

class Team(models.Model):
name = models.CharField(max_length=80)

class Game(models.Model):
game_date = models.DateTimeField()
home_team = models.ForeignKey(Team)
away_team = models.ForeignKey(Team)

んでsyncdbしてみたらこんなエラー出た

Error: One or more models did not validate:
hoge.game: Accessor for field ‘home_team’ clashes with related field ‘Team.game_set’. Add a related_name argument to the definition for ‘home_team’.
hoge.game: Accessor for field ‘away_team’ clashes with related field ‘Team.game_set’. Add a related_name argument to the definition for ‘away_team’.

しばらく悩み調べた結果related_nameを定義すればおkだった。

class Team(models.Model):
name = models.CharField(max_length=80)

class Game(models.Model):
game_date = models.DateTimeField()
home_team = models.ForeignKey(Team, related_name="home_team")
away_team = models.ForeignKey(Team, related_name="away_team")

参考ページ

Multiple Foreign Keys to same Table?

Filed under: Django,Programming,Python — maesan 1:11 AM

[Django] CSRF verification failed.

取りあえずDjangoはじめて、とりあえずformつくって、とりあえずPOSTしてみて「CSRF verification failed.」って出たらsettings.pyのMIDDLEWARE_CLASSESにdjango.middleware.csrf.CsrfResponseMiddlewareを入れとくとおk


MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.csrf.CsrfResponseMiddleware', # <-コレ
)
Filed under: Django,Programming,Python — maesan 7:30 PM

[Python] MySQLdbでDictCursorとか知らんかったし

PythonでMySQLdbつかってデータを取得する時にこんな感じにやってた
DBはこのエントリーのやつとして

import MySQLdb

con = MySQLdb.connect(db="currency", host="127.0.0.1", port=3306, user='root', passwd='root')
sql = "select target, value, inverse, created from currencies order by created desc"
cur = con.cursor()
cur.execute(sql)
row = cur.fetchone()
print row

実行結果はこんな感じでタプルで返ってくる

(‘EUR’, 0.0089999999999999993, 111.111, datetime.datetime(2010, 12, 3, 22, 4))

この場合、為替レートととろうと思ったら row[2]とかしないといけないので全く直感的じゃないよね。
で、phpのmysql_fetcharray() したときみたいな辞書(ハッシュ)で扱いたいなぁと思ったのでこんなことやってみた。

fields = [field[0] for field in cur.description]
dict_row = dict(zip(fields, row))
print dict_row

こうすると望み通り辞書でデータが扱えるようになってうれしい

{‘inverse’: 111.111, ‘target’: ‘EUR’, ‘value’: 0.0089999999999999993, ‘created’: datetime.datetime(2010, 12, 3, 22, 4)}

って満足してたら実はDictCursorって便利なのがあったらしく

from MySQLdb.cursors import DictCursor

cur = con.cursor(DictCursor)
cur.execute(sql)
row = cur.fetchone()
print row

ってやったら上のと全く同じの取得できた><

{‘inverse’: 111.111, ‘target’: ‘EUR’, ‘value’: 0.0089999999999999993, ‘created’: datetime.datetime(2010, 12, 3, 22, 4)}

参考ページ

ジャンゴ バックエンドに依存しない DictCursor
pythonのmysqldbの使い方メモ

Filed under: Programming,Python — maesan 11:36 PM

[TextMate] Portで入れたPythonで動かない

PythonのコーディングにTextMateを使い始めたのですが、command+Rで実行させた時にどうもSnow Leopardのデフォルトで入ってるPythonで動いているみたいです。
Python2.5とかPython2.6とかを使い分けたいので、Portで入れたPythonを使って欲しいのですが、python_selectで設定しても全く関係無しでデフォルトのやつで動くみたい。

試しに以下のスクリプトを実行すると

import sys
import os

print sys.version
print os.environ['PATH']


ってなってた。
どうやらPATHが素の状態のままっぽいのでちょっと無理矢理感がありますがプロジェクトの設定でPATHに/opt/local/bin:/opt/local/sbin/:/usr/bin:/bin:/usr/sbin って入れてみると


Portで入れたPythonが動作しました。

Filed under: Programming,Python — maesan 1:49 PM

PythonでKeyErrorを回避する

ハッシュ(Python的には辞書)で存在しないキーでアクセスするとKeyErrorが出ちゃう。
データは必要なのでキーの存在確認をして、存在しなかったらデフォルトの値とかを表示したい場合に

data = {}
if 'hoge' in data:
print data['hoge']
else:
print "default"

ってやればいいんだけど、getを使うと超かんたんにできちゃう

data = {}
print data.get('hoge', 'default')

で、他にもsetdefaultってのがあるらしく、表示だけじゃなくてデータをセットしたい場合に

data = {}
# getでやるならこんな感じなのを
data['hoge'] = data.get('hoge', 'default')
# setdefaultならこんな感じで書ける
data.setdefault('hoge2', 'default2')

何か気持ちイイw

Filed under: Programming,Python — maesan 10:19 PM

為替レートを取得するプログラム書いてみた

ちょっと自動で別通貨から日本円に変換する処理が必要になったのでなんとか自動で為替レートを取得できないかと試行錯誤してみた。

データソース

調べてみるとYahoo!ファイナンスやら証券会社のページをスクレイピングしてる人とか多いみたいですが、仕様が変わったりすると面倒だったり、何となく邪道な感じがしたので、為替レートをRSSで提供しているサイトを発見したのでそれをパースすることにしました。
使ったのはココ→http://xurrency.com/

方法

APIも用意されているみたいなのですが、アクセスキーを取得しないと1日10回までの制限があったり、商用利用じゃ無かったらお金はかからないっぽいのですが何となくAPIは使わずにRSSをパースすることにしました。
今回は日本円基準なのでhttp://xurrency.com/jpy/feedを使います。
最終的にはデータベースに格納することにしました。DBはこんな感じcakePHPとかで使えそうな構造にしました。

CREATE TABLE `currencies` (
`id` int(11) NOT NULL auto_increment,
`base` varchar(3) collate utf8_unicode_ci NOT NULL COMMENT '基準通貨',
`target` varchar(3) collate utf8_unicode_ci NOT NULL COMMENT '対象通貨',
`value` float NOT NULL COMMENT 'レート',
`inverse` float NOT NULL COMMENT 'レート逆数',
`created` datetime default NULL COMMENT '作成日時',
`modified` datetime default NULL COMMENT '更新日時',
PRIMARY KEY (`id`),
KEY `target` (`target`),
KEY `created` (`created`)
) ENGINE=InnoDB;

ソースコード

とりあえずサクっとPHPで作ってみた

<?php
// XML取得
$xml = file_get_contents('http://xurrency.com/jpy/feed');
// XML パーサー作ってパースする
$parser = xml_parser_create();
xml_parse_into_struct($parser, $xml, $values, $idx);
xml_parser_free($parser);

// とりあえずDB接続
$con = mysql_connect('localhost', 'root', 'root');
mysql_select_db('currency');
mysql_query('set names utf8');
// 挿入用のSQL
$sql_base = 'insert into currencies(base, target, value, inverse, created, modified)values("%s", "%s", %f, %f, "%s", now());';

$date = null;
foreach ($idx['DC:VALUE'] as $key => $val) {
if ($date == null) {
// RSSの構造によりdateが1個はじめにかぶるから1個ずらす
$date = date('Y-n-j H:i:s', strtotime($values[$idx['DC:DATE'][$key + 1]]['value']));
}
$data = array(
'value' => $values[$val]['value'],
'base' => $values[$idx['DC:BASECURRENCY'][$key]]['value'],
'target' => $values[$idx['DC:TARGETCURRENCY'][$key]]['value'],
'date' => $date,
);
$data['inverse'] = 1.0 / $data['value'];
$sql = sprintf($sql_base, $data['base'], $data['target'],
$data['value'], $data['inverse'],
$data['date']);
mysql_query($sql);
}
// おしまい
mysql_close($con);
?>

で見てもらうとわかると思うのですが、ちょっとXMLのパースの仕方が美しくない気がしません?何ていうか親子関係無視というかとりあえず上からパースしてタグ名でばらしてみましたみたいな?
なので最近お気に入りのPythonでも同じの書いてみた

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

from xml.etree.ElementTree import ElementTree
from urllib import urlopen
import MySQLdb
import datetime

# ElementTreeを生成
xml = ElementTree(file=urlopen('http://xurrency.com/jpy/feed'))
# タグ名が"{ネームスペース}:タグ名"に展開されるのでネームスペースを書いとく
rss = 'http://purl.org/rss/1.0/'
dc = 'http://purl.org/dc/elements/1.1/'

# MySQL接続
con = MySQLdb.connect(db="currency", host="127.0.0.1", port=3306, user='root', passwd='root')
# 挿入用のSQL
base_sql = 'insert into currencies(base, target, value, inverse, created, modified)values("%(base)s", "%(target)s", %(value)f, %(inverse)f, "%(date)s", now());';

# itemタグ内に為替レートを持ってるので取得してループ回す
for items in xml.findall('.//{' + rss + '}item'):
currency = {}
for item in items.getiterator():
if item.tag == '{' + dc + '}value':
currency['value'] = float(item.text)
if item.tag == '{' + dc + '}baseCurrency':
currency['base'] = item.text
if item.tag == '{' + dc + '}targetCurrency':
currency['target'] = item.text
if item.tag == '{' + dc + '}date':
currency['date'] = datetime.datetime.strptime(item.text, "%a %b %d %H:%M:%S UTC %Y")
currency['inverse'] = 1.0 / currency['value']

sql = base_sql%{'base':currency['base'], 'target':currency['target'], 'value':currency['value'], 'inverse':currency['inverse'], 'date':currency['date']}
cur = con.cursor()
cur.execute(sql)

con.commit()

そこまでこだわるような物ではないのかもしれませんが、コッチの方が構造を解析している感じがして個人的には綺麗な気がします。

まとめ

頻繁にアクセスするのも申し訳ないので、1日に1回cronで取得してデータ溜めこむ予定。なんかに使えそうだしね。
何ていうか、とりあえず円高スゲー、早く外貨口座作ってそっちにお金移さないとダメだ。ま、そんなに日本円も持ってないけどなw

Filed under: cakePHP,PHP,Programming,Python — maesan 2:37 AM  Comments (1)
 iTunes Store(Japan)
 iTunes Store(Japan)
 iTunes Store(Japan)
 iTunes Store(Japan)
 iTunes Store(Japan)