文档章节

oschina博客搬家更新 http://move.oschina.net/

Yashin
 Yashin
发布于 2014/01/24 15:02
字数 1377
阅读 3546
收藏 59

一、新增博客类型:新增了wordpress个人博客 xml文件上传导入oschina的功能。登陆osc后只有点击右下wordpress图标即可选择从自己wordpress站点导出的xml文件上传。再点击抓取就可以获取文件中的博客列表,可选地导入osc即可。


二、程序结构调整:本次更新最主要是将各个博客网站的抓取规则写到同一个配置文件中,将抓取逻辑封装在同一个类里面,然后根据不同的url从配置文件中读取不同网站的抓取规则(读取xml用dom4j)。主要是为了方便扩展,也让结构更加清晰一点。

/**
 * 博客爬虫抓取逻辑
 * @author oscfox
 * @date 20140124
 */
public class BlogPageProcessor implements PageProcessor{
	
	public class LinkXpath{
		public String linksXpath;	//链接列表过滤表达式
		public String titlesXpath;	//title列表过滤表达式
	}
	
	public class ArticleXpath{
		public String contentXpath;	//内容过滤表达式
		public String titleXpath;	//title过滤表达式
		public String tagsXpath; 	//tags过滤表达式
	}
	
	private Site site = new Site();
	private String url;
	private String blogFlag;							//博客url的内容标志域
	private List<String> codeBeginRex; 					//代码过滤正则表达式
	private List<String> codeEndRex; 					//代码过滤正则表达式
	private List<LinkXpath> linkXpaths;					//获取链接表达式
	private List<ArticleXpath> articleXpaths;			//获取文件表达式
	private List<String> PagelinksRex;					//类别页列表过滤表达式
	private Hashtable<String, String> codeHashtable;	//代码class映射关系
	private SpiderConfigTool spiderConfig; 

	public BlogPageProcessor(String url) throws Exception{
		if(url.endsWith("/")){
			url = url.substring(0, url.length()-1);
		}
		this.url=url;
		
		String spiderName="";	//切割域名 :类似:csdn.net, 51cto.com, cnblogs.com, iteye.com
		
		Pattern p=Pattern.compile("\\.([a-zA-Z0-9]+\\.[a-zA-Z]+)");
		Matcher m=p.matcher(url);
		
		if(m.find()){
			spiderName = m.group(1);
		} else {
			throw new Exception("不支持的网站!");
		}
		
		spiderConfig = new SpiderConfigTool(spiderName);
		
		init();
	}
	
	/**
	 * 初始化
	 */
	private void init(){
		String domain = spiderConfig.getSpiderNode().selectSingleNode("domain").getText();
		site = Site.me().setDomain(domain);
		String charset = spiderConfig.getSpiderNode().selectSingleNode("charset").getText();
		site.setCharset(charset);
		site.setSleepTime(1);
		
		blogFlag = spiderConfig.getSpiderNode().selectSingleNode("blog-flag").getText();
		
		initPageRex();
		initCodeRex();
		initLinkXpath();
		initArticleXpath();
		initCodeHash();
	}
	
	/**
	 * 初始化 代码替换正则
	 */
	@SuppressWarnings("unchecked")
	private void initCodeRex(){
		codeBeginRex = new ArrayList<String>(); 		//代码过滤正则表达式
		codeEndRex  = new ArrayList<String>(); 			//代码过滤正则表达式
		
		List<Node> list = spiderConfig.getSpiderNode().selectNodes("code-begin-rex");
		for(Node n:list){
			codeBeginRex.add(n.getText());
		}
		
		list = spiderConfig.getSpiderNode().selectNodes("code-end-rex");
		for(Node n:list){
			codeEndRex.add(n.getText());
		}
	}
	
	/**
	 * 初始化 分页链接
	 */
	@SuppressWarnings("unchecked")
	private void initPageRex(){
		PagelinksRex = new ArrayList<String>();
		//page-links-rex
		List<Node> list = spiderConfig.getSpiderNode().selectNodes("page-links-rex");
		for(Node pagelink:list){
			String page = pagelink.getText();
			String string=url.replaceAll("\\.", "\\\\\\.");
			String temString= string+page;
			PagelinksRex.add(temString);
		}
	}
	
