Amazon

2011年8月23日火曜日

AttributeError: 'tuple' object has no attribute

Pythonにて。


body="anonymous"
sjis(body)

def sjis(body)
        if isinstance(body, str):
            body = body.replace(u'\u00a6', u'\u007c'), #broken bar=>vertical bar
            body = body.replace(u'\u2014', u'\u2015'), #horizontal bar=>em dash

上のコードを実行すると
   body = body.replace(u'\u2014', u'\u2015'), #horizontal bar=>em dash
AttributeError: 'tuple' object has no attribute 'replace'
エラーが出る。
タプルは値を変更できないのに変更しようとしているからエラー、という意味なのだけど
そもそもタプルなんか使ってないのに何でだろう?と考えること10秒。

replaceの行にカンマが入ってんじゃん。。。
            body = body.replace(u'\u00a6', u'\u007c'), #broken bar=>vertical bar
            body = body.replace(u'\u2014', u'\u2015'), #horizontal bar=>em dash

このカンマを消したら見事エラーも消えましたとさ。

2011年8月17日水曜日

Docomo, Softbankが使用するIP網

DoCoMoが使用するIP網

WEBアクセス時 (iモードブラウザ)

  • 210.153.84.0/24
  • 210.136.161.0/24
  • 210.153.86.0/24
  • 124.146.174.0/24
  • 124.146.175.0/24
  • 202.229.176.0/24
  • 202.229.177.0/24
  • 202.229.178.0/24

WEBアクセス時(フルブラウザ)

  • 210.153.87.0/24
注意大規模災害などでiモードセンタが故障した際は、WEBアクセス時(iモードブラウザ)と同じIPアドレス帯域からのアクセスとなる場合があります。

メール送信時(インターネット⇒iモード対応携帯電話)

  • 203.138.180.0/24
  • 203.138.181.0/24

メール受信時(iモード対応携帯電話⇒インターネット)

  • 203.138.203.0/24
注意iモードメール、iモーションメール、iショットメール利用の場合

iアプリからのHTTP通信時

原則的にWEBアクセス時(iモードブラウザ)で利用する帯域と同じ帯域となります。
  • 210.153.84.0/24
  • 210.136.161.0/24
  • 210.153.86.0/24
  • 124.146.174.0/24
  • 124.146.175.0/24
  • 202.229.176.0/24
  • 202.229.177.0/24
  • 202.229.178.0/24

iアプリからのHTTP通信時(ドコモマーケット(iモード)提供iアプリ)

  • 210.153.87.0/24

Softbankが使用するIP網

■ ゲートウェイのIPアドレス帯域について
Yahoo!ケータイにて利用するIPアドレス帯域
ソフトバンク携帯電話のYahoo!ケータイにてウェブサーバへアクセスする際、 ウェブサーバ側に通知される送信元のIPアドレスは下記の帯域内アドレスとなります。
  123.108.237.0/27
  202.253.96.224/27
  210.146.7.192/26
PCサイトブラウザにて利用するIPアドレス帯域
ソフトバンク携帯電話のPCサイトブラウザにてウェブサーバへアクセスする際、 ウェブサーバ側に通知される送信元のIPアドレスは下記の帯域内アドレスとなります。
  123.108.237.224/27
  202.253.96.0/27

2011年8月15日月曜日

Google App Engineでローカルデバッグする際に


Google App Engineをローカルテストする際に、
ローカルのDatastoreにクエリを作成したりデータを更新したりする場合、
コードで書くのがめんどくさい時は、管理画面から操作が可能。

サーバを起動してから、以下のURLにアクセスする

http://localhost:8080/_ah/admin/

管理画面のDatastore Viewerページからデータを更新する(各モデルの要素の型を変更String->Integer)コードを書いて実施したけれども、
更新に時間差があるようですぐには反映されなかった。
そこで、同じく管理画面のDatstore Adminにて消したいmodelを選択して"Delete Entries"をクリック
するとDatastore Viewerに_AE_DatastoreAdmin_Operationというタスクが生成され、
エントリを消すタスクが処理待ちキューに入る。

2011年8月14日日曜日

mixiモバイルアプリ開発(1)

mixiモバイルアプリ開発 - 一般論 -
いつものごとくGoogle App Engine (Python)で実装しているのだけど、
mixiのモバイル(携帯電話)アプリの場合、Firebugが使えないためデバッグ環境が乏しい。
FirefoxのextensionのFireMobileSimulatorを入れて、
携帯の機種(User-Agent)を切り替えて行う必要がある。

