老韩
27十一/070

mod_python安装及问题解决

一、先下载一份最新版本的mod_python,当前最新版是3.3.1版:

wget http://apache.mirror.phpchina.com/httpd/modpython/mod_python-3.3.1.tgz
这里要注意,只有最新版本才支持2.2.2以上的apache。

二、解包,安装:

tar xzvf mod_python-3.3.1.tgz
cd mod_python-3.3.1
./configure --with-apxs=/usr/local/apache/bin/apxs --with-python=/usr/local/python251/bin/python --with-max-locks=32 --with-python-src=/soft/Python-2.5.1/ --with-flex=/usr/bin/flex
make
make install
在make install的过程中,有可能出问题,我就是在那一步卡住了,结果害我多折腾了半天,报错如下:

/usr/bin/install -c -d /usr/local/apache/modules
/usr/bin/install -c src/mod_python.so /usr/local/apache/modules
/usr/bin/install: stat‘src/mod_python.so’失败: 没有那个文件或目录
make[1]: *** [install_dso] 错误 1
make[1]: Leaving directory `/soft/mod_python-3.3.1'
make[1]: Entering directory `/soft/mod_python-3.3.1'
cd dist && make install_py_lib
一开始还以为是mod_python和apache 2.2.2不兼容,在网上找资料找了半天,最后在mod_python官方网站找到这样一篇文章:

4.1. src/mod_python.so: No such file or directory
When running “make install” I get this:

# make install
[snip]
Performing DSO installation.

/usr/bin/install -c src/mod_python.so /usr/local/apache2/modules
/usr/bin/install: cannot stat `src/mod_python.so’: No such file or directory
make[1]: *** [install_dso] Error 1
make[1]: Leaving directory `/home/hobb/mod_python-3.0.1′
make: *** [install] Error 2
#

This is a problem with libtool. Apache comes with its own copy of libtool, and the version which comes with Apache 2.0.43 is old for some reason. To fix this problem, you need to first make sure that you a have a recent libtool (”libtool –version” should show 1.4.2 or later), then recompile Apache by first rerunning ./buildconf like this:

$ ./buildconf
$ ./configure –your-config-args
$ make clean ; make
$ make install

And finally rebuild mod_python with

$ ./configure
$ make clean ; make

文章上说是libtool版本太旧的原因,他们给出的解决方案是:重新编译apache,当时我脑子也没有转过弯来,傻乎乎地直接照着他们说的重新编译,折腾半天,问题依旧,只好继续Google,最后在一个法文站点上看到了一个让我差点当场崩溃的答案,最简单的方法是这样的:

mv /usr/local/apache/build/libtool /usr/local/apache/build/libtool.old
ln -s /usr/bin/libtool /usr/local/apache/build/libtool
方才明白,自己走了多少弯路,其实只要link一下libtool就可以了!看来mod_python的官方网站也该检讨一下他们的文档了!当然,由此得出的教训也很深刻,那就是:谨慎求解,别急于求成!

三、配置httpd.conf,使之支持python程序。

cd /usr/local/apache/conf
vi httpd.conf
添加:

LoadModule python_module modules/mod_python.so
创建一个虚拟主机:



AllowOverride All
Options Indexes FollowSymlinks MultiViews
Order allow,deny
Allow from all

ServerAdmin webmaster@handaoliang.cn
DocumentRoot /home/handaoliang/web/python
ServerName www.handaoliang.cn
ErrorLog logs/handaoliang_cn-error_log
CustomLog logs/handaoliang_cn-access_log common

然后,在此虚拟主机上加上如下三行代码:

SetHandler mod_python
PythonHandler mod_python.publisher
PythonDebug On
完成后是这个样子:



AllowOverride All
Options Indexes FollowSymlinks MultiViews
Order allow,deny
Allow from all
#允许执行python程序
SetHandler mod_python
PythonHandler mod_python.publisher
PythonDebug On

ServerAdmin webmaster@handaoliang.cn
DocumentRoot /home/handaoliang/web/python
ServerName www.handaoliang.cn
ErrorLog logs/handaoliang_cn-error_log
CustomLog logs/handaoliang_cn-access_log common

