2010年11月23日星期二

[GFW BLOG] [更新]同步消息到15个微博服务

来源:http://isouth.org/archives/277.html

微博多了的人总是在想办法来简化自己的消息发布流程,在这之前我是使用月光博客的 一个架设在GAE上的程序来实现部分微博客之间的消息同步。不过稳定性并不是太好,经常性的一天过去了却一条消息都没有同步,而某个时间再一次性全部发到 其他服务上势必造成严重的刷屏效果。加之我还有一些额外的同步需求,此程序无法满足我了,所以最终还是打算自己动手......折腾......

目前已经可以较好地实现一次发布消息,并同步地向以下1415个服务发送:Twitter、人人、开心、嘀咕人间新浪163雷猴搜狐做啥Follow59911、纸飞机(UChome)、叽歪。每个链接都是我的个人页面,没有链接的说明目前不可访问或者由于隐私需要特地而为。

好吧,最主要的还是要讲讲主要的实现方法,着重的分享要点,而不会直接给出我的程序-.-

准备工具:给各个 API 发送数据的最佳命令行工具 Curl,可以从这里下载到 for windows 的版本,当然要支持 SSL 的。Ubuntu 等 Linux 用户直接 sudo aptitude install curl 即可。另外我为了更加稳定地向人人网发送信息而用了 Python

我想这些服务主要地分为两类,即开放 API 的和不开放 API 的,对于开放API的服务,一般情况下直接使用如下命令:

curl -u user:password -d "status=message" "API Address"

最具代表性的 Twitter API 示例

curl -k -u user:password -d "status=message" https://api.twitter.com/statuses/update.json

对于不开放 API 的或者 API 使用要求严格的,则可能需要使用 curl 来模拟登录并发布消息了,这个过程通常需要分析网页源代码,举两个例子,第一个是新浪微博的消息发布(新浪微博虽然开放 API 不过其使用过程中需要 appkey,我申请不到)

  1. curl -k -c sina.txt "https://login.sina.com.cn/sso/login.php?username=user_sina&password=psw_sina&returntype=TEXT"
  2. curl -e "http://t.sina.com.cn/" -b sina.txt -d "content=message" "http://t.sina.com.cn/mblog/publish.php

第一句模拟登录新浪微博,并将cookie文件保存为 sina.txt,第二步是带上 cookie 发布消息,参数中 -k 避免因 https 连接时证书不匹配导致的错误,-c 指定保存 cookie 文件,-e 指定 referer,-b 带上 cookie 文件,-d 以 post 方式提交数据,最后则为目的地址了。

再附向163发布消息的代码,这里的 -L 参数可以应对一些页面重定向的情况

  1. curl -k -L -e "http://t.163.com" -c 163.txt "https://reg.163.com/logins.jsp?username=user_163&password=psw_163&product=t&type=1" 
  2. curl -b 163.txt -e "http://t.163.com" -d "status=message" "http://t.163.com/statuses/update.do"

第二个例子为向开心001或者纸飞机这类 UChome社区发布状态,主要为登录问题,因为他们在登录的时候需要带上一串验证数字verify或者formhash。如果打算用批处理的话可能会稍微烦一点,因为获取该字符串要几个步骤,先以登录纸飞机社区为例

  1. curl "http://my.nuaa.edu.cn/home/do.php?ac=a4d30c424df67e23cdefc40e489f82c2&&ref" >home_enuaa.txt
  2. findstr formhash home_enuaa.txt > home_enua.txt
  3. for /f "tokens=4 delims==/" %%i in ('type home_enua.txt') do (
  4. set formha=%%i
  5. set formha=!formha:~1,8!
  6. )
  7. curl -c enuaa.txt -d "username=user_enuaa&password=psw_enuaa&cookietime=315360000& amp;refer=space.php?do\=home&loginsubmit=登录&formhash=!formha!" "http://my.nuaa.edu.cn/home/do.php?ac=a4d30c424df67e23cdefc40e489f82c2&&ref"
  8. curl -b enuaa.txt -c enuaa.txt "http://my.nuaa.edu.cn/home/space.php?do=home" >home_enuaa.txt
  9. findstr formhash home_enuaa.txt > home_enua.txt
  10. for /f "tokens=4 delims==/" %%i in ('type home_enua.txt') do (
  11. set formhash=%%i
  12. set formhash=!formhash:~1,8!
  13. )
  14. curl -L -b enuaa.txt -d "message=message" -d "addsubmit=true&spacenote=true&formhash=!formhash!&add=更新" "http://my.nuaa.edu.cn/home/cp.php?ac=doing"

