Della解析(1):在GAE上搭建miniblog查询机器人
Aug 30th, 2009 – 3:27 pm | Python

今年三月完成了一个比较有趣的Project,Della查询机器人。半年了程序也断断续续更新,没什么气力去纠缠在这个上面了,所以也差不多是时候总结下,算是一个完整的结束吧,现在Della的版本已经是1.2,和刚开始的程序结构有了很大的变化,所以我想就直接把原理简单介绍下,也可以让自己没事回顾下。
Della1.1
不过在此之前,还是简单说说第一个版本的主要结构,如果你对此没兴趣而只是想知道怎么在GAE上搭建miniblog查询机器人的话,请直接忽视本段落以及下面一段,Della1.1是完全由python的第三方模块xmpppy实现的,XMPP是一种以XML为基础的开放式即时通讯协议,而GTalk所使用的消息传输协议与XMPP兼容,所以采用XMPP协议的一个开源Python实现xmpppy可以实现Gtalk在线操作查询功能,至于在饭否上实现查询,很简单,只要把饭否机器人加为Della机器人的好友,这样就等于绑定了饭否的信息,再根据从Gtalk上接受到的饭否信息来进行操作并返回结果,所以Della第一版是完全建立在Xmpppy上的程序,至于xmpppy具体原理我会在下一篇文章中比较详细的介绍,如果你需要详细了解Della1.1结构,也可以到Della的项目主页上下载1.1版本。
Della1.2
Della1.1在线的时间很不确定,因为没有服务器去放置基于xmpppy的Della1.1,所以只能利用闲暇时间在自己电脑上挂着,这样很不方便,所以在六月的时候抽着时间把Della的程序做了调整,原来的程序一分为二,饭否和Gtalk这两部分功能彻底分离了,也可以区别为在IM上查询和在miniblog上查询两部分,IM部分还是依据1.1的结构原理,miniblog部分则利用强大的GAE实现了24小时在线查询,这样也把Della成功移植到Twitter上了。本篇文章将简单说说怎么利用GAE实现在诸如饭否,twitter,叽歪等等miniblog上搭建自己的查询机器人:
在GAE上搭建miniblog查询机器人
言归正传,其实在GAE上搭建自己的机器人是很简单的,本例将以Della1.2的词典查询部分为例,我们将在twitter上建立一个小词典查询机器人,语言使用Python,首先你所需要准备的是:
一个Google帐号
一个Twitter帐号
然后申请一个Google app engine帐号,建立一个Application,Application名称随便取吧,这里我们姑且设置为cidian 。GAE有一个非常酷的cron功能,能实现程序定时运行,所以cidian的总体思路就是:
运行程序,查询GAE数据库中最新消息的id
利用twitter api获取此id为起始的所有消息
把信息逐条分析,符合查询格式的则把信息发送到dict.cn进行查询,并获取返回的结果
把结果再返回给twitter上的查询用户,把最近一条查询消息的id放到GAE数据库中
利用cron实现程序每分钟执行一次
程序分为三部分,主程序,封装Twitter一些功能的程序,还有查询程序,先贴Twitter部分的程序(twitter.py):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | #coding:utf-8 import re import base64 import httplib, urllib,urllib2 import time from google.appengine.ext import db class Tiwdata(db.Model): re_id=db.StringProperty() re_date=db.StringProperty() class Twitter: """Class to processing information from the twitter users""" def __init__( self ): """initializing the username and password""" self.__username="帐号名" self.__password="密码" self.__since_id="" # Twitter 采用的是base64验证 self.__authStr = base64.b64encode(self.__username + ":" + self.__password); def setMessage( self , message ): """function to set the message""" regex=r'^@帐号名 (.*)' m=re.findall(regex,message.lower()) #提取其他用户查询消息 return m def getMessage( self ): """function to return the message""" return self.__message def parseMessage( self ): since_id=self.getSinceId() #从数据库获取最新id #以since_id为参数,通过API读取新收到的所有消息 if(since_id<>""): url="https://twitter.com/statuses/mentions.xml?since_id=%s"%(since_id) else: url="https://twitter.com/statuses/mentions.xml" req = urllib2.Request(url) req.add_header("Authorization", "Basic " + self.__authStr) try: response = urllib2.urlopen(req) page=response.read() except: return [] matches = re.findall( r"""(?sx)<created_at>(.*?)</created_at>s* <id>(.*?)</id>s* <text>(.*?)</text>.*? <screen_name>(.*?)</screen_name>.*? </status> """,page) # 并将最近一条消息的id放置到数据库中 if(matches<>[]): per=Tiwdata() per.re_id=matches[0][1] per.re_date=self.parseTime(matches[0][0]) per.put() return matches def parseTime( self, time_str ): T="%a %b %d %H:%M:%S +0000 %Y" t=time.strptime(time_str,T) return time.strftime('%Y-%m-%d-%H-%M-%S', t) def sentMessage(self, message): """sent message to twitter""" headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/xml", "Authorization": "Basic " + self.__authStr} try: params = urllib.urlencode({"status": message}) req = urllib2.Request("https://twitter.com/statuses/update.xml", params, headers) response = urllib2.urlopen(req) except: pass def getSinceId( self ): msg=db.GqlQuery("SELECT * FROM Tiwdata ORDER BY re_date DESC") x=msg.count() if x: return msg[0].re_id else: return "" |
详细功能见注释,twitter.py主要实现了获取以及提取最新消息,数据库id的更新,已经发送消息到twitter的功能
下面是词典查询功能(dict.py):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #!/usr/bin/env python #coding:utf-8 import urllib2,re class Dict: """Class to get EN2CN & CN2EN translation from dict.cn""" def __init__( self, word="Della" ): """initializing the word and the url received""" self.setWord(word) self.setUrl() def setWord( self, word ): """function to set the word""" self.__word=word def setUrl(self): """function to set the url""" self.__url="http://dict.cn/ws.php?utf8=true&q=%s"%self.__word def getPage(self): """function to get the content of the web page.return the string page content""" url=self.__url try: page = urllib2.urlopen(url) page_content = page.read() page.close() except: return "" return page_content def getWord(self): """function get the info what we needed from the web page.return a list reply""" page_content=self.getPage().replace("\n"," ") page_content=unicode(page_content,"utf-8") # set the page content encoding to unicode regex=r'<def>(.*)</def>' match=re.findall( regex , page_content ) return match |
这里利用Dict.cn的词典查询api接口,getWord()获取单词查询结果。
最后是主函数(cidian.py):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #coding:utf-8 from Twitter import Twitter from Dict import Dict def getService( match ): respons=[] try: word=match[0].replace(" ","%20") dict=Dict(word) reply=dict.getWord() #获取查询结果 except: return ["服务端连接有误,请稍后再试"] if (reply==[] or cmp(reply[0],unicode("Not Found","utf-8"))==0): return ["Oops,你查询的单词不存在或输入格式有误,请检查下或输入'词典'获取帮助"] reply[0]="["+match[0]+"] "+reply[0].encode('utf-8') respons=reply return respons twitter=Twitter() receive=twitter.parseMessage() #获取所有查询信息 for y in reversed(receive): word=twitter.setMessage(y[2]) #提取用户查询消息 if(word<>[]): reply=getService( word ) # 交给Dict去处理 if(reply<>[]): for i in reversed(reply): if(i<>None): i="@"+y[3]+" "+i #y[3]为twitter上查询用户的帐号名 twitter.sentMessage(i) #将查询结果返回 |
以上就是程序的3个主要部分,最后所要做的就是让这个程序在GAE上定时运行,这样就等于不间断地处理twitter上的查询请求了,利用cron job可以很容易做到。
上传到GAE的程序需要设置好app.yaml和cron.yaml文件,具体使用可以参考GAE的文档,比如在此例中要实现程序每分钟运行一次,可以把app文件和cron文件设置如下:
application: cidian
version: 1
runtime: python
api_version: 1
handlers:
- url: /cidian
script: cidian.py
secure: never
注意app文件中的application就是你在GAE上新建app的名称
cron:
- description: daily job
url: /cidian
schedule: every 1 minutes
timezone: Asia/Shanghai
然后上传,大功告成:) 利用这种思路和网上各种应用功能遍布的api可以很容易做出一个像Della那样多功能的查询机器人,而只要有开发api的miniBlog,你就能为其制作一个机器人。
我前几天就又做了一个twitter机器人Twity,算是Della的姐妹机器人吧,呵呵,当是试手,实现了天气预报,股票查询,还有美剧节目单查询,Twity功能少,但查询的内容是全球性的,比如可以查询全球各个地方的天气~有兴趣的话可以移步这里


