2012年12月11日星期二

python web框架bottle

bottle是一个python WSGI框架,简单的一个py文件,集成了router、redirect、template,request/response获取与设定等功能,下面介绍其基本使用方法。

先import相关方法,并声明Bottle对象:

from bottle import Bottle, jinja2_template as template, static_file, redirect, request, response, run
app = Bottle()

Router
利用python的decorator方法,可以声明多个URL对应一个处理函数:

@app.get('/')
@app.get('/index')
def index():
  return 'Hello bottle!'

template
template用于将后台代码与前端代码分离,增加后台代码重用:

@app.get('/login')
def login():
   return template("login.html", handler=get_site_info())

@app.post('/login')
def login_post():
   return UserService.login()

redirect
bottle提供了redirect方法用于页面跳转,如登出后跳转到登录页面:

@app.get('/log-out')
 def log_out():
   UserService.log_out()
   redirect('/login', 302)

request/response
bottle提供了request和response对象,通过这两个对象,可方便地操作请求与响应数据:

@app.get('/admin')
 def admin():
   _status = request.query.get('status', None)
   response.set_cookie('status', _status)

static_file
网页包含html、js、图片等静态内容,处理这些静态内容的请求,我们不需要编写专门的router处理,只需要将静态内容放到一个文件夹下,利用如下一段代码,即可处理所有static文件请求:

@app.get('/static/<filename:re:.*')
 def server_static_file(filename):
   return static_file(filename, root='./static/')

最后,使用run方法让我们后台服务跑起来:
run(app, host='localhost', port=8080)

Have fun!

2012年12月10日星期一

社会化评论系统 ”多说“

多说 是一个评论系统,其整合了新浪微博、豆瓣、人人等多个社交网站评论插件,原先孤立的站点文章、博文可以通过 多说 与社交网站关联起来,利用社交人气活跃站点。

多说 是个开源的评论系统,使用起来也非常简单,先在多说官网进行注册,注册完成后将获得一段代码,将该段代码粘贴到网页代码<body></body>间任意位置,就可以使用多说评论系统。效果如下:













Have fun!

2012年12月9日星期日

新浪微博开放平台应用之数据抓取

新浪微博开放平台为开发者提供了很多API,用于访问或修改各种数据,如微博、评论、话题、收藏、用户标签等。下面展示如何使用“话题”的API,对特定数据进行访问。

新浪微博中的话题,由##括起来,要访问话题数据,需用到 trends/statuses 接口,其接受以下参数:
  • source : 所申请的app_key
  • trend_name : 要抓取的话题
  • count : 抓取条目的数量

通过GET方式(或直接通过游览器),访问以下URL:
http://api.t.sina.com.cn/trends/statuses.json?count=40&source=31641035&trend_name=带上猫咪去旅行

该URL指示获取最多40条,话题包含“带上猫咪去旅行”关键字的微博数据,访问该URL后,可获得以下形式的数据:

