GAE牛刀小试:从twitter到9911同步消息
不是@ifire说起,还真不知道有9911这东东。与twitter, fanfou一样,9911是微博服务;来头不小,属于myspace旗下。我对9911/myspace一点尝新的兴趣也没有。@ifire问我能不能写一款将twitter的消息同步到9911的程序。经过思考,我答道,如果可以接受这两个条件,程序可以写:
- 每分钟的新消息不超过20条;
- 可以接受1分钟左右的延时;
fanfou的gtalk机器人可以完美地同步弹出好友消息更新。这一点我不知道是如何做到的。我自己的解决思路是这样的:
- 解析twitter消息,找出每条消息及其ID。
我是使用正则表达式析取所需内容的。 - 过滤掉不需要的消息(例如@开头的)。
依然是使用正则表达式做到。很简单,加一条(?!@)判断约定。 - 将符合要求的消息发布到9911上。同时将消息ID保存到数据库中,以备查询最新的消息ID。
需要说明的是,twitterAPI是使用类似于好麻烦呀自推特狐。这样的代码来保存中文的。我从网上借了一段代码,专门用来转换这种“乱码”。
将消息ID保存在数据库中,也是很有必要的。因为,如果不做上记号,每次重复读取,就会在9911上发布一大堆重复的消息。使用GQL记下消息ID,下次读取时,使用since_id函数就能只读取最新的消息。方便、经济、高效。 - 该程序每分钟执行一次。
GAE的cron jobs正好可以为我们提供这样的功能。不过,我发现windows下的Google App Engine SDK功能不如linux下的全,尤其是cron方面,至少缺乏这两种功能cron_info,update_cron。因此不得不重启到linux下完成上传。不过一旦cron同步起来之后,就不用在这方面操心了;主程序代码如有更改,直接update即可。
好了,源程序放在这里,各位看官可以自行修改、借鉴,用在需要的地方。有问题请留言,我尽量回答。
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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | #!/usr/bin/env python # -*- coding: utf-8 -*- #to ensure the utf8 encoding environment import sys default_encoding = 'utf-8' if sys.getdefaultencoding() != default_encoding: reload(sys) sys.setdefaultencoding(default_encoding) import base64 import re import time #time zone convertion import urllib from google.appengine.api import urlfetch from google.appengine.ext import db class Twitter(db.Model): id=db.StringProperty() def unescape(text): """Removes HTML or XML character references and entities from a text string. keep &, >, < in the source code. from Fredrik Lundh http://effbot.org/zone/re-sub.htm#unescape-html """ def fixup(m): text = m.group(0) if text[:2] == "&#": # character reference try: if text[:3] == "&#x": return unichr(int(text[3:-1], 16)) else: return unichr(int(text[2:-1])) except ValueError: print "erreur de valeur" pass else: # named entity try: if text[1:-1] == "amp": text = "&amp;" elif text[1:-1] == "gt": text = "&gt;" elif text[1:-1] == "lt": text = "&lt;" else: print text[1:-1] text = unichr(htmlentitydefs.name2codepoint[text[1:-1]]) except KeyError: print "keyerror" pass return text # leave as is return re.sub("&#?\w+;", fixup, text) #get one page of to user's replies def sendMsg(user,sn,msg): auth=base64.b64encode(user+":"+sn) auth='Basic '+auth msg=unescape(msg) form_fields = { "status": msg, } form_data = urllib.urlencode(form_fields) result = urlfetch.fetch(url="http://api.9911.com/statuses/update.xml", payload=form_data, method=urlfetch.POST, headers={'Authorization':auth} ) if result.status_code == 200: bk=result.content if bk.find("true"): return True else: return False def parseTwitter(user,sn="",since_id=""): if since_id: url="http://twitter.com/statuses/user_timeline/%s.xml?since_id=%s"%(user,since_id) else: url="http://twitter.com/statuses/user_timeline/%s.xml"%(user) result = urlfetch.fetch(url) if result.status_code == 200: content=result.content m= re.findall(r"(?i)<id>([^<]+)</id>\s*<text>(?!@)([^<]+)</text>", content) print "<html><body><ol>" for x in reversed(m): id=x[0] text=x[1] print "<li>",id,text,"</li><br />\n" if sendMsg("9911username","9911password",text): #input 9911 username and password here msg=Twitter() msg.id=id msg.put() print "</ol></body></html>" else: print "get twitter data error" def getLatest(): msg=db.GqlQuery("SELECT * FROM Twitter ORDER BY id DESC") x=msg.count() if x: return msg[0].id else: return "" print "" latest=getLatest() #use your own twitter user id here parseTwitter("zhasm",since_id=latest) |


