2011年6月18日星期六

  Java程序自动发布文章到百度空间

这几天建立了个博客,想把这个博客的内容同时导入到其他博客中去,同时,当在本博客发表一篇博文的时候,也同步传输到其他博客中去,

这样就方便多了,以后只要维护一个就ok了。

 

CSDN的博客开放的比较好,符合http://www.xmlrpc.com/metaWeblogApi标准,可以有开放的API来调用,容易解决。

 

目前遇到的问题就是导入博文到百度空间,貌似百度现在还没有做出什么开放的API来,没办法来直接调用,不过也有方法来解决,

那就是通过程序来模拟浏览器的登录过程和发表文章的过程,通过测试,搞定。。O(∩_∩)O哈哈~

 

下面介绍一下程序的思路和展示一下源码:

 

1. 基本思路就是通过程序来模拟浏览器的登录过程,本文的代码基于Java语言实现,主要利用的就是Apache的HttpClient包。

 

2. 大家首先可以利用浏览器的插件来捕获我们正常到百度登录过程,和发表博文过程的所有Http请求的数据,着重分析一下

   表单数据的提交,就可以知道百度空间发文在后台做了那些操作和需要哪些重要的数据来验证用户的正常登录。

 

3. 用程序来模拟浏览器登录的最重要的处理,就是Cookie的保存和后续数据的传输,因为像百度这类需要用户输入账户

   和密码来登录的系统,并且具有密码记忆功能的网站,用户的验证信息都存储在Cookie中。

 

4. 因为为了让百度服务器识别用户的登录,那就要在程序中记录第一次登录过程的Cookie数据,然后在以后的http请求中

  将cookie数据回传给服务器,那样服务器就认为你一直登录了,不然文章是不能正确发布出去的,因为你没有cookie的话,

  服务器还认为你没有登录过,会拒绝操作。

 

5. 用户的身份验证解决了以后,百度发表文章的时候,还要多加一步验证,就是通过访问新建博文的页面,获取一个临时的百度

  token,它会与你接下来发表的博文一一对应,我猜测可能是服务器支持单用户多点登录,同时发表多篇博文吧,不过这都没

  关系了,反正我们照做就行啦。

 

6. 文章分类的处理,我发现百度这边做的不够智能,如果你发表博文的时候,指定了一个不存在的类别,直接决绝发布,所以,还是

  想个笨点的办法,每次发布博文前,先建立一个类别,如果已经有了这个类型,重新建立一次也没关系,反正也不会覆盖掉,因为百度

  会拒绝建立新的类别,错误类型是类别已存在,这个善意的错误忽略就ok。。。哈哈

 

7. 所有这些前期工作做好了,就能正常发布文章了,下面贴出一下源码文件,大家按照自己的方式去修改吧:

  1. Config.java

    主要配置一下个人百度账号的用户名和密码

    

package com.carey.baidublog;public class Config {	public static final String USERNAME = "username";	public static final String PASSWORD = "password";}

  2. PublishBlog.java

   测试程序,调用函数发布文章到百度空间

   

package com.carey.baidublog;public class PublistBlog {	public static void main(String[] args) {		try {			BDHttpClient.publishBlog("Article-Title", "Article-Content",					"Article-category");			System.out.println("成功发布一篇文章到百度空间");		} catch (Exception e) {			e.printStackTrace();		}	}}

  3. BDHttpClient.java

  发布百度博文的实现类,主要是http请求和cookie的处理,以及获取百度令牌token

  

