同步你的twitter和开心网记录–基于GAE

一直很烦恼想发的牢骚要在twitter.com和kaixin001.com上说两遍。再有气势的话这么一搞也没啥想法了。
Google App Engine支持Task Queue和Cron Job,简直天生就是做Bot的平台阿。挑了一个周末马上动手搞起来。
从Twitter上抓取消息
我用的是twitter4j.没有特别的比较。觉得还挺方便就用了。不负责推荐。

Twitter twitter = new Twitter("xxx", "xxx");
try {
List list = (List) twitter.getUserTimeline();
for (int i = 0; i < list.size(); i++) { Status status = list.get(i); Query query = pm.newQuery(Tweet.class, "id == myId"); query.declareParameters("long myId"); List results = (List) query.execute(status
.getId());
if (results == null || results.size() == 0) {
Tweet tweet = new Tweet(status.getId(), status.getUser()
.getScreenName(), status.getText());
pm.makePersistent(tweet);
if (tweet.getText().indexOf("#kaixin") > -1) {
Queue queue = QueueFactory.getQueue("sendKaixin");
queue.add(TaskOptions.Builder.url("/sendKaixin")
.method(Method.GET).param("tweetid",
String.valueOf(tweet.getId())));
}
}
}
} catch (TwitterException e) {
log.warning(e.toString());
}

这段Code所在的servlet被配置成Cron Job,定义为每30分钟run一次。
大概的逻辑是说下载自己最新的tweets,如果内容包含”#kaixin”(只是为了方便),就调用TaskQueue的”/sendKaixin”发送到kaixin001上。

向kaixin001.com写消息
kaixin001的网站比较复杂,包含很多ajax,js的东西。看了几个外挂,主要都是对wap.kaixin001.com进行抓取和分析。
wap.kaixin001.com页面非常简单,没有session之类的概念。主要是通过登陆之后html之中带的一个”verifyValue”的值对各个组件进行关联。

URL url = new URL(URL_LOGIN);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Referer", URL_REFERER);
StringBuilder postData = new StringBuilder().append("email=")
.append(email.replaceAll("@", "%40")).append("&password=")
.append(password).append(
"&from=&login=+%E7%99%BB+%E5%BD%95+");
OutputStreamWriter writer = new OutputStreamWriter(connection
.getOutputStream());
writer.write(postData.toString());
writer.close();
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
System.out.println("Kaixin001 login successfully!");
BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream(),
"UTF-8"));
StringBuilder resultBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
resultBuilder.append(line);
}
reader.close();
String sResult = resultBuilder.toString();
verifyValue = findText(sResult, "/app/mylist.php?verify=",
"\"", 0);
}

有了verifyValue之后只需要向对应的URL提交form表单就可以了。

URL url = new URL(URL_PREFIX_POST_RECORD + verifyValue);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Referer", URL_PREFIX_WRITE_RECORD
+ verifyValue);
StringBuilder postData = new StringBuilder().append(
"privacy=1&content=").append(URLEncoder.encode(tweet.getText(),"UTF-8"));
OutputStreamWriter writer = new OutputStreamWriter(connection
.getOutputStream());
writer.write(postData.toString());
writer.close();
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
tweet.setStatus(Tweet.STATUS_UPDATED);
}
else{
log.warning("Kaixin001 update record failed" + connection.getResponseCode());
}

由于Google App Engine对URL Fetch有一些限制。所以直接用了它提供的URL来做Http Connection.用这个方法提交的记录会直接显示成手机提交,酷阿。
开发中的问题
要做的事情很明确。
1)抓取twitter.
2) 提交kaixin001
3) 更新tweet状态
但是由于Google App Engine中Cron Job和Task Queue都是基于URL Mapping做的,所以每一个请求都有30s的限制,这就对应用提出了要求。一开始考虑的两个方案都会因为超时而失败。
痛定思痛,考虑这两个功能的本质,Cron Job是定时执行,不论成败。Task Queue是定时循环执行,直到成功。
所以最后我的方案是
1)Cron Job定制抓取Twitter,遇到关键字丢给Task Queue.
2) Task Queue循环向kaixin001.com提交,直到成功。

后话
因为涉及twitter.com和kaixin001.com两个网站的账号和密码,所以个人觉得作在线应用会有一些障碍。可能考虑开源让大家自己搭着玩吧。后话了。大家有意见可以给我提。



Tags: App Engine, GAE, Google App Engine, kaixin001, twitter, twitter4j
  • http://www.qinzifang.cn 芦苇

    博主,好

    看了你的关于AGE的文章,很受启发,我还是个业余级的菜鸟,Java和Python都不太懂,但是想用一下google的CRON的功能,让他每10分钟访问一次我的一个任务触发.http://www.******.cn/cron/cron.php,不知道该怎么写。

    还请大侠赐教一下。盼复。非常感谢!

    [Reply]

无觅相关文章插件,快速提升流量