バグと戯れる(1)
さて、簡単にモバイルアプリつくってみたのだけど
モバイルアプリ内でのページの遷移方法はmixi developer centerでは以下のように書いてある

GETの場合

<a href="?url=http%3A%2F%2Fexample.com%2Ffoo%2Fbar%3Fa%3D1%26b%3D2">次のページ</a>

POSTの場合

<form action="?guid=ON&url=http%3A%2F%2Fexample.com%2Ffoo%2F" method="post">
  <input name="field1" type="text" value="value1" />
  <input type="submit" value="送信" />
</form>

要はリンク先はhrefにしろactionにしろ"?url=[エスケープ済みURL]"で記述しろとのこと。
そんなわけで早速エスケープ済みURLでGETリクエストを記述してみた
<a href="?url=http%3A%2F%2mytest.appspot.com%2Fhoge">次のページ</a>
ところが、
"只今アプリケーションサーバーでエラーが発生しています。しばらくしてから再度アクセスしてください。"
というエラーに遭遇。

デバッグしようにもmixi側ではこのメッセージのみで他は何も表示されないし、
Google App Engine側のログを見る当たりリクエストすら飛んで行ってない。
現象としてエラーが表示されている画面のURLに見慣れない"s=xxx"のクエリ文字列(93桁)がついている。
"http://ma.test.mixi.net/xxxx/?url=http%3A%2F%252mytest.appspot.com%2Fhoge&s=ZWJkZTEyMDNlNzY2MDZhN2Q5NmVmNWY2MDk....以下省略"

mixi側で勝手に変な文字列でもつけるのか?と思っていたのだけど、
どうも正しくないURLへアクセスした際に付いてくるデバックコードみたいなものっぽい。

上記のURLと自分で記述したaタグの中身をよーく見てみると一部書き変わっていることに気づく。

href="?url=http%3A%2F%2mytest.appspot.com%2Fhoge"
http://ma.test.mixi.net/xxxx/?url=http%3A%2F%252mytest.appspot.com%2Fhoge

ん?"52"ってなんだ?
あ。。。
hrefの記述の際に"/"のエスケープ文字列は"%2"ではなく"%2F"なのを書き間違えたためにエラーが発生。
おいおい、気づけよ自分(--;


バグと戯れる(2)
またまたエラー発生。
今度のエラーは
"只今アプリケーションサーバーでエラーが発生しています。しばらくしてから再度アクセスしてください。(body)"


(1)と似たエラーだが、今度は"(body)"がついてきた。

結論から言うと
Python(サーバーサイド)からHTMLのbodyタグの内容が変な場合に起こる。



*main.py*
class TestHandler(webapp.RequestHandler):  
def get(self):
        self.response.headers['Content-Type'] = 'application/xhtml+xml; charset=Shift_JIS'
        self.response.out.write('hoge')

application = webapp.WSGIApplication([
        ('/hello',TestHandler)], debug=True)

def main():
    run_wsgi_app(application)

if __name__ == '__main__':
    main()

3行目が原因なんだけど、乱暴な結果の返し方をすると怒られる。
通常はテンプレート(ここではtmpl/hello.html)を使って
*main.py*
class TestHandler(webapp.RequestHandler): 
def get(self):         self.response.headers['Content-Type'] = 'application/xhtml+xml; charset=Shift_JIS'         template_values = {             'user_info': 'hoge',             'page_num':page,         }         path = os.path.join(os.path.dirname(__file__), './tmpl/hello.html')         self.response.out.write(template.render(path, template_values))
application = webapp.WSGIApplication([         ('/hello',TestHandler)], debug=True) def main():     run_wsgi_app(application) if __name__ == '__main__':     main()

*tmpl/hello.html*
<?xml version="1.0" encoding="Shift_JIS"?>  <!DOCTYPE html PUBLIC "-//i-mode group (ja)//DTD XHTML i-XHTML(Locale/Ver.=ja/1.0) 1.0//EN" "i-xhtml_4ja_10.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" dir="ltr">     <head>         <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=Shift_JIS" />         <title>Test</title>     </head>     <body>         <div style="text-align:center">             {% if user_info %}             User Info: {{ user_info }}             {% else %}
            No user info.             {% endif %}             page_num:{{ page_num}} 
        </div>     </body> </html>

みたいに書く。


とりあえず困ったらまずはmixiのモバイル開発用コミュニティRemixLabsで確認
1)RemixLabsのコミュニティにアクセス
パートナーアカウント、またはパートナーテストアカウントでmixiにログインし、「RemixLabs」コミュニティにアクセスします。