写一个脚本,测试一下:

  1. def index():
  2.   return "Welcome to handaoliang.cn"

如果一切正常,当访问http://www.handaoliang.cn时,应该会显示:Welcome to handaoliang.cn的字样。

参考资料:

Mod_python Manual:http://www.modpython.org/live/current/doc-html/

27十一/070

一个用python写的备份脚本

  实际上没什么用,纯粹拿来练练手而已。这个脚本接受命令行的输入,同时在指定的备份文件夹下面按照日期建立新的文件夹,同时允许输入备份文件的注释,注释会按照一定的规则形成文件名的一部分。

  1. #!/usr/local/python251/bin/python
  2. import sys
  3. import os
  4. import time
  5.  
  6. #如果没有输入参数,则会提示并且中断。
  7. if len(sys.argv[1:]) == 0:
  8.     print 'please input source file or directory.'
  9.     sys.exit()
  10. else:
  11.     source = ' '.join(sys.argv[1:])#按照固定的格式组成一个字符串
  12.  
  13. target_dir = '/home/handaoliang/backup/'+time.strftime('%Y%m%d')#目标文件夹
  14. #如果目标文件夹不存在,则进行创建,并且打印结果
  15. if not os.path.exists(target_dir):
  16.     os.mkdir(target_dir)#create directory.
  17.     print target_dir,'is successfully created...'
  18. #要求输入注释
  19. comment = raw_input('please input a comment:')
  20. #如果注释为家,则默认文件名为时分秒格式。
  21. if len(comment) == 0:
  22.     target_file_name = target_dir+os.sep+time.strftime('%H%M%S')+'.tar.gz'
  23. else:
  24.     target_file_name = target_dir+os.sep+time.strftime('%H%M%S')+'_'+\
  25.         comment.replace(' ','_')+'.tar.gz'
  26. #组建tar命令串
  27. tar_command = 'tar czvf %s %s'%(target_file_name,source)
  28. #通过os.system把此命令跑一遍,并根据返回结果看是否备份成功。
  29. if os.system(tar_command) == 0:
  30.     print 'sucessfully backup:',target_file_name
  31. else:
  32.     print 'backup FAILED'
6十一/070

分享三个JS原型

这三个方法都是JS里没有的,现在把它写成了原型扩展,供直接调用。

  1. /**
  2. * 用正则表达式去掉首尾空格
  3. * 对应于PHP的trim函数
  4. * 用法:string.trim();
  5. **/
  6. String.prototype.trim = function()
  7. {
  8.     return this.replace(/(^\s*)|(\s*$)/g, "");
  9. }
  10. /**
  11. * explode方法
  12. * 等同于Python里面的splite方法
  13. * 等同于PHP里的explode方法
  14. * 用法:string.explode(separators);
  15. **/
  16. String.prototype.explode = function(separators){
  17.     //inputstring = new String(inputstring);
  18.     separators = new String(separators);
  19.  
  20.     if(separators == "undefined") {
  21.         separators = " ,,|"; //如果没有separators分割符
  22.     }
  23.  
  24.     str = new Array(1); //the return
  25.     currentElement = "";
  26.     count = 0;
  27.  
  28.     for(var i=0; i < this.length; i++) { //遍历整个字符串
  29.         char = this.charAt(i);
  30.         if(separators.indexOf(char) != -1) {
  31.             else {
  32.                 str[count] = currentElement;
  33.                 count++;
  34.                 currentElement = "";
  35.             }
  36.         } else {
  37.             currentElement += char;
  38.         }
  39.     }
  40.     return str;
  41. }
  42. /**
  43. * 把所有全角字符转成半角字符。
  44. * 用法:string.toDBC();
  45. **/
  46. String.prototype.toDBC = function(){
  47.     var DBCStr = "";
  48.     for(var i=0; i<this.length; i++){
  49.         var c = this.charCodeAt(i);
  50.         if(c == 12288) {//全角空格为12288
  51.             DBCStr += String.fromCharCode(32);//转成半角空格为32
  52.             continue;
  53.         }
  54.         //其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248
  55.         if (c > 65280 && c < 65375) {
  56.             DBCStr += String.fromCharCode(c - 65248);
  57.             continue;
  58.         }
  59.         if (c > 65280 && c < 65375) {
  60.             DBCStr += String.fromCharCode(c - 65248);
  61.             continue;
  62.         }
  63.         DBCStr += String.fromCharCode(c);
  64.     }
  65.     return DBCStr;
  66. }
