Python日記

Python Bottle Framework + Twitter BootStrap + MySQL ベース環境

いろいろな開発で利用できるPython Bottle Frameworkの初期開発環境パッケージを作ってみた。Apache WEBサーバで動作するように作成していますのでご参考ください。Bottleは使った感じがFlaskに似ています。Flaskを使っていた時期もありましたが今はBottleをメインで使っています。

そもそも毎回環境作っていると面倒くさいので最低限の機能をまとめてみました。
ワタシ的には、WEBシステムの開発依頼を受けるとほとんどは、Python Bottleで間に合っています。まれに規模が大きい時はPyramidを使う時はありますが割合的にはPyramidを使うのは2割程度で8割がBottleです。Bottleに必須で足りないのは認証とPagerとメールくらいです。これが揃えば簡単に短期間でプロトタイプが作れます。たまに事情的にPHPで仕事依頼を受ける時がありますが、結構嫌です。といっても結構PHPの割合は依然多いです。やはりPHPのほうがコードの解読性が良くないのでそこが開発上嫌なとこかな。

ページは必要最低限のものしか入っていません。login認証、トップ画面、管理画面パネルのみです。
他の進んだフレームワークのように管理画面のパネルが一気にCRUD機能を自動生成するところまではやっていないので、管理画面は水平メニューしかありません。
ただし、ORM使って簡単にデータ操作行えば管理画面は簡単に作れると思うので皆さん自作してみてください。ここまでbottleの動作ができていればbottle frameworkを使った開発は難しくありません。

Python Framework + Twitter BootStrap + MySQL ベース認証で動作します。認証はわざと難しく作っていませんので自分のアイデアで拡張・改造してみてください。

ユーザ認証はlogin:test@example.com  password:admin01 のデータがデモ用で入っています。
直接DB操作でユーザ登録を行なってください。MySQLで登録する際、MD5関数でパスワードを登録してください

Bottle,Beaker,SQLObjectはeasy_install やpipで落としてください。

同梱物)

Apache Config File –  wsgi-bottle.conf

adapter.wsgi – wsgi with apache interface

index.py –  framework top program

bottle_db.sql –  mysql  db sql create file

Twitter Bootstrap –  css/  js/ img/  view/main.tpl

その他 –  基本プログラム&ファイル

 

Dwonloadはここをクリック

Python Bottle&Cork サンプルPG

Pythonのbottle.pyというフレームワークがありますが、なかなかわかりやすく使いかってが良いのでご紹介します。
下記はWEBで自分のサイトのランクを調べるプログラム。ログインして条件入力するページへ飛び検索開始すると1分ぐらいで順位を表示します。

あらかじめbottle,bottle-cork,google,BeautifulSoup,Beakerをpipもしくはeasy_installで入れておくこと。
bottle-corkはbottleのセッション管理モジュール。あまり詳しい情報が本サイトを見てもないのでソースコードを見るのが一番わかりやすい。

尚、プログラムはadapter.wsgiを使ってApache WEBサーバと連携するようにしてください。

必要とするPGファイル

  • adapter.wsgi
  • index.py
  • admin.py
  • rank.py
  • login.py
  • make_conf.py

テンプレート(views)

  • index.tpl
  • login_form.tpl

staticファイル(static)

  • css/style.css
  • js/protoypr.js
  • js/rankget.js

confファイル(conf)

  • register.json
  • user.json
  • roles.json