2)RemixLabsコミュニティに参加
コミュニティTOPページにある「このコミュニティに参加」ボタンをクリックし、コミュニティに参加します。

2011年8月8日月曜日

携帯アプリを作る際に役立つ情報

今更感満載ですが、携帯電話のWebサイトを作るための情報をまとめてみます。

CSSが使用できる各キャリアのブラウザ
iモード: iモードブラウザ2.0 (i-CSS2)
au: WAP2.0 (オープンウェーブで使えるCSS
Softbank: 3GC (ソフトバンク携帯向けCSS)


 docomoユーザーエージェント情報

各キャリアで使えるHTMLタグ

iモードブラウザ2.0以降(2009年夏モデル)から外部CSS参照可能
iモードブラウザ2.0対応機種
P-07A, 08A, 09A, 01B, 02B, 03B, 04B, 05B, 06B, 02C
N-06A, 07A, 08A, 09A, 01B, 02B, 03B, 04B, 05B, 06B, 07B, 08B
F-08A, 09A, 01B, 02B, 03B, 04B, 05B, 06B, 07B, 08B, 09B, 10B, 04C, 05C, 11C
SH-05A, 06A, 07A, 08A, 01B, 02B, 03B, 04B, 05B, 06B, 07B, 08B, 09B
L-03C

○液晶表示サイズ
QVGA: 240 x NNN
VGA:  480 x NNN

○対応画像ファイル
・docomo
iモードブラウザ1.0
HTML -> GIFのみ
XHTML -> GIF, JPEG
iモードブラウザ2.0
+ PNG, BMP

au
PNG(256色), GIF, JPEG(256色), BMP

・softbank
PNG, GIF, JPEG

○サイズ制限
・au
XHTMLで記述するコンテンツは 9KB 程度以内

・Docomo

iモード対応のFOMA端末では一律100KBとなります。
iモードブラウザ2.0ではキャッシュは500KB

○キャリアのHTML/XHTML対応状況
・Docomo
MOVA: HTML
FOMA: HTML, XHTML

・au
DHTMLブラウザ HTMLのみ
WAP2.0ブラウザ(EZ Web) HTML, XHTML

・Softbank
C: HTML, MML
P: HTML, MML
3GC: HTML, XHTML

シリーズ呼称型名呼称ページサイズ制限
4-1,4-2シリーズC型6KB未満
6-5シリーズP型12-30KB未満
3Gシリーズ3GC型300KB未満


○その他
携帯サイトのスマフォへの対応

必見!携帯サイトをお手軽にiPhoneやスマートフォンに対応させる方法

1時間で携帯サイトをスマートフォン対応にする方法

Pythonで携帯の機種判別をする

 

 

2011年8月7日日曜日

Google App Engineでケータイサイトを作る際のポイント


参考:Google App Engineで、携帯サイトをつくる


○シフトJISのページを表示するには?

  1.  シフトJISで書いたテンプレートを使います(サンプルではtemplate_mobile.html)
  2.  self.response.headersを使って、ヘッダーにシフトJISである旨、情報を追加します
  3.  カスタムフィルター(サンプルではcustomfilters_m.py)を使って、テンプレートに差し込む文字列をユニコードからシフトJISに変換します

○シフトJISのページからPOSTされたデータを受け取るには?
  1.     POSTされたデータを受け取るためにself.request.get()を使っても、その結果はすでに文字化けしています
  2.     self.request.get()を使うまえに、self.request.charsetを定義します

○"~","-", "‐", "||"などの変換
上記の方法で body.encode('Shift-JIS')で変換しても以下のエラーが出る場合がある
UnicodeEncodeError: 'shift_jis' codec can't encode character u'\uff5e'
どうやらMSとUnicodeとShift-JISの間での変換マッピングにズレがあるようで、これを直す必要がある。

[参考]Pythonで「~」をエンコードすると例外が発生


サンプルコード
mobile.py
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import wsgiref.handlers, os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template

webapp.template.register_template_library('customfilters_m')

class MainPage(webapp.RequestHandler):
    def get(self):
        message = u"ようこそ、テストのサイトへ"
        template_values = {
            'message': message,
        }
        path = os.path.join(os.path.dirname(__file__), "template_mobile.html")
        self.response.headers['Content-Type'] = "text/html; charset=Shift_JIS"
        self.response.out.write(template.render(path, template_values))
    def post(self):
        self.request.charset = "Shift_JIS"
        message = self.request.get("new_message")        
        template_values = {
            'message': message,
        }
        path = os.path.join(os.path.dirname(__file__), "template_mobile.html")
        self.response.headers['Content-Type'] = "text/html; charset=Shift_JIS"
        self.response.out.write(template.render(path, template_values))

def main():
    application = webapp.WSGIApplication(
            [('/m/', MainPage)],
            debug=True)
    wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__":
    main()
customfilters_m.py
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import datetime
from google.appengine.ext import webapp

register = webapp.template.create_template_register()

def sjis(body):
body = string.replace(body, u'\uff5e', u'\u301c') # fullwidth tilde "~"
    body = string.replace(body, u'\u2015', u'\u2014') # Horizontal bar "―"
    body = string.replace(body, u'\u2225', u'\u2016') # Parallel to "||"
    body = string.replace(body, u'\uff0d', u'\u2212') # Fullwidth hyphen-minus "-"
    return body.encode('Shift_JIS')

register.filter(sjis)
template_mobile.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=SHIFT_JIS" />
<title>テスト</title>
</head>
<body>
{{ message|sjis }}
<form method="post" action="#">
<input type="text" name="new_message" /><br>
<input type="submit" value="送信"  />
</form>
</body>
</html>


○モデルに日本時刻で記録するには?
Google App Engineで以下のようにモデルをつくっておくと、データが挿入されたときに、自動的にその時の時刻が記録されていくので便利なのだが、この時刻はUTCであって日本時間ではない。UTCで記録していくのはよいとして、表示するときは、どうにかして9時間プラスしておかないとまずい。
from google.appengine.ext import db
class hoge(db.Model):
    timestamp = db.DateTimeProperty(auto_now_add=True)
解決方法

テンプレートに、与えられた時刻に9時間を足すカスタムフィルターを登録する。

(1) 以下のコードをcustomfilters.pyというファイル名で保存する。
import datetime
from google.appengine.ext import webapp
register = webapp.template.create_template_register()
def jshift(body):
    return body + datetime.timedelta(hours=9)
register.filter(jshift)
(2) メインとなるコードのほうに以下の1文を追加する。モジュールのインポートが終わったあたりがよい。
webapp.template.register_template_library('customfilters')
(3) テンプレートでは、以下のように記述する。
<p>{{ item.timestamp|jshift|date:"Y-m-d H:i" }}</p>

2011年8月6日土曜日

Aptanaで日本語HTMLが文字化け


Aptanaで日本語のHTMLファイルをShift-JISで指定しているのにIEプレビューで見ると見事に文字化け
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=Shift_JIS" />
ということで該当ファイルをナビゲーションから右クリック->プロパティ->リソース->テキストファイルエンコーディングでShift-JISを選ぼうにも選べない。

そこで直接Shift-JISと入力した所"The selected encoding is not supported"とエラーが出てしまう。



これを回避するにはAptanaのライブラリにJavaのcharsets.jarを入れる必要がある。

  • Javaの「charsets.jar」の場所 C:\Program Files\Java\jre6\lib
  • Aptanaの「charsets.jar」のコピー場所 C:\Program Files\Aptana\Aptana Studio 2.0\jre\lib
コピーしたらAptanaを再起動

2011年8月1日月曜日

Google App Engineでテンプレートを使用する際の注意点

Google App EngineではDjangoを利用することができる。
テンプレートを使う時はテンプレートフォルダを作って、そこにHTMLのひな形ファイルを作成して使用する。

ファイル構成例
tmpl/hello.html
app.yaml
main.py

class TestHandler(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'application/xhtml+xml; charset=Shift_JIS'
        template_values = {
            'app_id': "test",
            'user_info': "userinfo",
        }
  
        path = os.path.join(os.path.dirname(__file__), 'tmpl/hello.html')
        self.response.out.write(template.render(path, template_values)) 
 


但し、一つ注意するのが、テンプレートファイルは静的ファイル扱いではなくスクリプトファイル扱いとなるので、app.yamlに
- url: /tmpl
  static_dir: tmpl
ではなくて
 - url: /tmpl
  script: tmpl/(.html)
とする。
そうしないとTemplateDoesNotExist: hello.htmlというエラーが出る。

Amazon3