5十一/070

prototype1.6新特性

prototype 1.6 stable相对于前面的1.6 rc0版以及1.5版,改动还是比较大的。下面是到目前为止,我在开发中因为版本改进而碰到的问题:

一、hash->$H
1、的取值和设置值所用方法不同
看下面的例子:

  1. var myHash = $H({name:"handaoliang",gender:"males",company:"sohu.com"})
  2. alert(myHash["a"]);
  3.  
  4. //上面这行代码在1.6RC1以及1.6Stable版本上不能通过,因为这两个版本都重写了Hash类,并且使得:“The $H(object) shortcut is now completely equivalent to new Hash(object). Both always return a new object, regardless of whether the argument was an Object or another Hash. ”
  5. //下面这段代码才是正确的。
  6. alert(myHash.get("a"));
  7. //同样,在设置值方面也有所改进。

2、merge()函数应该用update函数取代:
以下代码在prototype1.6正式版里是无效的。

  1. myHash.merge({from:"china",where:"beijing"});

应该改成这样:

  1. myHash.update({from:"china",where:"beijing"});

二、1.6 RC1之后,Element下的setStyle方法允许传入一个符合CSS规则的字符串参数。比如:以前必须是这样写的:

  1. $('id').setStyle({fontSize: '12px', cssFloat: 'left', opacity: 0.5});

现在也可以写成这样了:

  1. $('id').setStyle('font-size: 12px; float: left; opacity: 0.5');

如果你有这种形式的代码:

  1. $('id').setStyle({'font-size': '12px'});

则必须替换成以下的任意一种形式:

  1. $('id').setStyle({fontSize: '12px'}); //注意这个地方,把font-size的原始形式改成了:fontSize,即凡是CSS里用“-”来表示的属性,都必须把“-”及其后面的字母替换成大写字母。我就很郁闷地被“background-color”耍了一下。在这里,“background-color”应该写成“backgroundColor”
  2. $('id').setStyle('font-size: 12px;');

文章参考:http://dev.rubyonrails.org/browser/spinoffs/prototype/tags/rel_1-6-0_rc1/CHANGELOG
http://www.prototypejs.org/2007/10/16/prototype-1-6-0-rc1-changes-to-the-class-and-event-apis-hash-rewrite-and-bug-fixes

2十一/070

python线程池的实现

由于系统初始架构的问题,一直采用单线程运行,而当我在导入大批量数据时,要去请求大量的外部数据,使得IO一直爆满,第一反应就是使用纯种池来解决。

在网上查了一下资料,发现已经有人写了相关的应用了:
http://blog.daviesliu.net/2006/10/09/234822/
后来还发现国外一个比较完善的开源的项目:
http://chrisarndt.de/en/software/python/threadpool/