adapter.cgi
# -*- coding:utf-8 -*-
import sys, os ,bottle
dirpath = os.path.dirname(os.path.abspath(__file__))
sys.path.append(dirpath)
os.chdir(dirpath)
from index import app
application = app
rank_get.js
function ajaxReq(url){
         var p1 = document.js.url.value;
         var p2 = document.js.keywords.value;
         var p3 = document.js.number.value;
         var para = new String();
         para += '&url=';
         para += p1;
         para += '&keywords=';
         para += p2;
         para += '&number=';
         para += p3;
         new Ajax.Request(url, {
                          method: "get",
                          parameters: para,
                          onSuccess:function(httpObj){
                          $("result1").innerHTML = httpObj.responseText;
                          $("result2").innerHTML = httpObj.responseXML;
                          },
                          onFailure:function(httpObj){
                          $("result1").innerHTML = "エラー及び取得順位ゼロが要因で読み込めませんでした";
                          }
                                });
     }

     Ajax.Responders.register({
         onCreate: function() {
         Element.show($('loading'));
     },

     onComplete: function() {
         Element.hide('loading');
         alert('complete');
     }
    });

   Event.observe(window, 'load', function() {
      Element.hide('loading');
    }, false);
make_conf.py
#!/usr/bin/env python
#
#
# Regenerate files in example_conf

from datetime import datetime
from cork import Cork

def populate_conf_directory():
    cork = Cork('conf', initialize=True)

    cork._store.roles['admin'] = 100
    cork._store.roles['editor'] = 60
    cork._store.roles['user'] = 50
    cork._store.save_roles()

    tstamp = str(datetime.utcnow())
    username = password = 'admin'
    cork._store.users[username] = {
        'role': 'admin',
        'hash': cork._hash(username, password),
        'email_addr': username + '@localhost.local',
        'desc': username + ' test user',
        'creation_date': tstamp
    }
    username = password = 'guest'
    cork._store.users[username] = {
        'role': 'user',
        'hash': cork._hash(username, password),
        'email_addr': username + '@localhost.local',
        'desc': username + ' test user',
        'creation_date': tstamp
    }
    cork._store.save_users()

if __name__ == '__main__':
    populate_conf_directory()
rank.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from google import search
from BeautifulSoup import BeautifulSoup
import urllib

class webRank(object):
      def __init__(self):
          self.lang = 'ja'

      def search(self,domain,mysite,words,st0,st1):
          cnt = 1
          for url in search( words ,tld=domain, lang=self.lang,start=st0, stop=st1):
                soup = BeautifulSoup(urllib.urlopen(url))
                if url.find(mysite) != -1:
                       try:
                           title =  soup.find('title').string
                       except:
                           title = ""
                       #return str(cnt) + u"位" + url + "  " + title
                       return [str(cnt),url,title]
                cnt += 1
admin.py
import bottle
from beaker.middleware import SessionMiddleware
from cork import Cork
from login import *

@bottle.route('/admin')
def admin():
    """Only administrators can see this"""
    aaa.require(role='admin', fail_redirect='/sorry_page')
    return 'Welcome administrators'

@bottle.route('/register', method='POST')
def register():
    """Users can create new accounts, but only with 'user' role"""
    username = request.POST.get('user', '')
    password = request.POST.get('pwd', '')
    email_addr = request.POST.get('email_addr', '')
    aaa.register(username, password, email_addr)
    return 'Please check your inbox.'
~
login.py
import bottle
from beaker.middleware import SessionMiddleware
from cork import Cork

# Setup Beaker middleware to handle sessions and cookies
app = bottle.default_app()
session_opts = {
        'session.type': 'cookie',
        'session.validate_key': True,
}
app = SessionMiddleware(app, session_opts)

# Use users.json and roles.json in the local example_conf directory
aaa = Cork('conf')

@bottle.route('/login', method='POST')
def login():
    username = bottle.request.POST.get('user', '')
    password = bottle.request.POST.get('pwd', '')
#    return username,password
    aaa.login(username, password, success_redirect='/', fail_redirect='/login')

@bottle.route('/login')
@bottle.view('login_form')
def login_form():
    """Serve login form"""
    return {}

@bottle.route('/logout')
def logout():
    aaa.logout(success_redirect='/login')

@bottle.route('/sorry_page')
def sorry_page():
    """Serve sorry page"""
    return '<p>Sorry, you are not authorized to perform this action</p>'