	/**
	 * 初始化 获取链接列表xpath
	 */
	@SuppressWarnings("unchecked")
	private void initLinkXpath(){
		linkXpaths = new ArrayList<LinkXpath>();		//获取链接表达式
		
		List<Node> list = spiderConfig.getSpiderNode().selectNodes("link-xpath");
		for(Node node : list){
			String link = node.selectSingleNode("links-xpath").getText();
			String title = node.selectSingleNode("titles-xpath").getText();
			LinkXpath linkXpath = new LinkXpath();
			linkXpath.linksXpath=link;
			linkXpath.titlesXpath=title;
			linkXpaths.add(linkXpath);
		}
	}
	
	/**
	 * 初始化 文章规则
	 */
	@SuppressWarnings("unchecked")
	private void initArticleXpath(){
		articleXpaths = new ArrayList<ArticleXpath>();	//获取文件表达式
		
		List<Node> list = spiderConfig.getSpiderNode().selectNodes("article-xpath");
		for(Node node : list){
			String content = node.selectSingleNode("content-xpath").getText();
			String title = node.selectSingleNode("title-xpath").getText();
			String tags = node.selectSingleNode("tags-xpath").getText();
			ArticleXpath articleXpath = new ArticleXpath();
			articleXpath.contentXpath=content;
			articleXpath.titleXpath=title;
			articleXpath.tagsXpath = tags;
			
			articleXpaths.add(articleXpath);
		}
	}
	
	/**
	 * 初始化代码类型映射
	 */
	@SuppressWarnings("unchecked")
	private void initCodeHash(){
		codeHashtable = new Hashtable<String, String>();
		
		List<Node> list = spiderConfig.getSpiderNode().selectNodes("code-hashtable");
		for(Node node : list){
			String key = node.selectSingleNode("key").getText();
			String osc = node.selectSingleNode("osc").getText();
			codeHashtable.put(key, osc);
		}
	}

	/**
	 * 抓取博客内容等,并将博客内容中有代码的部分转换为oschina博客代码格式
	 */
	@Override
    public void process(Page page) {
		
		Pattern p=Pattern.compile(blogFlag);
		Matcher m=p.matcher(url);
		boolean result=m.find();
		
        if(result){
        	getPage(page);
        	page.putField("getlinks", false);
        } else {
			getLinks(page);
			page.putField("getlinks", true);
		}
	}
	
	/**
	 * 抓取链接列表
	 * @param page
	 */
	private void getLinks(Page page) {
		List<String> links = page.getHtml().xpath(linkXpaths.get(0).linksXpath).all();
        List<String> titles = page.getHtml().xpath(linkXpaths.get(0).titlesXpath).all();
        
        for(int i=1; i < linkXpaths.size() && titles.size() == 0; ++i){
        	links = page.getHtml().xpath(linkXpaths.get(i).linksXpath).all();
            titles = page.getHtml().xpath(linkXpaths.get(i).titlesXpath).all();
        }
        
        page.putField("titles", titles);
        page.putField("links", links);
        
        List<String> Pagelinks = page.getHtml().links().regex(PagelinksRex.get(0)).all();
        
        for(int i=1; i < PagelinksRex.size() && Pagelinks.size() == 0; ++i){
        	Pagelinks = page.getHtml().links().regex(PagelinksRex.get(i)).all();
        }
        
        page.addTargetRequests(Pagelinks);
	}