写了一段测试代码,目的是去抓一批页面过来,这些操作都被分布到50个线程当中,当然,我这种测试方法不是很准,说成是一个使用例子更合适一些,而且,如果是在IO密集型的应用中,完全可以多开几个线程:

  1. import urllib2
  2. import time
  3. import socket
  4. from datetime import datetime
  5. from thread_pool import *
  6.  
  7. def main():
  8.     url_list = {"sina":"http://www.sina.com.cn",
  9.                "sohu":"http://www.sohu.com",
  10.                "yahoo":"http://www.yahoo.com",
  11.                "xiaonei":"http://www.xiaonei.com",
  12.                "qihoo":"http://www.qihoo.com",
  13.                "laohan":"http://www.laohan.org",
  14.                "eyou":"http://www.eyou.com",
  15.                "chinaren":"http://www.chinaren.com",
  16.                "douban":"http://www.douban.com",
  17.                "163":"http://www.163.com",
  18.                "daqi":"http://www.daqi.com",
  19.                "qq":"http://www.qq.com",
  20.                "baidu_1":"http://www.baidu.com/s?wd=asdfasdf",
  21.                "baidu_2":"http://www.baidu.com/s?wd=dddddddf",
  22.                "google_1":"http://www.baidu.com/s?wd=sadfas",
  23.                "google_2":"http://www.baidu.com/s?wd=sadflasd",
  24.                "hainei":"http://www.hainei.com",
  25.                "microsoft":"http://www.microsoft.com",
  26.                "wlzuojia":"http://www.wlzuojia.com"}
  27.  
  28.     #使用线程池
  29.     socket.setdefaulttimeout(10)
  30.     print 'start testing'
  31.     wm = WorkerManager(50)
  32.     for url_name in url_list.keys():
  33.         wm.add_job(do_get_con, url_name, url_list[url_name])
  34.     wm.wait_for_complete()
  35.     print 'end testing'
  36.  
  37. def do_get_con(url_name,url_link):
  38.     try:
  39.         fd = urllib2.urlopen(url_link)
  40.         data = fd.read()
  41.         f_hand = open("/tmp/ttt/%s" % url_name,"w")
  42.         f_hand.write(data)
  43.         f_hand.close()
  44.     except Exception,e:
  45.         pass
  46.  
  47. if __name__ == "__main__":
  48.     main()

thread_pool的代码(非原创,转自:http://blog.daviesliu.net/2006/10/09/234822/)

  1. import Queue, threading, sys
  2. from threading import Thread
  3. import time
  4. import urllib
  5.  
  6. # working thread
  7. class Worker(Thread):
  8.     worker_count = 0
  9.     timeout = 1
  10.     def __init__( self, workQueue, resultQueue, **kwds):
  11.         Thread.__init__( self, **kwds )
  12.         self.id = Worker.worker_count
  13.         Worker.worker_count += 1
  14.         self.setDaemon( True )
  15.         self.workQueue = workQueue
  16.         self.resultQueue = resultQueue
  17.         self.start( )
  18.  
  19.     def run( self ):
  20.         ''' the get-some-work, do-some-work main loop of worker threads '''
  21.         while True:
  22.             try:
  23.                 callable, args, kwds = self.workQueue.get(timeout=Worker.timeout)
  24.                 res = callable(*args, **kwds)
  25.                 print "worker[%2d]: %s" % (self.id, str(res) )
  26.                 self.resultQueue.put( res )
  27.                 #time.sleep(Worker.sleep)
  28.             except Queue.Empty:
  29.                 break
  30.             except :
  31.                 print 'worker[%2d]' % self.id, sys.exc_info()[:2]
  32.                 raise
  33.               
  34. class WorkerManager:
  35.     def __init__( self, num_of_workers=10, timeout = 2):
  36.         self.workQueue = Queue.Queue()
  37.         self.resultQueue = Queue.Queue()
  38.         self.workers = []
  39.         self.timeout = timeout
  40.         self._recruitThreads( num_of_workers )
  41.  
  42.     def _recruitThreads( self, num_of_workers ):
  43.         for i in range( num_of_workers ):
  44.             worker = Worker( self.workQueue, self.resultQueue )
  45.             self.workers.append(worker)
  46.  
  47.     def wait_for_complete( self):
  48.         # ...then, wait for each of them to terminate:
  49.         while len(self.workers):
  50.             worker = self.workers.pop()
  51.             worker.join( )
  52.             if worker.isAlive() and not self.workQueue.empty():
  53.                 self.workers.append( worker )
  54.         print "All jobs are are completed."
  55.  
  56.     def add_job( self, callable, *args, **kwds ):
  57.         self.workQueue.put( (callable, args, kwds) )
  58.  
  59.     def get_result( self, *args, **kwds ):
  60.         return self.resultQueue.get( *args, **kwds )
   下一页