読者です 読者をやめる 読者になる 読者になる

Facebook いいねボタンの挙動を localhost で検証する

Facebook app 登録

まあしましょう

ドメイン設定が必要

app の設定で localhost とかだとなんかだめっぽかったので以下を参考にした
localhost環境で、Facebook のJavaScript APIでOAuth認証をする - Goodpic

testapp.com

この場合 Mac がローカルだからいいけど、自分の場合開発用の Ubuntu Server でやってるので Mac 側の hosts の設定は以下を参考にした。
VMware上で動くWebアプリにホスト側からアクセス | ゆーすけぶろぐ

# 開発用のVMのアドレス
192.168.56.101 local.testapp.com

そうえば hosts って設定してよしなにしたことなかった。

検証する

FQL(Facebook Query Language) を飛ばして確認する。使用ライブラリは (python)facebook-sdk

>>> import facebook
>>> g = facebook.GraphAPI('token')
>>> g
<facebook.GraphAPI object >
# Like する前
>>> g.fql('select like_count from link_stat where url="testapp.com"')
[{u'like_count': 0}]
# Like したあと
>>> g.fql('select like_count from link_stat where url="testapp.com"')
[{u'like_count': 1}]

どうやら機能していることがわかる

まあ

はい

Django でメールを送信と確認

メールを送信する。Python 標準モジュールやライブラリにもありそうだけど、Django 組み込みであるのでそれを利用する。
日本語1.4::メールの送信 — Django 1.4 documentation

つかう

ドキュメントのままです

from django.core.mail import send_mail
send_mail('Subject here', 'Here is the message.', 'from@example.com',
    ['to@example.com'], fail_silently=False)
# もうちょっとつかいまわしやすくする
message = message
subject = subject
# to 部分はリストかタプルで指定
email_from  = "atas@hoge.com"
email_to = ("noreply@hoge.com",)
send_mail(subject, message, email_from, email_to)

メールサーバーはとりあえず postfix をつかった

sudo apt-get install postfix
sudo /etc/init.d/postfix start

とどきます

ダミーサーバーをたてる

いちいち全部自分宛にやるのもうっとおしいのでなんかないかな、と思ったら python の smtpd モジュールで DebuggingServer なるものがあるらしくて、そのままつかった

# sudo しないと動かなかった。権限の問題?
sudo python -m smtpd -n -c DebuggingServer localhost:25

なんかダミーサーバーがうごいていないと思ったら、postfix が port 25 で動いてたので止めたらよかった

sudo /etc/init.d/postfix stop

内容はこんな感じ

---------- MESSAGE FOLLOWS ----------
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Subject: some message
From: noreply@hoge.com
To: atas@hoge.com
Date: Wed, 17 Apr 2001 06:37:39 -0000
Message-ID: <20130417063739.10658.62373@dev>
X-Peer: 127.0.0.1

高円寺5.5万円徒歩10分東向き部屋一人暮らし情報ください
------------ END MESSAGE ------------

ちなみに -m はモジュール、-c はコマンドってのはわかったけど -n ってなんだろう。

まあ

はい

grep/ack/ag でのエスケープがわからないなら直接文字列リテラル渡せばいいじゃない

適当にエスケープしてメタ文字消して置換しようとしたけど、正直よくわからなかった。たとえばこういうもの

Obj.objects.create(**kwargs)

こういうとき愚直に「. をエスケープして……あれ()ってクオートで囲むの……あれ……」とかやってた

別に単純な文字列のマッチでよかった

そういうときには grep なら -F, ag なら -Q というオブションがある

# grep
grep -rF "Obj.objects.create(**kwargs)" ./
# ag
ag -Q "Obj.objects.create(**kwargs)"

あとは煮るなり焼くなり

# -l でファイル出力して xrags で受け取る
ag -lQ "Obj.objects.create(**kwargs)" | xargs sed -i "s/Obj\.objects\.create(**kwargs)/oyaoya/g"

はい

真面目に正規表現で必要ならいいけど、単純な文字列置換したいだけならこの方が楽。ほんとうは sed 側も正規表現じゃなくて直接置換できるといいんだけど、 d で消して a で追加とかなのかな?ちょっと調べたけどわからなかった。

Django のコマンドを作って定期的に実行する

なんてことはないが、ちょっとハマったのでメモ

流れ

  • Django の python manage.py some_command をつくる
  • crontab に登録する

それだけなんだけど、復習も込めて

Django でカスタムコマンドをつくる