[{
"created_at":"Fri Dec 07 23:01:47 +0800 2012",
"id":3520736712709956,
"text":"#带上猫咪去旅行图站#低调内测上线 http://t.cn/zjJypQ5",
"source":"<a href=\"http://weibo.com\" rel=\"nofollow\">新浪微博</a>",
"thumbnail_pic":"http://ww4.sinaimg.cn/thumbnail/66f77025gw1dzlk18f7r3j.jpg",
"bmiddle_pic":"http://ww4.sinaimg.cn/bmiddle/66f77025gw1dzlk18f7r3j.jpg",
"original_pic":"http://ww4.sinaimg.cn/large/66f77025gw1dzlk18f7r3j.jpg",
"user":
{"id":1727492133,
"screen_name":"bangerlee",
"name":"bangerlee",
"province":"44",
"city":"1",
"location":"广东 广州",
"gender":"m",
"created_at":"Fri Apr 09 15:12:15 +0800 2010",
}]

可以看到返回的微博数据包含了我们想要搜索的关键词#带上猫咪去旅行#,另还有微博文字内容、微博图片ip、微博用户名等信息。

通过一个python小程序,我们可以实现数据抓取:




























运行以上程序有:
linux # python get_data.py  
bangerlee
#带上猫咪去旅行图站#低调内测上线 http://t.cn/zjJypQ5
http://ww4.sinaimg.cn/thumbnail/66f77025gw1dzlk18f7r3j.jpg

Have fun!

2012年11月27日星期二

文件系统缓存控制小工具vmtouch

文件系统缓存的一个作用是加快文件读取速度,vmtouch可用于管理文件系统缓存,是个有意思的小工具。vmtouch有以下功能:
  1. 查询文件/目录有多少被载入缓存
  2. 将文件/目录载入缓存
  3. 将文件/目录从缓存中清除
  4. 锁定缓存

以下为vmtouch使用示例:

















最开始 a.txt 文件被载入到缓存中,占用84个page,共336K;使用vmtouch -e 将文件从缓存中清除;使用tail命令读取 a.txt 部分内容,再使用vmtouch进行查看,a.txt 部分内容被载入缓存,占用10个page,40K。

下面是vmtouch的具体实现:

递归查找文件:因为我们向vmtouch传入的可以是目录,最终是要操作该目录下的所有文件,而目录下可能包含目录,因而需要用到递归。vmtouch中vmtouch_crawl函数是个递归函数,若其参数path指示一个目录,则不断递归,是否是目录通过stat结构的st_mode字段判断,vmtouch_crawl函数中用到stat、opendir、readdir系统调用。

打开/映射文件:目录下每个文件最终会跳出递归调用,vmtouch_file函数被vmtouch_crawl调用,用于文件处理。vmtouch_file先判断文件类型,对链接以及过大的文件(500*1024*1024)不进行处理,调用open、mmap完成文件打开和虚拟内存映射。

查询:vmtouch_file调用mincore查询某个文件的缓存占用情况,传入系统调用mincore的第一个参数是mmap的返回值,第二个参数是文件长度值,第三个参数是指向一块pages_in_file大小的内存指针。根据mincore的查询结果,如果一个页面在内存中,则增加pages_in_core等统计值。

载入内存:要将一个文件载入缓存,对其进行读取即可,vmtouch_file中通过对mem的访问操作达到载入文件缓存的目的:







清除缓存:在linux下,清除一个文件相应的缓存可调用posix_fadvise完成,posix_fadvise函数原型如为:int posix_fadvise(int fd, off_t offset, off_t len, int advice); 传入相应文件描述符、文件大小和 POSIX_FADV_DONTNEED 标志即可完成缓存清除。

内存锁:有时候我们系统一些数据长驻内存,不被交换出去,这时我们可通过mlock调用实现,mlock第一个参数为mem,第二个参数为文件长度。

vmtouch可用于“预热”文件系统缓存,有意识地换出冷数据、控制热数据常驻内存,从而减少page fault,增加缓存命中率。

Have fun!

2012年11月22日星期四

rtags——node.js+redis实现的标签管理模块

引言
在我们游览网页时,随处可见标签的身影:
  • 进入个人微博主页,可以看到自己/他人的标签,微博系统会推送与你有相同标签的人
  • 游览博文,大多数博文有标签标记,以说明文章主旨,方便搜索和查阅
  • 网上购物,我们经常使用标签进行商品搜索,如点选 “冬装” +  “男士” + “外套” 进行衣物过滤
rtags就是一个用于标签管理的node.js模块,其使用redis的set数据结构,存放标签和相关信息。

API
rtags提供以下接口:
  1. 添加物件及其标签  Tag#add(tags, id[, fn])
  2. 查询物件的标签  Tag#queryID(id, fn)
  3. 查询两个物件共有的标签  Tag#queryID(id1, id2, fn)
  4. 查询具有特定标签的物件  Tag#queryTag(tags, fn)
  5. 删除物件的标签  Tag#delTag(tags, id[, fn])
  6. 删除物件  Tag#remove(id[, fn])
示例
首先调用 Tag#createTag 生成一个 Tag 实例,传入一个字符串指示物件的类别,比如 ‘blogs’ 指示博文,‘clothes’ 指示衣服:
 var tag = rtags.createTag('blogs');

然后添加该类别的物件和对应的标签,Tag#add 接收两个参数,第一个是物件的标签,有多个标签可用逗号隔开;第二个参数是物件的 id,以下代码中以 strs 下标为 id:

var strs = [];
strs.push('travel,photography,food,music,shopping');
strs.push('music,party,food,girl');
strs.push('mac,computer,cpu,memory,disk');
strs.push('linux,kernel,linus,1991');
strs.push('kernel,process,lock,time,linux');

strs.forEach(function(str, i){ tag.add(str, i); });

经过上面调用,redis 数据库中就有了博文标签数据,我们就可以进行相关查询了。查询某物件具有哪些标签,我们可以调用 Tag#queryID,该函数接收物件 id 和一个回调函数作为参数,查询结果作为数组存放在 ids 中:

tag
  .queryID(id = '3')
  .end(function(err, ids){
    if (err) throw err;
    console.log('Tags for "%s":', id);
    var tags = ids.join(' ');
    console.log('  - %s', tags);
  });

以上代码用于查询 id 为 ‘3’ 的博文的标签,执行该段代码,输出为:

Tags for "3":
  - kernel linux linus 1991

要查询两个物件具有哪些相同标签,同样调用 Tag#queryID,这时传入的参数应为两个物件的 id 和一个回调函数:

tag
  .queryID(id1 = '3', id2 = '4')
  .end(function(err, ids){
    if (err) throw err;
    console.log('Tags for "%s" and "%s" both have:', id1, id2);
    var tags = ids.join(' ');
    console.log('  - %s', tags);
  });

以上代码用于查询 id 为 ‘3’ 和 ‘4’ 的博文共有的标签,查询结果为:

Tags for "3" and "4" both have:
  - kernel linux

rtags 还提供根据标签搜索物件的功能,调用 Tag#queryTag,传入标签和一个回调函数,若有多个标签,可用逗号隔开:

tag
  .queryTag(tags = 'music,food')
  .end(function(err, ids){
    if (err) throw err;
    console.log('The objects own the "%s" tags:', tags);
    var id = ids.join(' ');
    console.log('  - %s', id);
    process.exit();
  });

以上代码查询同时具有 ‘music’ 和 ‘food’ 标签的博文,其输出为:

The objects own the "music,food" tags:
  - 0 1

安装
rtags通过以下命令安装,该命令会一同安装rtags依赖的redis模块:
$ npm install rtags

亦可以通过以下命令从 github 获取 rtags 源码:
$ git clone git@github.com:bangerlee/rtags.git

拉起 redis-server,安装 should 模块后,我们可以执行 rtags 源码目录下的例子:
$ cd rtags/test
$ node index.js

github地址: https://github.com/bangerlee/rtags.git
欢迎 git pull/fork/clone。

Have fun!

2012年11月16日星期五

使用libqrencode生成二维码

libqrencode用于生成QR code格式的二维码,其用C编写。相比ZXing支持一维、二维和多种编码格式,libqrencode功能更简单,只针对最常见的QR code,只能用于编码。

libqrencode提供的接口在源码qrencode.h文件中有详细说明,除了编程接口,libqrencode还提供了一个现成的程序用于生成二维码。安装libqrencode后,源码目录下生成qrencode,其用法如下:
./qrencode -s 5 -o bangerlee.png bangerlee.blogspot.com

以上命令将字符串 "bangerlee.blogspot.com" 编码为QR code二维码,其中 -s 指示二维码上黑白小块的大小(单位为像素),-o 指示生成的二维码图像文件名称。

libqrencode支持对中文进行编码。












Have fun!

2012年11月13日星期二

Node.js+MongoDB实现短域名功能——开源项目short

MongoDB是一个分布式的文档存储数据库,数据用二进制的JSON格式BSON存储。

设计一个存储博文的数据库表,如果使用关系型数据库,博文本身用一个表存储,评论用另一个单独的表存储,而使用MongoDB,评论可嵌入博文表,一篇完整的博文,其相关信息只需存放在一个表中:




















下面来看如何使用Node.js和MongoDB实现短域名功能,主要用到Node.js的Mongoose模块。

首先设计短域名在MongoDB中的保存结构,除原URL、短域名这两个字段要存储外,还可以存储生成时间、访问者等与短域名相关的信息,表结构如下:












以上URL表示缩短前的域名,hash表示短域名。

其次考虑接口,接口很简单,一个接口generate用于接收URL,返回短域名;另一个接口retrieve接收短域名,返回原URL。

最后需要设计一个hash函数实现URL与短域名关联,hash函数供generate函数调用。

generate函数:













以上用到mongoose的save接口,往mongoDB服务器保存短域名数据。

retrieve函数:










findByHash函数中,调用mongoose的findeOne接口,findeOne根据传入的hash值,在mongoDB服务器中查找相应的短域名条目。完成查找后,findByHash再调用mongoose的update接口更新短域名条目中的hits等字段。

hash函数:


hash函数很简单,一个URL通过hasher对应到一个长度为6的 [0-9a-zA-Z]字符串。

调用以上generate接口,完成 URL为 http://nodejs.org/,以及URL为 http://bangerlee.blogspot.com/ 的短域名生成后,使用mongo进行数据查询,我们可以看到:





















有了以上短域名功能,我们可以进一步搭建一个提供短域名跳转的服务器,其核心是根据hash,调用retrieve函数,从MongoDB服务器上获取相应的URL,完成域名跳转:


































执行以上服务器程序,然后在地址栏输入 http://localhost:8080/GHJwvl ,回车之后就会跳转到 http://bangerlee.blogspot.com/ 。

Have fun!