Move google svn to github git

之前contactlist这个项目一直放在google code上面,今天把contactlist移植到了github上。记录下移植的过程:

首先是用git-svn把googlecode上的项目checkout出来

git svn clone https://contact-list.googlecode.com/svn -T trunk -b branches -t tags

之后就是push到github了

git remote add origin git@github.com:flyerhzm/contactlist.git
git push origin master

相当简单,这下我的项目就都搬到github上面去了

Posted in  git contact-list


contact-list类库依赖包之json

json类库为java提供了方便地在json和string之间的转换和对json数据的操作。

对于contact-list类库来说,有些联系人信息是通过json来传输的,所以利用json类库来处理数据。

1. 从String转换为JSON对象

protected JSONObject parseJSON(String content, String startTag) throws JSONException {
    String json = content.substring(content.indexOf(startTag) + startTag.length());
    JSONTokener jsonTokener = new JSONTokener(json);
    Object o = jsonTokener.nextValue();
    return (JSONObject) o;
}

protected JSONObject parseJSON(String content, String startTag, String endTag) throws JSONException {
    String sub_content = content.substring(content.indexOf(startTag) + startTag.length());
    String json = sub_content.substring(0, sub_content.indexOf(endTag));
    JSONTokener jsonTokener = new JSONTokener(json);
    Object o = jsonTokener.nextValue();
    return (JSONObject) o;
}

传入一个String,同时传入其中json的start tag和end tag,来划定这个json string。

2. 读取json数据中的值

JSONArray jsonContacts = jsonObj.getJSONArray("Contacts");
for (int i = 0; i  jsonContacts.length(); i++) {
    JSONObject jsonContact = (JSONObject) jsonContacts.get(i);
    String username = jsonContact.getString("c");
    String eamil = jsonContact.getString("y");
    contacts.add(new Contact(username, email));
}

getJSONArray获取一个json array

getJSONObect获取一个json object

jsonObject.getString(key)获取json object的string值

Posted in  contact-list java


disable browser cache in rack

bullet插件在浏览器cache下总是会问题,因为页面被cache了,总是返回304 Not Modified,bulletware下的代码没有执行就直接跳过了。

之前就是在README下面写了一段,让用户把web browser cache disable掉,不过始终不是一个解决方法,今天就直接在rack下把browser cache disable掉了

class Bulletware
  def initialize(app)
    @app = app
  end

  def call(env)
    return @app.call(env) unless Bullet.enable?
    ......
    no_browser_cache(headers) if Bullet.disable_browser_cache
    [status, headers, response_body]
  end

  def no_browser_cache(headers)
    headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
    headers["Pragma"] = "no-cache"
    headers["Expires"] = "Wed, 09 Sep 2009 09:09:09 GMT"
  end
end

no_browser_cache这个方法内容是google出来的,换了一个好日子_,还换了rack的方式,这样304 Not Modified就不会出现了。

Posted in  rails rack http


Add logger to rake task

在rake task中写了一个爬虫,用cron定期去爬取,但是没有任何输出,实在心里没底。于是要加入log,结果发现logger在task中没有定义,只能自己加上去了。

task :crawl => :environment do
  RAILS_DEFAULT_LOGGER.info "crawl start"
  crawl_board('XXX')
  RAILS_DEFAULT_LOGGER.info "crawl end"
  RAILS_DEFAULT_LOGGER.flush
end

或者也可以在最前面定义

RAILS_DEFAULT_LOGGER.auto_flushing = true

如果不flush的话,是看不到日志输出的

Posted in  rails


在google app engine上做代理服务(for crawler)

本来是想在GAE上做一个完整的代理服务器的,结果发现不可行,好像当HTTP的URL和HOST不匹配的时候,GAE就会把你拦截。怪不得GAE上找到的代理服务器都必须安装客户端或者是网页式的呢。

但是我在hostmonster上的crawler还被挡在国门之外,没办法,只能通过QUERY_STRING来实现一个比较奇怪的代理了:

package com.huangzhimin.gae.proxy;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Enumeration;

import javax.servlet.http.*;

@SuppressWarnings("serial")
public class RichardProxyServlet extends HttpServlet {
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String dest = req.getParameter("dest");
        URL url = new URL(dest);
        HttpURLConnection connection = null;
        InputStream in = null;
        try {
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            Enumeration headers = req.getHeaderNames();
            while (headers.hasMoreElements()) {
                String headerName = (String) headers.nextElement();
                connection.setRequestProperty(headerName, req.getHeader(headerName));
            }
            connection.setDoOutput(true);
            connection.setReadTimeout(10000);
            connection.connect();
            in = connection.getInputStream();
            byte[] b = new byte[4096];
            int bytesRead = 0;
            while (true) {
                bytesRead = in.read(b, 0, 4096);
                if (bytesRead == -1) {
                    break;
                }
                resp.getOutputStream().write(b, 0, bytesRead);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
}

实现起来很简单,就是读取QUERY_STRING,获取需要爬取的网址,设置相应的request headers,然后发送请求,读取应答。

再来看看hostmonster上的爬虫如何处理吧:

require 'regexp_crawler/crawler'

module Net
  class HTTP
    def HTTP.get_response_with_headers(uri, headers)
      response = start('richardproxy.appspot.com', 80) do |http|
        http.get('/richardproxy?dest=' + uri.to_s, headers)
      end
    end
  end
end

那就是在获取网页内容的时候,传入GAE上代理的地址,增加QUERY_STRING来表示要爬取的网页,当然也可以修改相应的http headers,其它地方都无须改动。

虽然在GAE上搭建完整代理服务的尝试失败了,但是我的爬虫又活过来了,而且发现在GAE上放些应用应该会很不错,毕竟google的server还是相当牛的,只要流量不是太大,就可以创建十个免费的应用哦,下次试试做个JRuby应用上去,呵呵。

Posted in  java gae ruby http


Fork me on GitHub