index.py
# -*- coding: utf-8 -*-
import bottle
from bottle import route, request, response, template,static_file
from beaker.middleware import SessionMiddleware
from cork import Cork
from rank import webRank
# Setup Beaker middleware to handle sessions and cookies
app = bottle.default_app()
session_opts = {
        'session.type': 'cookie',
        'session.validate_key': True,
}app = SessionMiddleware(app, session_opts)
# Use users.json and roles.json in the local example_conf directory
aaa = Cork('conf')

from login import *
from admin import *

@route('/static/<filepath:path>')
def static(filepath):
    return static_file(filepath, root="./static")

@bottle.route('/')
@bottle.view('index')
def index():
    """Only authenticated users can see this"""
    aaa.require(fail_redirect='/sorry_page')
    return {}

@bottle.route('/rank', method="GET")
@bottle.view('web_rank')
def rank():
    """Only authenticated users can see this"""
    aaa.require(fail_redirect='/sorry_page')
    web = webRank()
    words = bottle.request.GET.get('keywords', '')
    url = bottle.request.GET.get('url', '')
    stop = bottle.request.GET.get('number', '')
    result = web.search("co.jp",url,words,1,int(stop))
    return {'url':result[1],'title':result[2],'rank':result[0]}

# Web application main

def main():

    bottle.debug(True)
    # Start the Bottle webapp
    bottle.run(app=app,host="0.0.0.0", quiet=false, reloader=True)

if __name__ == "__main__":
    main()
login_form.tpl
<!doctype html>
<html lang="ja">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type">
</head>
<body>

  <div class="login_box">
      <h2>管理ページログイン</h2>
      <p>ログイン項目を入力してください</p>
      <form action="/login" method="post" name="login">
          ログイン&nbsp;&nbsp;&nbsp:<input type="text" name="user" /><br>
          パスワード:<input type="password" name="pwd" /><br>
          <button type="submit" name="submit" > LOGIN </button>
          <button type="button" class="close"> CANCEL </button>
      </form>
  </div>

</body>
</html>

WORDPRESSからAjaxでPythonへリクエスト。DBデータをJSON形式にしてAjaxへ返却

Python WSGI SCRIPTで依頼元からAjax経由でJSONで受取り、DBから引用したデータをJSONデータにして返却するサンプル。呼び出し元はWordPressなどでAjax記述で呼び出して、コールバックしたものをWordPressに表示する。尚、DBはSQLObjectのORMapperを利用しています。

WORDPRESSの固定ページ、記事に直接Javascriptを記述できないのでプラグインを導入して利用できるようにします。
尚inline-jsと言うプラグインを使用しています。
このプラグインを導入します

WORDPRESSで呼び出すAjax

[inline]
[script type="text/javascript"]
jQuery(function(){
  jQuery('#get_search_json').click(function(){
    var data = jQuery("#job").val();
    var url = '/search/get_jobs';
    jQuery.getJSON(url,
          { 'job': data }, 
          function(data){
           for(var i in data){
               for( var key in data[i]){
                    jQuery('#result').append(jQuery('<p>').html(key +': '+ data[i][key]));
               }
               jQuery('#result').append("<hr>");
           }
    });
  });
});
[/script]
[/inline]



JOBの種類:<input type="text" id="job" />
<button id="get_search_json">JOB検索</button>
<div id="result" style="border: 2px solid #595">
[結果出力]
</div>

Ajaxで裏側で呼び出すAPI(WSGI SCRIPT)  url:/search/get_jobs – index.wsgi

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import cgi
from sqlobject import *
import datetime
import json
import pprint
sqlobject_encoding="utf8"
#SQLObjectのバグでURLにcharsetをつけないと日本語コードが文字化けする。
sqlobject_url = "mysql://xxxx:xxxxxxxxxxxxxxxxx@localhost/nms_test?charset=%s" % sqlobject_encoding
sqlhub.processConnection = connectionForURI( sqlobject_url )