	/**
	 * 抓取博客内容
	 * @param page
	 */
	private void getPage(Page page){
        
        String title = page.getHtml().xpath(articleXpaths.get(0).titleXpath).toString();
        String content = page.getHtml().xpath(articleXpaths.get(0).contentXpath).toString();
        String tags = page.getHtml().xpath(articleXpaths.get(0).tagsXpath).all().toString();
        
        for(int i=1; i < articleXpaths.size() && null == title; ++i){
        	title = page.getHtml().xpath(articleXpaths.get(i).titleXpath).toString();
        	content = page.getHtml().xpath(articleXpaths.get(i).contentXpath).toString();
            tags = page.getHtml().xpath(articleXpaths.get(i).tagsXpath).all().toString();
        }
        
        if(StringUtils.isBlank(content) || StringUtils.isBlank(title)){
        	return;
        }
        
        if(!StringUtils.isBlank(tags)){
        	tags = tags.substring(tags.indexOf("[")+1,tags.indexOf("]"));
        }

        OscBlogReplacer oscReplacer= new OscBlogReplacer(codeHashtable);	//设置工具类映射关系
    	String oscContent = oscReplacer.replace(codeBeginRex, codeEndRex, content);		//处理代码格式
    	
        page.putField("content", oscContent);
        page.putField("title", title);
        page.putField("tags", tags);
	}
	
    @Override
    public Site getSite() {
        return site;
    }
}

部分xml文件:

