11月 22

python 获取阿里OSS存储图片,在内存中处理图片

  申请了阿里的云存储OSS来存储图片。需要的时候直根据图片名,到阿里OSS中获得图片,然后切割成需要尺寸,最后返回给客户。获取后的切割操为内存操作,这样就不用占硬盘的IO了。
  Image使用的是PIL。阿里的SDK。SDK在python2.6调试报错。SDK比较古老,如报MD5的错误可以将oss_util.py开始的“import md5”修改为“from hashlib import md5”
  部分代码如下:

#!/bin/env python
# -*- coding:utf-8 -*-
# ---------------------------------------------
# Filename:    test.py
# Revision:    
# Date:        2012-11-19
# Author:      simonzhang
# Email:       simon-zzm@163.com
# Web:         www.simonzhang.net
# ---------------------------------------------
from oss import oss_api
import Image
from StringIO import StringIO

#### 阿里云OSS的基础信息 
HOST="oss.aliyuncs.com"  
ACCESS_ID = "xxxxxxxxx" 
SECRET_ACCESS_KEY = "xxxxxxxxxxxxx="
bucketName = "_photo"


#### 从阿里云存储获取图片
def get_image(_image_name):
    my_store = oss_api.OssAPI(HOST, ACCESS_ID, SECRET_ACCESS_KEY)
    res = my_store.get_object(bucketName, _image_name).read()
    #### 开始切图
    _cut_image = cut_image(res)
    return _cut_image

#### 切图部分
def cut_image(_image_data):
    _get_image = Image.open(_image_data)
    #### 切成300X300的尺寸
    tmp_image = _get_data.resize((300,300),Image.ANTIALIAS)
    #### 在内存中转换图片为string
    _tmp_file = StringIO("")
    tmp_image.save(_tmp_file, 'JPEG', quality=75)
    _tmp_file.seek(0)
    _tmp_image = _tmp_file.read()
    return _tmp_image

  测试效果还可以,一个一核的CPU,512M内存,1M带宽跑满CPU使用率10%。买台最便宜的阿里主机,直接从OSS里获取就不用再收费了。框架用的是tornado。

11月 18

tornado 使用配置文件的问题测试

  使用tornado做个能承担高负载的接口,配置部分是否要使用配置文件(ConfigParser)。现在有两个问题需要测试。第一、配置文件是否一次性加载,我可不希望,每次调用都会加载配置文件。第二、修改配置文件是否可以自动加载。在tornado中py文件可以自动加载,这样服务就不需要重启,服务也不会间断。
  首先是做一个tornado的测试页。在目录opt下建立testconfig文件夹,在testconf下编写代码。共有4个文件。

  主文件 main.py 代码如下:

#!/bin/env python
# -*- coding:utf-8 -*-
# -------------------------------------------------------------------------------
# Filename:    main.py
# Revision:    1.0
# Date:        2012-11-18
# Author:      simonzhang
# Email:       simon-zzm@163.com
# Web:         www.simonzhang.net
# -----------------------------------------------------------------------------
import tornado.ioloop
import tornado.web
from index import *
 
application = tornado.web.Application([
    (r"/", MainHandler),
])
 
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

  主文件要调用的部分 index.py 代码如下:

#!/bin/env python
# -*- coding:utf-8 -*-
# -------------------------------------------------------------------------------
# Filename:    main.py
# Revision:    1.0
# Date:        2012-11-18
# Author:      simonzhang
# Email:       simon-zzm@163.com
# Web:         www.simonzhang.net
# -----------------------------------------------------------------------------
import tornado.ioloop
import tornado.web
import ConfigParser

# 配置进行全局加载,如果是放到类中肯定每次都有IO。
cf = ConfigParser.ConfigParser()
cf.read("config.properties")
get_index_file_path = cf.get(cf.sections()[0], "path")
 
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        read_file = open(get_index_file_path, "rb").read()
        self.write("%s" % read_file)

  配置文件名为config.properties内容如下:

[context_path]
path = index.txt

  创建一个index.txt文件,在里面写点要显示的文件。

  开始编写监控配置文件IO的脚本。监控文件变化的部分详见:http://www.simonzhang.net/?p=429。还不知道watchdog能不能做到这个。
  脚本名为 watchfile.py 代码如下:

#!/bin/env python
# -*- coding:utf-8 -*-
# -------------------------------------------------------------------------------
# Filename:    watchfile.py
# Revision:    1.0
# Date:        2012-11-17
# Author:      simonzhang
# Email:       simon-zzm@163.com
# Web:         www.simonzhang.net
# -----------------------------------------------------------------------------
import re
import pyinotify

wm = pyinotify.WatchManager()
mask = pyinotify.IN_OPEN

class EventHandler(pyinotify.ProcessEvent):
    def process_IN_OPEN(self, event):
        self.rebuild(event)
    def rebuild(self, event):
        if (event.dir == False) and (event.name == 'config.properties') :
            print "open config file"