class Jobs(SQLObject):
      class sqlmeta:
        table = "jobs"
        fromDatabase = True

def application(environ,start_response):
      query = cgi.parse_qs(environ.get('QUERY_STRING'))
      status = '200 OK'
      response_headers = [('Content-type', 'application/json;charset=utf8')]
      listdat = []
      i = 0
      for b in  Jobs.select( Jobs.q.jobcategoryAlias == query['job'][0] ):
          if i > 4:
             break
          json_data ={'id':b.id,
                      'catch_copy':b.catchCopy,
                      'jobcategorysummary':b.jobcategorysummary,
                      'profile':b.mysummary,
                      'work_history':b.worksummary,
                      'requirement':b.description,
                      'position':b.position
                     }
          listdat.append(json_data)
          i += 1

      start_response(status,response_headers)
      data = json.dumps(listdat,indent=7,ensure_ascii=False )
      return data

WSGI SCRIPTのApache Web Serverへの設定

スクリプトは/etc/httpd/conf.d/wsgi.confへ以下のように追記します

LoadModule wsgi_module modules/mod_wsgi.so
WSGIScriptAlias /search/get_jobs /var/www/vhosts/wp2.alpscd.co.jp/index.wsgi

PythonでFeedを取ろう!

PythonでWEB作るなら、もちろんFeedを引っ張ることでしょう。NEWSとかTOPICSとか
ということで必要最低限の情報を取り出すコードを下記へペースト。

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

import feedparser
import time

fd = feedparser.parse('FEED URIパス')

#サイト名を表示
print fd.feed.title

#記事タイトルとリンクURL、日付、概要を表示
for i in range(10):
  print fd.entries[i].title
  print fd.entries[i].link
  print fd.entries[i].published
  print fd.entries[i].summary

#最新記事の更新時間
updatetime = time.strftime('%Y/%m/%d %X',fd.entries[0].published_parsed)
print updatetime

PythonでSEO調査(検索順位)

SEOをやっていると、自分のサイトの順位はどのへんなんだろう?って思いますよね。

気になるけど、最近のSEOツールは結構順位が不正確だったりします。Googleの変動が頻繁に行われているし、検索サーバが多いから同期がおいつかないのでしょう。

ということで今回はコマンドラインで、パパンと検索順位を調べる方法を掲載します。

もし、pipというツールをいれていないならこのページを参照してください(ここ CLICK)

標準でないモジュールで必要なのは2つだけ、インストールしておきます。

$ pip install google

$pip install BeautifulSoup

コードは以下の通リ。
自社のキーワードで100番以内に入っているか確認。TLDのco.jpはgoogle.co.jpの範囲で検索するという意味です。Lang=jaも日本語のサイトを対象に検索するという意味になります。後のパラメータはわかるよね!意外と便利だ!
正直言って顧客のサイトをさばくので手がいっぱいで自社のSEO全くしていない。。。(^_^;)でも33位くらいみたい。

$vi search.py

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from google import search
from BeautifulSoup import BeautifulSoup
import urllib

#search data

words = "中小企業 WEBセキュリティ"
mysite = "www.netmarvs.com"
cnt = 1
for url in search( words ,tld='co.jp', lang='ja',start=1, stop=100):
    soup = BeautifulSoup(urllib.urlopen(url))
    if url.find(mysite) != -1:
           print str(cnt) + u"位" + url + "  " + soup.find('title').text
           sys.exit()
    cnt += 1

$ chmod 755 search.py
$ ./search.py

これなら、cronバッチファイルや自分のメールに定期的に送信も簡単出来ますな!

Python WEBアプリをCGIで使う(後編:Part3)

今度はデータベースをSQL文なしで使うORマッパーを利用してデータベースを操作してみよう。
使うのはhttp://sqlobject.org/これはpythonの中でもなかなかわかりやすい
ORマッパーだと思います。CGIレベルで使うのであればこれで十分
Part1のプログラムを改造していじってみます。