<!-- CSND -->
	<spider-cofig>
		<domain>blog.csdn.net</domain>
		<charset>utf-8</charset>
		<name>csdn.net</name>							<!--//博客域名: 用于匹配博客spider配置  -->
		<blog-flag>/article/details/</blog-flag>			<!--//博客url的内容标志域  -->
		
		<link-xpath>							<!--//获取链接表达式  -->
			<links-xpath><![CDATA[//div[@class='list_item article_item']/div[@class='article_title']/h3/span/a/@href]]></links-xpath>
			<titles-xpath><![CDATA[//div[@class='list_item article_item']/div[@class='article_title']/h3/span/a/text()]]></titles-xpath>
		</link-xpath>
		
		<article-xpath>							<!--//获取文章表达式  -->
			<content-xpath><![CDATA[//div[@class='article_content']/html()]]></content-xpath>
			<title-xpath><![CDATA[//div[@class='details']/div[@class='article_title']/h3/span/a/text()]]></title-xpath>
			<tags-xpath><![CDATA[//div[@class='tag2box']/a/text()]]></tags-xpath>
		</article-xpath>
		
		<code-begin-rex><![CDATA[<pre.*?class=\"(.+?)\".*?>]]></code-begin-rex>		<!--//代码过滤正则表达式-头  -->
		<code-begin-rex><![CDATA[<textarea.*?class=\"(.+?)\".*?>]]></code-begin-rex>
		<code-end-rex><![CDATA[</textarea>]]></code-end-rex>			<!--//代码过滤正则表达式-尾  -->
		
		<!--//列表页url过滤表达式 -->
		<page-links-rex><![CDATA[/article/list/\d+]]></page-links-rex>		
		
		<!--//代码class映射关系 -->
		<code-hashtable>						
			<key>csharp</key>
			<osc>c#</osc>
		</code-hashtable>
		<code-hashtable>						
			<key>javascript</key>
			<osc>js</osc>
		</code-hashtable>
		<code-hashtable>						
			<key>objc</key>
			<osc>cpp</osc>
		</code-hashtable>
	</spider-cofig>



四、源码

程序已更新到git 

更多代码请看git地址:http://git.oschina.net/yashin/MoveBlog

欢迎各位OSCer 提交代码或BUG或提出宝贵意见。

由于本人资历尚浅,如有不足,敬请各位不吝赐教。


PS: 如各位OSCer 有需要从上述博客网站之外的站点搬家博客,可以给我留言,尽量满足各位的要求增加上去。

或者更欢迎您提交git 上的 pull Requests

如抓取的内容或者列表有误,请留言提供您要抓取的链接并简单说明bug,我会尽快给您答复。



© 著作权归作者所有

共有 人打赏支持
Yashin

Yashin

粉丝 252
博文 55
码字总数 5378
作品 1
深圳
高级程序员
加载中

评论(11)

shitalpig
shitalpig
@Yashin 博客搬家能不能增加一个 对google blogger blogspot.com的支持
Yashin
Yashin

引用来自“feiandxs”的评论

只是有感而发,并非说OSC的blog。 仅仅是因为想起了当年搬家来搬家去的痛苦。

osc openapi 有个人博客获取的api的,欢迎查阅使用:http://www.oschina.net/openapi/docs/user_blog_list0
feiandxs
feiandxs
只是有感而发,并非说OSC的blog。 仅仅是因为想起了当年搬家来搬家去的痛苦。
feiandxs
feiandxs
所有的提供搬家程序的BSP的有趣的地方。。
“导入我们这可方便啦”
但没有人提导出。生怕用户学会了就拔腿走人。
Yashin
Yashin

引用来自“FoxHu”的评论

这个不错,很实用!

欢迎使用,感谢支持0
Yashin
Yashin

引用来自“itfanr”的评论

引用来自“叶秀兰”的评论

@itfanr

收到 谢谢

欢迎使用,如有bug,请艾特我,会尽快解决0
Yashin
Yashin

引用来自“苗哥”的评论

很棒的功能,不过我的CSDN和ItEye里有的文章,OSC里全都有。

谢谢支持
FoxHu
FoxHu
这个不错,很实用!
苗哥
苗哥
很棒的功能,不过我的CSDN和ItEye里有的文章,OSC里全都有。
itfanr
itfanr

引用来自“叶秀兰”的评论

@itfanr

收到 谢谢
开源中国博客搬家支持导入简书

3步完成简书博文迁移 伙计们,大家好呀,随着越来越多的人喜欢在简书上看文章,我们特别推出了简书博文的一键迁移功能,然后让大家能够把自己喜欢的人或者文章,一键迁移到我们自己的博文中。...

天蓬小猪
2017/05/04
1K
19
下定决心博客搬家(再见csdn,For my oschina!)

感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正! 如有转载,请保留源作者博客信息。 tantexian的博客:http://my.oschina.net/tantexian 码云地址...

tantexian
2016/02/28
0
43
本博客公告(有问题的必看)

写这个公告的目的是: 一开始写博客的时候,我在好几个网站都注册了账号,发表的时候也基本都是同步发表或者使用的博客搬家功能,因此导致很多个网站里边都有我的全部或者部分博客。 这些博客...

涂宗勋
2016/12/18
15
0
Yashin/MoveBlog

基于osc openapi 以及 webmagic爬虫 开发的oschina博客搬家应用。 本应用作为oschina openAPI的一个实用demo,向各位OSCer 展示OSC openAPI 如何使用,以及可以实现什么功能 2014.6.6 新增功...

Yashin
2015/03/04
0
0
垂直爬虫--WebMagic

webmagic的是一个无须配置、便于二次开发的爬虫框架,它提供简单灵活的API,只需少量代码即可实现一个爬虫。 以下是爬取oschina博客的一段代码: Spider.create(new SimplePageProcessor("h...

黄亿华
2013/06/13
105.9K
82

没有更多内容

加载失败,请刷新页面

加载更多

下一页

ES6 Promise

Promise promise是异步编程的一种解决方案 1 什么是异步? 异步模式,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则...

NDweb
25分钟前
0
0
Python百分登顶年度编程语言排行榜

今天 IEEE Spectrum 发布了 2018 年度顶级编程语言排行榜。该榜单可根据流行趋势、职业方向、语言类型等多个标准各自细分生成榜单,也可以综合多个标准进行排列,使用者可以根据自己的需求过...

六库科技
29分钟前
0
0
consul笔记

安装和启动就不说了,很简单。 注册一个服务: http://localhost:8500/v1/agent/service/register put请求,json格式内容如下 { "ID": "userServiceId", //服务id "Name": "userService", //服...

朝如青丝暮成雪
29分钟前
0
0
iOS CollectionView 的那些事

UICollectionView是开发中用的比较多的一个控件,本文记录UICollectionView在开发中常用的方法总结,包括使用UICollectionViewFlowLayout实现Grid布局、添加Header/Footer、自定义layout布局...

aron1992
30分钟前
0
0
linux tar.gz zip 解压缩 压缩命令

http://apps.hi.baidu.com/share/detail/37384818 download ADT link http://dl.google.com/android/ADT-0.9.6.zip download SDK link http://dl.google.com/Android/android-sdk_r11-linux_......

owensliu
32分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部