标签

2015年2月17日星期二

Twitter实时同步到新浪微博

寒假写的这个程序。一开始天真地打算通过纯Python来实现,或者说不借助Twitter和新浪微博的官方API。整个程序的机理可以解释为,每隔一定时间间隔,从Twitter上爬取新的推文(Tweets),筛选出这一段时间内新发的推文,在新浪微博上发送。一开始因为我不打算用官方的API,所以用的是模拟新浪微博登录后调用发送的请求。

新浪微博模拟登录
微博有三个登录的站点,一般的网页版(weibo.com),智能手机访问的网页版(m.weibo.cn)和传统手机版式(weibo.cn),通过Chrome的开发者工具,我们会知道这三个机制在登录时浏览器向新浪发送的报文内容不尽相同。PC端网页版的登录最复杂,其密码和用户名均经过加密,而且在搜解决办法的时候,一些以前可行的方法都失效了,原因是新浪会改变密码的加密方式,目前使用的是RSA方式。
相比之下另外两个站点的登录方式则更简单,因为密码和用户名是不通过加密直接POST请求的,用urllib组织好报文发送即可。响应报文的Cookie可以用来后续的操作(发微博,点赞等等)。
如果只是一段时间的任务,最简单的方法是在发送报文的header中直接设置你的Cookie字段,只要用开发者工具查看你登录或是其他和浏览器交互的报文,就可以看到你的Cookie。因为要让其持久工作,有生存时间的Cookie不在考虑范围。
weibo.cn登录后只能发送文字,而m.weibo.cn支持六张图片的发送,其机制是先调用上传图片的请求,将文件上传到新浪的服务器,上传图片的请求会返回包含图片pid(或pid列表)的响应报文。微博在正式发送时连同正文和pid发送。
上面所述的办法我最终都没采用,因为模拟登录有时需要验证码(验证码的作用就是挡住我们这些机器人程序),我们需要一个能“长治久安”的办法,终究得用新浪微博提供的API。

新浪微博API
《挖掘社交网络》这本书的时候,里面在Twitter等网站上做信息获取也是直接使用官方的API。官方API优势很明显,在于方便,但也有很明显的缺点,比如频次限制,这里便有新浪微博对API频次的说明,微博的API还有等级限制,你要有获得更多数据的权限,或是增加你的频次上限,都需要通过增加认证信息或是付费的方式(一如SAE的风格)。我同步的NBA的Twitter帐号便因为发送频率过高(NBA的更新频率的确很高)而被帐号冻结。
这里讲一下一个很好的应用IFTTT。新浪微博是第一个与其建立连接的国内社交网络,它支持很多样的社交应用网络,用户可以自定义自己的Recipe(其最喜欢举的例子便是“如果明天下雨,发我一条短信”,利用天气预报的信息)。不少牛人,诸如BYvoid和禅叔伍嘉贤等等利用它来同步自己的Twitter到新浪微博。IFTTT的功能还可以很多样。
IFTTT的帐号可以很高频地发送信息,原因就是因为他们申请了较高的API级别。
新浪微博没有官方提供Python的SDK,而是推荐了廖雪峰所写的SDK。SDK的作用是进一步提供基于API的接口,这样一来程序可以更好写。转换短链接的接口很简易,只需要提供你的appkey和要转换的url即可,因此我将这部分放到了Twitter预处理的那部分。
sdk的weibo.py定义的一个很有用的类是APIClient,新浪微博的读写API均需要通过OAuth2的方式,也就是不能通过简单的用户名和密码。我们在微博授权应用访问我们的帐号时,都会出现一个认证页面,实际上就是OAuth机制的其中一环。
正因如此,我为了让程序能自动发送微博,也基于SDK进行了改进,因为SDK仍然需要一个认证页面授权的过程,我的程序则通过爬虫实现自动授权。
关于OAuth及其细节可以看阮一峰的这篇博文

Twitter这边
Twitter的信息获取实质很自由,因为不需要登录就可以访问一个人的主页。在本地测试时使用urllib2模块设置代理的函数,使程序通过GoAgent进行爬虫。
proxies = {'http': '127.0.0.1:8087', "https" : "https://127.0.0.1:8087"}
proxy_support = urllib2.ProxyHandler(proxies)
opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
Twitter的开发者帐号我无法申请,因为发现他们无法向中移动的号码发送验证码。无法使用Twitter API中的user_timeline获取推文的方式带来一个问题,如果是从首页进行爬虫,一条转发的推文(Retweet)并不包含转发的时间。如果更新间隔是五分钟,那么一条三分钟前转发的几天前的推文将被判断为几天前的内容而被筛掉,我最终没有解决这个问题的打算。(Retweet和新浪微博的转发很不相同,你不能附加任何信息,新浪微博一条转发可以相当于两条——你转发所说的话和原微博的内容)

部署
代码部署在Google App Engine上,利用GAE的cron服务可以很方便地实现定时执行,这里便引入另一个问题,GAE的cron服务,每一次的计时是在一次任务执行完毕后才开始计算的,也就是说间隔N分钟的任务,如果执行用了K分钟,那么下次检查更新将会跳过前面的时间间隔空隙。而IFTTT的同步频率比较快,却会出现一条动态被发送两次的问题。因此我的选择仍然是不理会这个误差。
这个程序的源代码可以在我的Github上看到。

这个是我同步的Techmeme帐号:
http://weibo.com/u/5521000534





没有评论 :

发表评论