まず最初に、MySQLでデータベースの器だけ用意しておきましょう。

[hidy@dev-mar01 py]$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 12374
Server version: 5.1.69 Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql> create database test_db;
Query OK, 1 row affected (0.01 sec)

mysql> use test_db
Database changed
mysql> show databases;
+——————–+
| Database |
+——————–+
| information_schema |
| mysql |
| pyramid_db |
| test_db |
+——————–+
21 rows in set (0.00 sec)

mysql>

この例ではtest_dbというデータベースを作成しました。
次に2つモジュールを導入しましょう。

$ pip install sqlobject
$ pip install MySQL-python

ソースコードを作成します。

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import string
import random
import hashlib
from sqlobject import *
import datetime

sqlhub.processConnection = connectionForURI("mysql://test:12345@localhost/test_db")

class WpUserSub(SQLObject):
    default = "CURRENT_TIMESTAMP"
    id_no = StringCol(length=6,notNone="yes",alternateID=True)
    pd_src = StringCol(length=64,notNone="yes",alternateID=True)
    enable = BoolCol(notNone="yes")
    created_at = TimestampCol()

class  Id_gen(object):
    def  __init__(self,stat):
       try:
            WpUserSub.createTable()
            self.__stat = stat
       except:
            self.__stat = stat

    def  inst(self):
       try:
           b = WpUserSub.select().max('id_no')
           b = int(b) + 1
       except:
           b = 1
       data = "%05d" % b
       pw = self.pw_gen(10)
       return {'id_no':data,'enable':self.__stat,'pd_src':pw}

    def  pw_gen(self,length):
       src = string.digits + string.letters
       s=''
       for i in range(1, length):
          s += random.choice("suhvq4v87wrnqweq3b234tb2vNN")
       s = hashlib.md5(s).hexdigest()
       return s

def main():
    p = Id_gen(1)
    print p.inst()['id_no']
    print p.inst()['enable']
    ins = WpUserSub(
        id_no = p.inst()['id_no'],
        pd_src = p.inst()['pd_src'],
        enable = p.inst()['enable'],
    )

if __name__  ==  '__main__':
    main()

導入が完了しましたら実行してみましょう。

# chmod 755 code01.py
# ./code01.py

データベースにアクセスしてテーブルができていればOK

$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 12377
Server version: 5.1.69 Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.

mysql> use test_db
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+——————-+
| Tables_in_test_db |
+——————-+
| wp_user_sub |
+——————-+
1 row in set (0.00 sec)

mysql> desc wp_user_sub;
+————+————-+——+—–+——————-+—————————–+
| Field | Type | Null | Key | Default | Extra |
+————+————-+——+—–+——————-+—————————–+
| id | int(11) | NO | PRI | NULL | auto_increment |
| id_no | varchar(6) | NO | UNI | NULL | |
| pd_src | varchar(64) | NO | UNI | NULL | |
| enable | tinyint(1) | NO | | NULL | |
| created_at | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+————+————-+——+—–+——————-+—————————–+
5 rows in set (0.00 sec)

mysql> select * from wp_user_sub;
+—-+——-+———————————-+——–+———————+
| id | id_no | pd_src | enable | created_at |
+—-+——-+———————————-+——–+———————+
| 1 | 00001 | 6eddb71104751725f6d6894d4ddb030a | 1 | 2013-07-13 22:59:05 |
+—-+——-+———————————-+——–+———————+
1 row in set (0.00 sec)

mysql>

はい、自動的にデータベースのテーブルが作成されました。ついでにデータも1件入りましたね。
んー、便利。

Python WEBアプリをCGIで使う(後編:Part2)

今回は、Twitterのショートプログラムを作って見よう。

