為了備份blog,簡單寫了一個適用于blogjava等metaWeblog的blog備份工具,功能:
(1)備份post的正文到本地
(2)備份正文中的圖片、css文件到本地
(3)基于以上兩的步驟,修改相關的鏈接,實現本地脫機瀏覽
想到了但是未實現的功能:
(1)評論無法保存
(2)合適的話可以考慮以Eclipes RCP形式包裝
一、實現原理
(1)獲取post的方法:使用MetaWeblog提供的API接口
metaWeblog.getRecentPosts (blogid, username, password, numberOfPosts) returns array of structs,
Each struct represents a recent weblog post, containing the same information that a call to metaWeblog.getPost would return.
If numberOfPosts is 1, you get the most recent post. If it's 2 you also get the second most recent post, as the second array element. If numberOfPosts is greater than the number of posts in the weblog you get all the posts in the weblog.
(2) 使用正則表達式分析獲取下來的post,解析出post中包含的css和圖片文件的地址,執行兩步操作
- 根據地址,抓取圖片保存到本地
- 修改post中的地址為本地保存地址
(3) 使用xml-rpc來簡化遠程調用過程的編程
二、主要的代碼
public ArrayList<SimplePost> getAllPosts(String blogID, String name,String password, int num) throws XmlRpcException {
ArrayList<SimplePost> posts = new ArrayList<SimplePost>();
Object[] params = new Object[] { blogID, name, password,new Integer(num) };
Object[] result = (Object[]) client.execute("metaWeblog.getRecentPosts", params);
for (int i = 0; i < result.length; i++) {
Map map = (Map) result[i];
String postUrl = (String) map.get("link");
String title = (String) map.get("title");
String postId = (String) map.get("postid");
// post的內容
String description = (String) map.get("description");
Map<String, String> images = new HashMap<String, String>();
images = getImagesURL(description);
String newDes = handleImagesURL(description,postId);
String descriptioFileName = savePostContent(savePath, title,postId, newDes, css);
SimplePost post = new SimplePost(postUrl, title, postId,descriptioFileName);
//從postContent獲取圖像的地址和名稱,以便獲取圖片并保存
post.setImages(images);
posts.add(post);
log.debug("postID: " + postId + "postTitle :" + title);
}
return posts;
}
ArrayList<SimplePost> posts = new ArrayList<SimplePost>();
Object[] params = new Object[] { blogID, name, password,new Integer(num) };
Object[] result = (Object[]) client.execute("metaWeblog.getRecentPosts", params);
for (int i = 0; i < result.length; i++) {
Map map = (Map) result[i];
String postUrl = (String) map.get("link");
String title = (String) map.get("title");
String postId = (String) map.get("postid");
// post的內容
String description = (String) map.get("description");
Map<String, String> images = new HashMap<String, String>();
images = getImagesURL(description);
String newDes = handleImagesURL(description,postId);
String descriptioFileName = savePostContent(savePath, title,postId, newDes, css);
SimplePost post = new SimplePost(postUrl, title, postId,descriptioFileName);
//從postContent獲取圖像的地址和名稱,以便獲取圖片并保存
post.setImages(images);
posts.add(post);
log.debug("postID: " + postId + "postTitle :" + title);
}
return posts;
}
public static Map<String, String> getImagesURL(String description) {
Map<String, String> map = new HashMap<String, String>();
// img 的正則表達式
String imgPattern = "<\\s*img\\s+([^>]+)\\s*>";
Pattern p = Pattern.compile(imgPattern, Pattern.CASE_INSENSITIVE);
Matcher matcher = p.matcher(description);
// img src元素的正則表達式
String srcPattern = "\\s*src\\s*=\\s*\"([^\"]+)\\s*\"";
Pattern p2 = Pattern.compile(srcPattern, Pattern.CASE_INSENSITIVE);
while (matcher.find()) {
Matcher matcher2 = p2.matcher(matcher.group());
// 一定要find(),這是實際的匹配動作
if (matcher2.find()) {
String src = matcher2.group();
log.info(src);
int i2 = src.lastIndexOf('/');
int i1 = src.indexOf("http");
if (i1 != -1) {
map.put(src.substring(i2 + 1, src.length() - 1), src
.substring(i1, src.length() - 1));
}
}
}
log.debug("圖片:" + map);
return map;
}
Map<String, String> map = new HashMap<String, String>();
// img 的正則表達式
String imgPattern = "<\\s*img\\s+([^>]+)\\s*>";
Pattern p = Pattern.compile(imgPattern, Pattern.CASE_INSENSITIVE);
Matcher matcher = p.matcher(description);
// img src元素的正則表達式
String srcPattern = "\\s*src\\s*=\\s*\"([^\"]+)\\s*\"";
Pattern p2 = Pattern.compile(srcPattern, Pattern.CASE_INSENSITIVE);
while (matcher.find()) {
Matcher matcher2 = p2.matcher(matcher.group());
// 一定要find(),這是實際的匹配動作
if (matcher2.find()) {
String src = matcher2.group();
log.info(src);
int i2 = src.lastIndexOf('/');
int i1 = src.indexOf("http");
if (i1 != -1) {
map.put(src.substring(i2 + 1, src.length() - 1), src
.substring(i1, src.length() - 1));
}
}
}
log.debug("圖片:" + map);
return map;
}
/**
* 替換description的圖片鏈接為本地的相對鏈接,結構為blogFiles/images/postid/
*
* @param description
* @param userName
* @param postId
* @return
*/
public static String handleImagesURL(String description, String postId) {
String tmp = description;
String address="images/" + postId + "/";
String imgPattern = "<\\s*img\\s+([^>]+)\\s*>";
Pattern p = Pattern.compile(imgPattern, Pattern.CASE_INSENSITIVE);
Matcher matcher = p.matcher(tmp);
// img src元素的正則表達式
String srcPattern = "\\s*src\\s*=\\s*\"([^\"]+)\\s*\"";
// String srcPattern = "\\s*src\\s*=\\s*\'([^\']+)\\s*\'";
Pattern p2 = Pattern.compile(srcPattern, Pattern.CASE_INSENSITIVE);
while (matcher.find()) {
Matcher matcher2 = p2.matcher(matcher.group());
// 一定要find(),這是實際的匹配動作
if (matcher2.find()) {
String src = matcher2.group();
log.info(src);
int l2=src.lastIndexOf('/')+1;
log.info(src.substring(l2,src.length()-1));
tmp=tmp.replace(src," src=\""+address+src.substring(l2,src.length()-1)+"\"");
}
}
return tmp;
}
* 替換description的圖片鏈接為本地的相對鏈接,結構為blogFiles/images/postid/
*
* @param description
* @param userName
* @param postId
* @return
*/
public static String handleImagesURL(String description, String postId) {
String tmp = description;
String address="images/" + postId + "/";
String imgPattern = "<\\s*img\\s+([^>]+)\\s*>";
Pattern p = Pattern.compile(imgPattern, Pattern.CASE_INSENSITIVE);
Matcher matcher = p.matcher(tmp);
// img src元素的正則表達式
String srcPattern = "\\s*src\\s*=\\s*\"([^\"]+)\\s*\"";
// String srcPattern = "\\s*src\\s*=\\s*\'([^\']+)\\s*\'";
Pattern p2 = Pattern.compile(srcPattern, Pattern.CASE_INSENSITIVE);
while (matcher.find()) {
Matcher matcher2 = p2.matcher(matcher.group());
// 一定要find(),這是實際的匹配動作
if (matcher2.find()) {
String src = matcher2.group();
log.info(src);
int l2=src.lastIndexOf('/')+1;
log.info(src.substring(l2,src.length()-1));
tmp=tmp.replace(src," src=\""+address+src.substring(l2,src.length()-1)+"\"");
}
}
return tmp;
}
http://www.aygfsteel.com/beansoft/archive/2007/06/20/125255.html
BlogJava 備份文章閱讀器+離線瀏覽備份(含源碼,SWT)
里面已經包含了保存 CSS, js, image 的 MHT 文件生成器的API, MHT 文件可以離線瀏覽(IE下). 不過我的所有文章列表都是從 BlogJava 備份文件那個大 XML 里面分析的. 不會 RCP, 交流一下思路先. 我用 HtmlParser 這個項目做的 HTML 解析, 比正則表達式準確率高一些.
多謝!^_^
寫這個小東西的背景:
當時剛剛在blogjava上安家,在blog上已經放了點東西了,不過有一天在某個商業的blog服務提供商上的主頁上看到一段話,大致的意思是“大家難度都忘了幾年前,免費主頁空間的教訓了嗎?”,于是試著google blog的備份工具,就找到了你提供的BlogJava 備份文章閱讀器+離線瀏覽備份,下載試用了下,感覺挺好的,美中不足的是,如果想要真正離線瀏覽,就必須使用mht來保存文章,這點我感覺有點受限了,因為firefox不能打開mht文件,(有時候還要到linux下面耍耍,mht在linux好像也沒有什么方式打開),所以我才決定寫一個東西將文件和圖片,css都下載到本地,同時修改鏈接來實現更加靈活的離線瀏覽。我沒有用過HtmlParser,學習學習去。。
如果有需要的話,可以考慮用RCP 封裝了提供出來,在http://www.aygfsteel.com/beansoft/archive/2007/06/20/125255.html有一個離線備份工具提供下載,原理上有點不一樣,但是目的是一樣的,現在也支持保存圖片等資源到本地了