本文所述内容已失效,请转向用GAE同步twitter到人人网状态之二
  yegle做过一个同步twitter到人人网状态的PHP脚本,但要求有点高——必须有php-cli组件,估计大多数虚拟主机都没有。Shellex又做了一个用GAE实现的版本,这个可用性高一点,不过他的原版需要webpy和simplejson,需要上传很多东西,而且拼写有错。我改了一下,直接引用django里面的simplejson,再用webapp替换webpy,这样只需要一个文件就能实现了。
更新记录
  2010-5-16:跟随校内网更新。
  2010-4-25:跟随校内网更新。
  2010-4-10:跟随校内网更新。
  纪念冯正虎成功回国特别更新:Retweet一并同步。
使用指南
  请避免使用“记事本/notepad“编辑twitter2renren.py。
  允许同步以"@"开头的tweet:注释掉第46行,同时将第47行的缩进减小一格。
  取消同步retweet:注释掉第38, 39, 42, 43, 48, 49行。
脚本文件twitter2renren.py

#!/usr/bin/env python2.6
#coding=utf8

import Cookie
import urllib
import re
from django.utils import simplejson
from google.appengine.api import urlfetch
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

renren_usr = '你的人人网用户名'
renren_passwd = '人人网密码'
twitter_usr = '推特用户名'
twitter_passwd = '推特密码'
last_non_sync_tweet = '最后一条不需要同步的tweet的id,比如:8726641859'
last_non_sync_retweet = '8883341324'

cookie_buf = Cookie.SimpleCookie();

class Record(db.Model):
#key is twitter_usr
last_tweet = db.StringProperty(required=True)
last_retweet = db.StringProperty(required=True)

def make_cookie_header(cookie):
ret = ''
for v in cookie.values():
ret += '%s=%s;' % (v.key, v.value)
return ret

def get_tweets (usr, passwd):
record = Record.get_or_insert(twitter_usr, last_tweet=last_non_sync_tweet, last_retweet=last_non_sync_retweet)
new_timeline = []
timeline_uri = 'http://%s:%s@twitter.com/statuses/user_timeline.json?count=10&since_id=%s' % (usr, passwd, record.last_tweet)
timeline = simplejson.loads(urllib.urlopen(timeline_uri).read())
retweets_uri = 'http://%s:%s@api.twitter.com/1/statuses/retweeted_by_me.json?count=10&since_id=%s' % (usr, passwd, record.last_retweet)
retweets = simplejson.loads(urllib.urlopen(retweets_uri).read())
if len(timeline) != 0:
record.last_tweet = str(timeline[0]['id'])
if len(retweets) != 0:
record.last_retweet = str(retweets[0]['id'])
record.put()
for tweet in timeline:
if tweet['text'][0] != '@' :
new_timeline.append(tweet['text'].encode('utf8'))
for tweet in retweets:
new_timeline.append(tweet['text'].encode('utf8'))
return new_timeline

def login2renren():
verify_url = 'http://passport.renren.com/PLogin.do'
verify_data= urllib.urlencode({
'email': renren_usr,
'password': renren_passwd,
'origURL': 'http://home.renren.com/Home.do',
'domain': 'renren.com',
'formName': '',
'method': '',
'isplogin': 'true',
'submit': '登录'
})
result = urlfetch.fetch(
url=verify_url,
headers={
'Cookie':make_cookie_header(cookie_buf),
'Content-Type': 'application/x-www-form-urlencoded',
'user-agent':'Mozilla/5.0 (Linux; U; Linux i686; en-US) Gecko/20100115 Firefox/3.6',
},
method=urlfetch.POST,
payload=verify_data,
follow_redirects = False,
)
return result

def do_redirect(url, cookie):
result = urlfetch.fetch(
url=url,
headers={
'Cookie':make_cookie_header(cookie),
'Content-Type': 'application/x-www-form-urlencoded',
'user-agent':'Mozilla/5.0 (Linux; U; Linux i686; en-US) Gecko/20100115 Firefox/3.6',
},
method=urlfetch.GET,
follow_redirects = False,
)
return result

def send_status(status, cookie):
status_url = 'http://status.renren.com/'
result = urlfetch.fetch(
url=status_url,
headers={
'Cookie':make_cookie_header(cookie),
'Content-Type': 'application/x-www-form-urlencoded',
'user-agent':'Mozilla/5.0 (Linux; U; Linux i686; en-US) Gecko/20100115 Firefox/3.6',
},
method=urlfetch.GET,
)
cookie_buf = Cookie.SimpleCookie(result.headers.get('set-cookie', ''))
ticket = re.search('', result.content)
status_url = 'http://status.renren.com/doing/update.do?'
status_data = urllib.urlencode({
'c': status,
'raw': status,
'statusPage': 1,
'publisher_form_ticket': ticket.group(1),
})
result = urlfetch.fetch(
url=status_url,
headers={
'Cookie':make_cookie_header(cookie),
'Content-Type': 'application/x-www-form-urlencoded',
'user-agent':'Mozilla/5.0 (Linux; U; Linux i686; en-US) Gecko/20100115 Firefox/3.6',
'Referer': 'http://status.renren.com/'
},
method=urlfetch.POST,
payload=status_data,
)
return True

class sync(webapp.RequestHandler):
def get(self):
global cookie_buf
#get timeline
timeline = get_tweets(twitter_usr, twitter_passwd)
if len(timeline) == 0:
return 'no tweets to sync.'
#login to renren
result = login2renren()
cookie_buf = Cookie.SimpleCookie(result.headers.get('set-cookie', ''));
callback_url = result.headers.get('location','xx');
result = do_redirect(callback_url, cookie_buf)
cookie_buf = Cookie.SimpleCookie(result.headers.get('set-cookie', ''))
#post status
for tweet in timeline:
result = send_status(tweet, cookie_buf)
return 'ok'

application = webapp.WSGIApplication([('/twitter2renren', sync)])

if __name__ == "__main__":
run_wsgi_app(application)

配置文件cron.yaml,每5分钟触发一次

cron:
- description: twitter2renren
url: /twitter2renren
schedule: every 5 minutes

配置文件app.yaml,限制只有管理员才能访问/twitter2renren

application: 你的app名字
version: 8
runtime: python
api_version: 1

handlers:
- url: /twitter2renren
script: twitter2renren.py
login: admin

  另:前天刚拿到一个SAE的帐号,不知道能干点什么用……有谁知道的,请悄悄告诉我……