原则上就是首先访问一遍网页,然后查找字符串,得到相应的验证值之后再登录,发送,并且可能登录的 formhash 和发送时的 formhash 值并不相同。这么复杂的事情交给 Python 来办就好多了,向 开心001 发送消息的例子(片段)

  1. import os,re,urllib
  2. from BeautifulSoup import BeautifulSoup
  3. curl = r'g:\curl\curl.exe'
  4. def    UpdateKaixin( user , password , message ):
  5.     print u'更新开心消息...'
  6.     os.system(curl+' -L -c kaixin_cookie.txt -d \"email='+ user +'&password='+ password +'&remember=1&from=&refuid=0&refcode=&bind=&gotourl=&submit=true\" \"http://wml.kaixin001.com/login/login.php\" >kaixin_temp.txt 2>nul')
  7.     kaixin_web=BeautifulSoup(file(r'kaixin_temp.txt').read())
  8.     verify = kaixin_web.find('postfield',attrs={'name':'verify'})['value']
  9.     os.system(curl +' -b kaixin_cookie.txt -d \"state='+ message + '&verify='+ verify +'\" \"http://wml.kaixin001.com/home/state_submit.php\" >nul' )
  10.     os.system('del /q kaixin_temp.txt')
  11.     os.system('del /q kaixin_cookie.txt')

其中的 verify 就是要获取的字符串,我使用了 BeautifulSoup 这个模块来提取网页数据,并且用 os.system 命令来调用 curl,为了简单,这里是模拟登录开心的手机版页面发送消息,因此在消息后会出现手机的标志。这里又有个问题,人人网的登录验证字符串长度可能变化,使 用批处理时不好弄,并且人人网模拟登录时可能不大稳定,liancheng 给出了利用 PyXMPP 的方法

  1. from pyxmpp import streamtls
  2. from pyxmpp.jabber.client import JabberClient
  3. from pyxmpp.jid import JID
  4. from pyxmpp.presence import Presence
  5. from sys import argv
  6. def UpdateR2( user, password, message ):
  7.     class R2Client( JabberClient ):
  8.         def __init__( self, jid, password ):
  9.             tls = streamtls.TLSSettings( require=True, verify_peer=False )
  10.             auth = ['sasl:PLAIN']
  11.             JabberClient.__init__( self, jid, password, tls_settings=tls,
  12.                                    auth_methods=auth )
  13.  
  14.         def session_started( self ):
  15.             self.stream.send( Presence( status=message ) )
  16.             self.stream.disconnect()
  17.             self.stream = None
  18.  
  19.     client = R2Client( JID( user + '@talk.xiaonei.com/r2' ), password )
  20.     client.connect()
  21.     client.loop( 1 )

很好很强大,需要注意的是这里的 user 是在自己个人主页地址中的那一串数字。

发送消息中还需要注意的是可能需要使用 UTF-8 字符并 URLEncode 编码,而 中文默认使用 GBK 进行编码,这就需要转换一下了,如果使用 Python,那么可以在 import urllib 后使用类似如下语句转换为 UTF-8 编码并 URLEncode

  1. message_ut=message_gb.decode('gbk').encode('utf-8')
  2. message=urllib.quote(message_ut)

若是为了简便只用批处理,可以访问 “http://m.isouth.org/ded/urlencode.php?zh=中文字符” 这个地址获得转换后的结果,但是我不保证这个地址长期有效。

归类起来也就这么几种情况,稍微熟悉一下就可以组织起来自己编写脚本,只是因为批处理不好处理空格和特殊字符的问题,所以我又转向了 Python 。除了腾讯微博现在不知该怎么处理为好,目前我使用自己编写的脚本来同时给1415个服务更新状态感觉很好,虽然简陋,限制较多,但是安全,快速。




--
Posted By GFW BLOG 功夫网 to GFW BLOG at 11/23/2010 11:46:00 PM

--
1、我们的订阅地址:http://feeds2.feedburner.com/chinagfwblog。2、发一封标题为GFW的邮件到fanqiang70ma@gmail.com,就可获取翻墙利器赛风新地址。附《数字时代》赠阅版。3、本站热烈欢迎各位朋友投稿或推荐文章,请发邮件至chinagfwblog[at]gmail.com。
停止订阅,请发邮件到
gfw-blog+unsubscribe@googlegroups.com

没有评论:

发表评论