package com.carey.baidublog;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.HashMap;import java.util.Set;import java.util.regex.Matcher;import java.util.regex.Pattern;import org.apache.commons.httpclient.Cookie;import org.apache.commons.httpclient.HttpClient;import org.apache.commons.httpclient.HttpMethod;import org.apache.commons.httpclient.HttpStatus;import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;import org.apache.commons.httpclient.methods.GetMethod;import org.apache.commons.httpclient.methods.PostMethod;public class BDHttpClient {	private static final String LOGIN_URL = "https://passport.baidu.com/?login";	private static final String CREATBLOG_URL = "http://hi.baidu.com/"			+ Config.USERNAME + "/creat/blog";	private static final String MODIFYCATEGORY_URL = "http://hi.baidu.com/"			+ Config.USERNAME + "/modify/category/0";	private static final String COMMITBLOG_URL = "http://hi.baidu.com/"			+ Config.USERNAME + "/commit";	private static final int CONNECTION_TIMEOUT = 20000;	public static void publishBlog(String title, String content, String category)			throws Exception {		// step 1, login baidu and get cookies		Cookie[] cookies = LoginBaidu();		// step 2, get Bdstoken		String bdstoken = getBdstoken(cookies);		// step 3, publish article		if (bdstoken != null) {			postBlog(cookies, bdstoken, title, content, category);		} else {			throw new Exception("bdstoken == null");		}	}	private static HttpClient getHttpClient(Cookie[] cookies) {		HttpClient httpClient = new HttpClient();		if (cookies != null) {			// add cookies			httpClient.getState().addCookies(cookies);			// httpClient.getParams().setParameter("http.protocol.cookie-policy",			// CookiePolicy.BROWSER_COMPATIBILITY);		}		return httpClient;	}	private static Cookie[] LoginBaidu() {		HttpClient httpClient = getHttpClient(null);		HashMap params = new HashMap();		params.put("username", Config.USERNAME);		params.put("password", Config.PASSWORD);		params.put("pwd", "1");		try {			httpPost(httpClient, LOGIN_URL, generateQueryString(params));		} catch (Exception e) {			e.printStackTrace();		}		return httpClient.getState().getCookies();	}	private static String getBdstoken(Cookie[] cookies) {		HttpClient httpClient = getHttpClient(cookies);		try {			String res = httpGet(httpClient, CREATBLOG_URL, null);			Pattern p = Pattern.compile("bdstoken=([0-9a-z]+)\\W");			Matcher m = p.matcher(res);			if (m.find()) {				return m.group(1);			}		} catch (Exception e) {			e.printStackTrace();		}		return null;	}	private static String createCategory(Cookie[] cookies, String bdstoken,			String category) throws Exception {		HttpClient httpClient = getHttpClient(cookies);		HashMap params = new HashMap();		// bdstoken		params.put("bdstoken", bdstoken);		// create category		params.put("ct", "2");		params.put("cm", "1");		// Article category, such as "Android", "Google", "默认分类"		params.put("spBlogCatName", category);		params.put("spRefURL", MODIFYCATEGORY_URL);		return httpPost(httpClient, COMMITBLOG_URL, generateQueryString(params));	}	private static String postBlog(Cookie[] cookies, String bdstoken,			String title, String content, String category) throws Exception {		HttpClient httpClient = getHttpClient(cookies);		HashMap params = new HashMap();		// bdstoken		params.put("bdstoken", bdstoken);		// new blog		params.put("ct", "1");		params.put("cm", "1");		// add a new article		params.put("spBlogID", "");		params.put("edithid", "");		params.put("spBlogCatName_o", "");		// Article title		params.put("spBlogTitle", title);		// Article content		params.put("spBlogText", content);		// Article category, such as "Android", "Google", "默认分类"		params.put("spBlogCatName", category);		// Article view Permissions,		// 0 --> every one 1 --> only friend 3 --> only oneself		params.put("spBlogPower", "0");		// 0: forbidden comment 1: allow comment		params.put("spIsCmtAllow", "1");		// 0: allow share 1: forbidden share		params.put("spShareNotAllow", "0");		// verify code		params.put("spVcode", "");		params.put("spVerifyKey", "");		// first create category		createCategory(cookies, bdstoken, category);		return httpPost(httpClient, COMMITBLOG_URL, generateQueryString(params));	}	private static String generateQueryString(HashMap params) {		StringBuffer sb = new StringBuffer();		if (params != null && !params.isEmpty()) {			Set keys = params.keySet();			for (String key : keys) {				sb.append(key);				sb.append("=");				sb.append(params.get(key));				sb.append("&");			}			// remove last &			sb.deleteCharAt(sb.length() - 1);		}		return sb.toString();	}	private static String httpGet(HttpClient httpClient, String url,			String queryString) throws Exception {		String responseData = null;		if (queryString != null && !queryString.equals("")) {			url += "?" + queryString;		}		GetMethod httpGet = new GetMethod(url);		httpGet.getParams().setParameter("http.socket.timeout",				new Integer(CONNECTION_TIMEOUT));		try {			int statusCode = httpClient.executeMethod(httpGet);			if (statusCode != HttpStatus.SC_OK) {				System.err.println("HttpGet Method failed: "						+ httpGet.getStatusLine());			}			responseData = getResponseBodyAsString(httpGet);		} catch (Exception e) {			throw new Exception(e);		} finally {			httpGet.releaseConnection();		}		return responseData;	}	private static String httpPost(HttpClient httpClient, String url,			String queryString) throws Exception {		String responseData = null;		PostMethod httpPost = new PostMethod(url);		httpPost.addParameter("Content-Type",				"application/x-www-form-urlencoded");		httpPost.getParams().setParameter("http.socket.timeout",				new Integer(CONNECTION_TIMEOUT));		if (queryString != null && !queryString.equals("")) {			httpPost.setRequestEntity(new ByteArrayRequestEntity(queryString					.getBytes()));		}		try {			int statusCode = httpClient.executeMethod(httpPost);			if (statusCode != HttpStatus.SC_OK) {				System.err.println("HttpPost Method failed: "						+ httpPost.getStatusLine());			}			responseData = getResponseBodyAsString(httpPost);		} catch (Exception e) {			throw new Exception(e);		} finally {			httpPost.releaseConnection();		}		return responseData;	}	private static String getResponseBodyAsString(HttpMethod httpMethod) {		StringBuffer sb = new StringBuffer();		try {			BufferedReader br = new BufferedReader(new InputStreamReader(					httpMethod.getResponseBodyAsStream()));			String line = br.readLine();			while (line != null) {				sb.append(line + "\n");				line = br.readLine();			}		} catch (IOException e) {			e.printStackTrace();		}		return sb.toString();	}}

 

程序运行后会在百度空间发布一篇博文的,截图如下:

 

有兴趣的童鞋希望给改进更好的版本,给我反馈一下,哈哈,就当人人为我,我为人人,做个小广告!

好了,到现在为止,工作都做完了,收工喽!!!



本文是使用 Carey Blog润物无声 进行同步发布的 原文地址: http://www.zhourunsheng.com/articles/2011/06/18/1308403894049.html

没有评论:

发表评论