PythonでTwitterプログラムを作る時に便利なのがTweepy。
Twitter はREST API v1.0の頃と今は違って仕様が変わっています。巷にあふれているサンプルコードは動作しないものばかりです。動作するものはREST API v1.1に対応したtweepyが必要。
ところが、これがまた不完全で使えない機能が結構ある。

本家のtweepyが糞で使えない。一部対応しているが特に検索機能はだめ!
フォークしたtweepyを”sakito”さんが作ってるのでそれをインストールします。
https://bitbucket.org/sakito/tweepy/src/4e1704b3e391?at=default

Twitter検索の仕様)
https://dev.twitter.com/docs/api/1.1/get/search/tweets

Twitter application keyの取得)
ログインしてアプリケーション登録するとキーが取得出来ます。
https://dev.twitter.com/

hgを使ってローカルに取り込みます。まずはhgがないと話にならない。
# yum install python-devel
# easy_install -U mercurial
# hg clone https://bitbucket.org/sakito/tweepy
# cd tweepy
# python setup.py install

はい、これで使えるようなりました。

検索プログラムで特定のTweetを引っ張りましょう。

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import os.path
import tweepy2
import urllib

CONSUMER_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
CONSUMER_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
ACCESS_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
ACCESS_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

# Twitter の認証を行う
auth = tweepy2.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_KEY, ACCESS_SECRET)
api = tweepy2.API(auth)

def main():
# 検索
    query = u"犬" # クエリ
    results = api.search_tweets(urllib.quote_plus(query.encode('utf-8')))

    print "Content-Type: text/html;charset=utf-8"
    print
#    print "Content-Type: application/octeat-stream"
#    print ""
    print
    print
    print "<html>"
    print "<body>"

    for result in results:
         print str(result.created_at) + "<br>"
         print result.user["name"].encode('utf-8') + "<br>"
         print result.text.encode('utf-8') + "<br>"
         print "-----------------------------------------------------------------------------------------<br>"
    print "</body>"
    print "</html>"
    print ""

if __name__  ==  '__main__':
    main()

Python WEBアプリをCGIで使う(後編:Part1)

Pythonで作業を始める前にやっておきたいのが、デフォルトのエンコードセッティング。
かならずやっておきましょう。

プログラムからやるのではなく、環境設定として行うことで文字種別に関するエラーがコレで半減する。

インストールしているpython libraryのパスにある”site-packages”配下に作成する。
通常は/usr/lib/python2.6/site-packagesがCentOSのパスです。
# vi sitecustomize.py

import sys
sys.setdefaultencoding("utf-8")

プログラムから設定するdefaultencodingの設定もあるが、呼び出しモジュール側のことも考えるとエラーに成ってしまうことも度々。だからこの設定をしておくと全体でデフォルト文字コードを設定してくれる。

それでは、必要最低限のブラウザへ表示させる簡単なコードを書いてみましょう。WEBサーバの設定は前の記事を参考にしてください。
ブラウザへ出力するには、どの言語でも共通ですがこの2行を忘れずに

print "Content-Type: text/html;charset=utf-8"
print

以下のプログラムはIDとパスワードをブラウザ上へ出力する簡単なプログラムです。例えばワードプレスで会員サイトを作ろうと思った時にIDとパスワードを大量にまとめて発行したいときなど手作業でやったら大変です。ということでそのベースとなるサンプルプログラムです。
IDは何回やっても同じですが、ここはDBにあるシーケンシャルIDの最大値を求めて最終的に作り変えればよいでしょう。PDは毎回乱数で作成しMD5で暗号化していますのでWPのユーザテーブルに直接書き込んで使えば、もちろん問題なく使えます。

仕様:
クラス IdInf_gen にIDの長さとPDの長さを指定してIDとPDを得るプログラム。
コンソールで実行しても、ブラウザで実行しても動作するプログラムです。必ず最後はアクセス権を実行権限をつけましょう。

# vi disp.py

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import string
import random
import hashlib
import datetime

#ログイン名のダミー情報
base_code ="G"
b = 1

