喜欢玩新浪微博的同学应该都知道最近有个叫“古城钟楼”微博因为其一到整点就发条微博报时而爆红网络,网友都感叹其是史上最无聊又最有毅力的微博。作为一个微博控的我,看着“古城钟楼”和“big_ben_clock”这种机器人微博竟然也能火起来,就想自己也来玩玩,琢磨了下花了一天时间把它实现了,于是“成信钟楼”整点报时微博就诞生了。目前“成信钟楼”可以24小时整点报时,并上传当前时间图片和显示钟楼所在地图位置,围观地址:http://weibo.com/CUITClock 。
网上说“古城钟楼”的程序至少有3万行,其中使用了AmazonEC2 和 MicrosoftAzure云服务, Redis, RabbitMQ, JSON, WebService,还专门做了个网站支持钟楼的运行。“成信钟楼”没有用到这么多高深的技术,仅用了Python + SAE。本来是用的OpenShift的,但OpenShift 被墙,22端口经常连不上,所以还是放弃了。
Python是一门面向对象的编程语言。OpenShift是红帽公司推出的,一个面向开源开发人员开放的平台即服务(PaaS)。红帽OpenShift提供比任何PaaS更多的灵活性,它支持用于Java、Python、PHP、Perl和Ruby的更多的开发框架,包括 Spring、Seam、Weld、CDI、Rails、Rack、Symfony、Zend Framework、Twisted、Django和Java E。它包含SQL和NoSQL数据存储和一个分布式文件系统,很强大,作为免费云平台空间确实很好,推荐给大家,官网地址:https://openshift.redhat.com/app/ 。
__实现原理__:
当然一切都是调用微博开放平台的API接口(http://open.weibo.com/wiki/API%E6%96%87%E6%A1%A3_V2 ),平台还提供了各平台和语言的SDK。“成信钟楼”没有用到SDK,采用自己编码调用API接口。
发微博很简单,请求https://api.weibo.com/2/statuses/update.json 或者https://upload.api.weibo.com/2/statuses/upload.json ,前者是直接发布微博文字信息,后者是上传一张图片的同时发布一条微博,给出对应要求的参数发起HTTP请求即可。调用前需要进行微博授权,据说现在微博对于开发者的帐号是永久不过期,但是为了以防万一,我仍然让他每次报时都去授权,而要24小时报时仅在自己电脑上是不现实的,总会到关机睡觉的时候,所以就要借助SAE做服务器了。用Python发微博,采用Django部署一个网站,通过请求特定url来调用发微博函数。而整点报时则采用Cron实现。其中显示地理位置只需在Google地图上找出钟楼具体位置,然后作为API的参数传递给请求函数即可显示。而来自与YiBo.MX是使用了YiBo的app_key和app_secret。使用自己申请的app_key在没有经过Sina审核通过时显示的时来自未审核的应用。
__使用Python实现时需要注意的地方__:
1.授权时自动获取浏览器URL必须指明Content-Type为application/x-www-form-urlencoded
要调用api必须先创建微博应用,然后得到app_key和app_secret。经过授权然后获得access_token作为请求参数的一部分,而要得到它必须先得到授权码。授权时可以抓下post到https://api.weibo.com/oauth2/authorize 的包,然后用程序模拟这个授权过程。在自动获取回调页面的code值时,请求授权url时必须要在http头信息中写明Content-Type为application/x-www-form-urlencoded,不然无法跟踪到页面跳转后的url,就无法通过代码自动得到code,在SAE上必须设置environ['disable_fetchurl'] = "1"才能正确获取。有了code后请求https://api.weibo.com/oauth2/access_token 获取access_token,返回的是json数据,从json数据中拿出access_token即可。具体操作可查看微博开放平台的API文档,这里不详细介绍。
请求代码:
headers = {'Referer':auth_url,'Content-Type': 'application/x-www-form-urlencoded'} r = urllib2.Request(url, data, headers)
2.模拟表单上传图片要细心构造Content-Type的值
上传图片时,API规定只能使用表单方式上传,所以http头的Content-Type要为multipart/form-data。post的数据不能直接写,必须按照格式加boundary,multipart/form-data boundary说明:http://yefeng.iteye.com/blog/315847 在抓包是可以看到上传时request payload里面有详细格式,boundary和格式非常重要,其中的换行是\r\n,有的地方是两个换行要注意,只要构造出这个字符串作为request的data参数即可。
有表单如下:
表单代码如下:
<form name="uploadForm" method="POST" action="http://api.t.sina.com.cn/statuses/upload.xml" enctype="multipart/form-data"> <input type="text" name="status" value="填写要发表的文字"> <input type="file" name="pic" value="浏览文件"> <input type="submit" value="上传"> <input type="hidden" name="source" value="改成你的appkey"> </form>
Content-Type示例如下:
------WebKitFormBoundaryxD3EeLtCYnk3hHkY
Content-Disposition: form-data; name="status"
hello myclover
------WebKitFormBoundaryxD3EeLtCYnk3hHkY
Content-Disposition: form-data; name="pic"; filename="20100620083829213.jpg"
Content-Type: p_w_picpath/jpeg
图片二进制信息
------WebKitFormBoundaryxD3EeLtCYnk3hHkY
Content-Disposition: form-data; name="source"
------WebKitFormBoundaryxD3EeLtCYnk3hHkY--
用Python构造以上内容结构即可作为请求参数上传图片
boundary = 'cuitclockweibopostdata%s'%(int(time.time())) post_data = [] for k,v in values.iteritems(): post_data.append('--%s'%boundary) post_data.append('Content-Disposition: form-data; name="%s"\r\n'%k) post_data.append(v) post_data.append('--%s'%boundary) post_data.append('Content-Disposition: form-data; name="pic"; filename="pic.png"') post_data.append('Content-Type: p_w_picpath/png\r\n') post_data.append(pic) post_data.append('--%s--\r\n'%boundary) data = '\r\n'.join(post_data) headers = {'Content-Type':'multipart/form-data; boundary=%s'%boundary} r = urllib2.Request(url, data, headers)
关于生成图片使用Python的PIL,在SAE和OpenShift上由于安全原因,都不允许对本地进行文件写操作,所以要把生成的图片放到内存中,在内存中进行读写,StringIO就是拿来做这事的。
buf_img = StringIO.StringIO() img.save(buf_img, 'png') output = buf_img.getvalue() buf_img.close()
3.Cron整点调用函数
在SAE上使用cron服务,是Unix和类Unix的操作系统之中常见crontab 命令,用于设置周期性被执行的指令。
配置时在sae环境的配置文件config.yaml中写上脚本就可以了,如下:
name: cuitclock
version: 1
cron:
- url: /url_update_weibo/
schedule: every 1 hour, offset 0
即每隔1小时,会自动请求url_update_weibo这个地址,然后后台得到请求后立即调用发微博函数。
最后,千万别关注成信钟楼新浪微博 http://weibo.com/CUITClock 这显然就是个坑嘛
文章为阿小信的个人笔记,转载请注明出处。