def main():
    handler = EventHandler()
    notifier = pyinotify.Notifier(wm, handler)
    wdd = wm.add_watch('/opt/testconfig',mask, rec=True,auto_add=True )
    notifier.loop()

if __name__ == "__main__":
    main()

  最终测试结果。第一、配置文件是在服务启动时一次加载。第二、配置文件不能自动加载,修改完配置文件必须要重启服务。
  使用ConfigParser来做配置文件,自然非常方便,tornado重启速度很快,但是我还是希望能自动加载,因为在几百台服务的情况下,能自动加载自然比需要重启更方便。所以当前就是把配置直接写到代码中,然后找个文件记录配置位置。之后再研究一下能不能热重启。如果大家有好的办法也烦请请告诉我一声。

11月 13

python 通过邮件服务器发送 邮件

很早写的,本来觉得意义不大,还是放上来,以备丢了。python2.6下发送通过。

#!/bin/env python
# -*- coding:utf-8 -*-
# -------------------------------------------------------------------------------
# Filename:    sendmail.py
# Revision:    1.0
# Date:        2012-7-18
# Author:      simonzhang
# Email:       simon-zzm@163.com
# Web:         www.simonzhang.net
# -------------------------------------------------------------------------------
import smtplib
from email.mime.text import MIMEText

#
mail_host = 'smtp.exmail.qq.com'
mail_user = 'XXXXXXXX'
mail_pwd = 'XXXXXXXXX'

def mail_send(content, mailto, get_sub):
    msg = MIMEText(content.encode('utf8'), _subtype='html',  _charset='utf8')
    msg['From'] = mail_user
    msg['Subject'] = u'%s' % get_sub
    msg['To'] = mailto
    try:
        s = smtplib.SMTP()
        s.connect(mail_host)
        s.login(mail_user,mail_pwd)
        s.sendmail(mail_user,[mailto],msg.as_string())
        s.close()
    except Exception ,e:
        print e
9月 27

我的 tornado 启停脚本

  之前在tornado学习中(一)中,写了一个启停的脚本,来启动多个端口,但是其中没有日志部分。我将脚本修改一下,使其能支持启动输出日志。具体可见早起笔记http://www.simonzhang.net/?p=1170

#!/bin/sh
#
# Filename:    main.sh
# Revision:    1.1
# Date:        2012-09-27
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
#
### END INIT INFO

# Source function library.
. /etc/profile

# Set the base value
listen_line=1
listen_start=8000
## info|warning|error|none   
loglevel='info'
log_file_prefix='logs/pypixshow.log'
log_file_max_size=20480

# 
CWD=`pwd`
cd $CWD

# See how we were called.
case "$1" in
  start)
        /bin/rm -rf main.port
	for (( i=0 ; i<${listen_line} ; i++)); do
            listen_port=$[${listen_start}+${i}]
            echo ${listen_port} >> main.port
            python main.py ${listen_port} ${loglevel} ${log_file_prefix} ${log_file_max_size} &
	done
        echo "start ok !"
        ;;
  stop)
        get_port_line=`/bin/cat main.port`
        for i in ${get_port_line};do
             now_pid=`/bin/ps -ef|grep ${i}|grep -v grep|awk ' ''{print $2}'`
             /bin/kill -9 $now_pid
        done
        /bin/rm -rf *.pyc
        echo "stop"
        ;;
  status)
        get_port_line=`/bin/cat main.port`
        for i in ${get_port_line};do
             now_pid=`/bin/ps -ef|grep ${i}|grep -v grep`
             if [ -z "${now_pid}" ] ; then
                 echo ${i} "is stop"
             else
                 echo ${now_pid}
             fi
        done
	;;
  restart)
	$0 stop
	$0 start
	;;
  *)
        echo $"Usage: $0 {start|stop|restart|status}"
        exit 1
esac

exit $rc

main.py 也需要修改,下面简单列出日志相关的代码。

import  tornado.options
import logging

if __name__ == "__main__":
    listen_port =  sys.argv[1]
    tornado.options.options['logging'].set(sys.argv[2])
    tornado.options.options['log_file_prefix'].set(sys.argv[3])
    tornado.options.options['log_file_max_size'].set(int(sys.argv[4]))
    tornado.options.parse_command_line()
    application.listen(listen_port)
    tornado.ioloop.IOLoop.instance().start()
9月 24

python 判断“NoneType”

  使用python+tornado,在数据库中根据用户id取用户名出错了。经查看是由于,手动删除了值,什么数据都没有取回,所以报错。这个用try是不行的,也不想用import types,搞个简单的,使用if判断一下,出错的人都叫“haha”。

_get_user_name = db_get_user(userid)
if type(_get_user_name) == type(None):
    _get_user_name = "haha"