(?!@):表示此处不可出现@字符。(?!…)是negative look-around,表示不允许出现某表达式。请参考正则表达式高级技巧基本概念实例详解一文。http://is.gd/15JfG
在同步消息时,会有以@开头的消息,这是回复某人的消息,不值得同步。因此需要过滤。该表达式只匹配不是以@开头的消息。
reversed函数:由于读取的twitter消息是从上到下读取,顺序是从新到旧;在向9911发送时,需要以从旧到新的顺序,才能与twitter顺序一致。该函数是将list逆向排序。
看你的正则表达式是一种享受,但我自己却一直未能把握要领。上面代码中有两处不明白,可否帮我解惑?
1、在这句中 r"(?i)<id>([^<]+)</id>s*<text>(?!@)([^<]+)</text>" ,有(?!@)这个式子,不知道其中?!的作用是什么?
2、for x in reversed(m)中,reversed函数作用是什么?
谢谢!
看你的正则表达式是一种享受,但我自己却一直未能把握要领。上面代码中有两处不明白,可否帮我解惑?
1、在这句中 r"(?i)<id>([^<]+)</id>s*<text>(?!@)([^<]+)</text>" ,有(?!@)这个式子,不知道其中?!的作用是什么?
2、for x in reversed(m)中,reversed函数作用是什么?
谢谢!
看你的正则表达式是一种享受,但我自己却一直未能把握要领。上面代码中有两处不明白,可否帮我解惑?
1、在这句中 r"(?i)<id>([^<]+)</id>s*<text>(?!@)([^<]+)</text>" ,有(?!@)这个式子,不知道其中?!的作用是什么?
2、for x in reversed(m)中,reversed函数作用是什么?
谢谢!
看你的正则表达式是一种享受,但我自己却一直未能把握要领。上面代码中有两处不明白,可否帮我解惑?
1、在这句中 r"(?i)<id>([^<]+)</id>s*<text>(?!@)([^<]+)</text>" ,有(?!@)这个式子,不知道其中?!的作用是什么?
2、for x in reversed(m)中,reversed函数作用是什么?
谢谢!
(?!@):表示此处不可出现@字符。(?!…)是negative look-around,表示不允许出现某表达式。请参考正则表达式高级技巧基本概念实例详解一文。http://iregex.org/blog/crucial-concepts-behind-ad...
在同步消息时,会有以@开头的消息,这是回复某人的消息,不值得同步。因此需要过滤。该表达式只匹配不是以@开头的消息。
明白了,謝謝
请教,我不是程序员,也可能用GAE加上你这个代码将我的Twitter同步到我的9911吗?可否赐教下实现的步骤?
我已经“Application Registered Successfully”,下一步不知道怎么弄了
刚又下载并安装了GoogleAppEngine_1.2.4.msi,但是不知道怎么搞。
我在出差,暂不方便。加我gtalk吧,下周三可以线上联系。rex[at]zhasm[dot]com
看了你的同步新浪微博的文章,是否用本文中的代码替换那篇文章的main.py,就可同步9911了。
对。原理一样,架构也一样。
搞定了,谢谢
嘀嗒的服务可以的,直接从twitter网页更新,同步到hellotxt,hellotxt可以同步其他的微博,不过嘀嗒正在申请OpenCloud,应该不久能实现twitter网页同步到其他微博。