単純なスクリプトならそのまま Python のスクリプトとしてつかえばいいとおもうけど、 Django のコマンドであること、またそれらのモデルとかと連携したり、まああと意味合い的にそっちにもたせたいとかあるとき、コマンドを自作できる。
日本語 1.0::アクションを自作する — Django v1.0 documentation
英語 1.5::Writing custom django-admin commands | Django documentation | Django
英語の最新版のほうがわかりやすい。

階層をつくる

リポジトリ/プロジェクト/アプリ/ とツリー構造があるとき、INSTALLED_APPS に通っているパスで management/commands をつくる。python なので __init__.py も忘れずに。

BaseCommand クラスを継承したクラスをつくる

例だと class Command(BaseCommand) としてつくってる。クラス変数にオプションやらなんやらを設定できる。引数は optparse ベースで現状 python 2.7 だから argparse なんじゃないのとおもったけど、PyPi にはそれっぽいライブラリをつくってくれている人はいる。

実際の処理をかく

自分の場合は def handle(self, *args, **options) は main と同じような扱いにして、あとは関数に分けた。logger とかそういうバッチ処理系のなんかはよしなにした。

動かす

ファイル名が実行コマンドになっている(クラス名ではない) ので python manage.py some_command で実行できる

pyhton manage.py some_command

crontab で動かす

定期的に実行するなら crontab はまあつかう。で、登録する。それはいいが、2つハマった。

実行ユーザーの登録

実運営的にどうするかはわからないけど、実行ユーザーを管理したい場合は crontab -u user -e で登録できる。だけど Ubuntu だと sudo する必用があったっぽくて、root 権限でしか動かせないかと思ってた。そんなことはなかった。

sudo crontab -u atas -e

でよい

virtualenv 環境

普段 Python 関係の開発だと virtualenv(pyvenv) は必須だと思うけど、シェルから簡単に叩ける virtualenvwrapper を使っていた。でも、cron の登録では workon など virtualenvwrapper のコマンドは叩けないよね、ってところで少しハマってた。なので直接 virtualenv を activate すればよい

. ~/.virtualenv/dev/bin/activate

つなげる

こうなる

# m, h, d, w, m, command
* * * * * . /home/atas/.virtualenv/dev/bin/activate && cd /path/to/porject && python mamage.py some_command

もうちょっとちゃんとやるならシェルスクリプトにして

#!/bin/bash
export DJANGO_SETTINGS_MODULE=mysite.settings
. /path/to/virtualenv/dev/bin/activate
cd /path/to/src
python manage.py some_command

のほうがいいかもしれない

トラブルシューティング

Django のカスタムコマンドはつくれている前提で crontab での実行がどうなってるかがみえなかった

  • 登録っぽいことをかく
  • ログは /var/log/syslog に出るらしい
  • crontab の設定自体は /var/spool/crontab/... にあるらしい(が、実ファイルを直接触ることは基本しないらしい)
  • tmux でペインを分けてログを監視する tail -f /var/log/syslog
    • ちなみに less で表示して shift f でも同じ事できるけど、圧倒的に普段は tail -f のほうがいい感じだった
  • logger も動かしているのでそのファイルの状態も tail -f some.log してみる
  • VM で開発しているのでたぶん大丈夫だけど時刻設定は date コマンドで確認する。1分を待つのが長い。
  • ユーザーやなんやらでうごかなかったけど、結局はよく考えたら virtualenv 環境で環境のパスを実行ユーザーが見れないと困るよね*1、というようなところで解決

まあ

ある

*1:この記事をかいたときPYTHONPATH だと思ってたけど違った

Python の全角半角処理に zenhan が便利

バリデーションとか検索とか

だいたい全角半角でどうとか変換とかかませたりする。で、Python で有名なところだと zenhan というのがある。

導入

PyPi にある。うれしい。

pip install zenhan

つかう

公式にもあるけど、ヘルプ見た感じでも難しくない

import zenhan
# バイト列
s = 'Foo'
# unicode 型に変換
if isinstanc(s, str):
    s = s.decode('utf-8')
# 全角から半角に変換
s_hankaku = zenhan.z2h(s)
print(s_hankaku) # Foo

いいですね

英数字だけ変換したい

ちょっとはまったのは、日本語部分は別にそのままでいいんだけど英数字だけ変換したいしたいということだった。オプション指定すればいいだけだった

help(zenhan)

FUNCTIONS
    h2z(text, mode=7, ignore=())
            # function convert from HANKAKU to ZENKAKU
            # argument and return: unicode string

    z2h(text='', mode=7, ignore=())
            # function convert from ZENKAKU to HANKAKU
            # argument and return: unicode string

DATA
    ALL = 7
    ASCII = 1
    DIGIT = 2
    KANA = 4
    __version__ = '0.4'

VERSION
    0.4

ということで、この場合 3 をしていてやったらうまくいった

はい

ありがたや