class  IdInf_gen(object):
    def  __init__(self,len=5,pw_len=10):
       self.__len  = len
       self.__pw_len = pw_len

    def  inst(self):
       fm = "%0" + str(self.__len) + "d"
       data = fm % b
       data = base_code + data
       pw = self.pw_gen()
       return {'id':data,'pw':pw[0],'pw_org':pw[1]}

    def  pw_gen(self):
       length = self.__pw_len
       src = string.digits + string.letters
       s=''
       for i in range(1, length):
          s += random.choice("suhvq4v87wrnqweq3b234tb2vNN")
       d = hashlib.md5(s).hexdigest()
       return [d,s]

def main():
    #第一引数がIDの長さ、第二引数がパスワードの長さ`
    p = IdInf_gen(10,15)
    print "Content-Type: text/html;charset=utf-8"
    print
    print "ID:" + p.inst()['id'] + "<br>"
    print "Crypt PD:" + p.inst()['pw'] + "<br>"
    print "ORIGIN PD:" + p.inst()['pw_org'] + "<br>"

if __name__  ==  '__main__':
    main()

# chmod 755 disp.py

コンソールで確認)
# ./disp.py

ブラウザで確認)
http://yourhost/yourpath/disp.py

Python WEBアプリをCGIで使う(前編)

「Python WEBアプリをCGIで使う」は一番手軽な作り方。既に作られているプログラムの継接ぎやちょっとした機能を作るならこれで十分。
確かに簡単ですから。WEBサーバへの設定が少なくて済む。

ApacheのWEBサーバ設定は基本気をつけるのは2箇所くらい。
CGIスクリプトのパス設定とExecCGIを追加すること。WEBサーバは言語に関係なくコンテンツプログラムを拡張子.cgiにしておけば
デフォルト設定でハンドラーのあたりはOKだ。 下記に仮想ホストのサンプルを貼り付ける。

<Virtualhost *:80>

ServerName  test.example.com
ServerAdmin test@example.com
CustomLog logs/test.access_log common
ErrorLog logs/test.error_log

DocumentRoot /home/www/html/httpdocs

ScriptAlias /cgi-bin/ /home/www/html/cgi-bin/
    <Directory "/home/www/html/cgi-bin">
        AddHandler cgi-script .py .cgi
        AllowOverride None
        Options ExecCGI SymLinksIfOwnerMatch
        Order allow,deny
        Allow from all
    </Directory>
   <Directory "/home/www/html/httpdocs">
        AllowOverride All
        Options ExecCGI SymLinksIfOwnerMatch
        Order allow,deny
        Allow from all

   </Directory>
</virtualHost>

WEBアプリをPythonで作るという事は!

PythonでWEBアプリを作るというのは、方法が幾つか用意されています。

  1. Apache等のWEBサーバの数ある言語の一つとしてCGIプログラムを作る。
  2. WSGIとしてpython単独でWEBサーバ兼コンテンツとして動作
  3. WSGI ScriptとしてApacheと連携
  4. WSGIとしてApacheでラップして動作

Pythonフレームワークの場合は、2番と4番をよく使います。
開発中は2番で作業をおこない、本番で4番というパターン。

開発中はサーバを再起動しないと行けない機会がおおくなるため、2番がいいんだよね。
本番は、1台のコンピュータで複数の仮想ホストを立てる事を考えるとApacheの機能を利用するのが一番手軽。だから4番。

ネットでPython関連のプログラムサンプルは検索すると沢山出てくるが、注意が必要な事は上記のどれで動作させているかということ。
これ、WEBのコンテンツを作る場合において非常にプログラムの書き方が変わってくるので要注意です。

例えば、WEBフォームの入力をGET,POSTで取り出す時に大きな差が出てきます。またブラウザーにエコーさせるということはスクリプト
ならprintで出力しますし、サーバ系ならreturnやレンダリングエンジンでエコーします。