使用Java爬虫得到CSDN博客信息并保存(一)

1.

需求:

       使用java爬虫得到blog.csdn.net首页的所有出现的博客地址,并逐个访问,把博客信息保存到本地。

2.

思路:

      (1).通过URL类的方法得到首页的HTML源码,使用正则把博客的url都放到一个String数组中

      (2).再逐个访问个人博客的首页得到HTML源码,使用正则提取到需要的信息

      (3).使用IO把得到的信息保存到本地

3.

具体实现:

      这里我把程序分成了两个部分:得到博客中需要的信息、把信息保存到文件中。这篇博客先讲怎样得到博客信息。

4.

代码实现:

package cn.test12.WebRobot04;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
 * 这个类就是得到cdsn的imgUrl,visits,titles,Bloger
 * 步骤:
 *    1.构造方法,传入url,得到属性urlString和webLine
 * 总结:
 *    1.set集合转String[]可以使用
 String[] strs =  set.toArray(new String[0]);
 System.out.println(Arrays.toString(strs));
 切勿使用 strs = (String[])set.toArray()会出现转换异常
 */
public class GetCsdn {
	//代表访问的CSDN得URL
	public String urlString = null;
	//把整个网页都放到一行里面,方便正则表达式进行匹配
	public String webLine = null;

	// 创建对象后,这个对象中就已经有了表示这个网页的webLine
	public GetCsdn(String urlString) throws Exception {
		this.urlString = urlString;
		// 创建链接对象
		URL url = new URL(this.urlString);
		// 创建根据链接对象写出通道对象
		URLConnection uc = url.openConnection();
		uc.setRequestProperty("User-Agent",
				"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0");
		// 根据通道对象,得到读的方法,并指明字节流是utf-8格式的
		BufferedReader br = new BufferedReader(new InputStreamReader(
				uc.getInputStream(), "utf-8"));
		// 把得到的数据一行一行的交给filter()
		String line = null;
		StringBuffer sb = new StringBuffer();
		while ((line = br.readLine()) != null) {
			// 这里默认就不添加回车换行,所以保存好就是一行
			sb.append(line);
		}
		this.webLine = new String(sb);
	}

	// 一开始博主的名字是通过传入的得url得到的,但是,后来需要多页的时候,就不可以了,这里采用猜得到博主的主页再进行截取
	public String getBloger() {
		// 这句话得到的网址是:href="http://blog.csdn.net/xuejiayue1105"
		String regex = "href=\"http://blog.csdn.net/\\w+\"";
		Pattern pa = Pattern.compile(regex);
		Matcher ma = pa.matcher(this.webLine);
		ma.find();
		return ma.group().split("\"")[1].substring(21);
	}

	public String getWebName() {
		// 这句话得到<div id="blog_title"> <h2> <a
		// href="http://blog.csdn.net/wangquannetwork">WangQuanNetwork专栏</a></h2>
		// <h3></h3> <div class="clear"> </div>
		String regex = "<div id=\"blog_title\">.+?</div>";
		// 也可以用这个表达式,这个表达式捕获组1就是网站名字了
		// String regex = "<div id=\"blog_title\">.+?>(\\S+)</a>.+</div>";
		Pattern pa = Pattern.compile(regex);
		Matcher ma = pa.matcher(this.webLine);
		ma.find();
		String temp = ma.group();
		String tempRegex = "<.+?>";
		return temp.replaceAll(tempRegex, "").trim();

	}

	public String[] getVisits() {
		// 2.写出正则对象
		String regex = "<li>[\u4E00-\u9FA5]+.+?</li>";
		Pattern pa = Pattern.compile(regex);
		// 3.处理数据得到引擎对象
		Matcher matcher = pa.matcher(this.webLine);
		// 4.遍历引擎对象
		HashSet<String> visits = new HashSet<>();
		while (matcher.find()) {
			visits.add(matcher.group().replaceAll("<.+?>", ""));
		}
		// 返回数组类型的数据
		return visits.toArray(new String[0]);
	}

	public String[] getTitles() throws Exception {
		// 2.编写正则对象
		String tempRegex = "[0-9]+\">尾页";
		Pattern tempPa = Pattern.compile(tempRegex);
		// 3.使用正则对象得到引擎
		Matcher tempMatcher = tempPa.matcher(this.webLine);
		tempMatcher.find();
		// 4.得到一共有多少页
		int count = Integer.parseInt(tempMatcher.group().split("\"")[0]);
		// 5.这里需求是希望可以让先捕获标题在前面,所以这里使用可以排序的TreeSet集合,实现了比较器接口
		TreeSet<String> titles = new TreeSet<>(new Comparator<String>() {
			public int compare(String o1, String o2) {
				// 这里永远都返回1,表示后来的永远都在后面
				return 1;
			}
		});
		// 5.根据页数常见循环,每个循环中都是自己的组成的一个链接,调用getCsdn类中的方法得到html内容,然后再判断,得到title
		for (int i = 1; i <= count; i++) {
			String onePageLine = new GetCsdn(this.urlString + "/article/list/"
					+ i).webLine;
			// 2.编写正则对象
			String regex = "<span class=\"link_title\">.+?</a></span>";
			Pattern pa = Pattern.compile(regex);
			// 3.使用正则对象得到引擎
			Matcher matcher = pa.matcher(onePageLine);
			// 4.输出的引擎中的内容,首先把标签都去掉,然后使用String自带的trim()方法把标题旁边的空格都去掉
			// <span class="link_title"><a
			// href="/qq_20607829/article/details/47747947"> 《学习记录》Toast带图片的显示
			// </a></span>
			while (matcher.find()) {
				titles.add(matcher.group().replaceAll("<.+?>", "").trim());
			}
		}
		return titles.toArray(new String[0]);
	}

	public String getImgUrl() {
		// 2.写出正则对象
		// 这是早期使用的正则,但是因为如果博主有了专栏,就会截取不正常
		// String regex = "<img src=\"http://avatar.csdn.net.+?/>";
		String regex = "<img src=\"http://avatar.csdn.net/\\w{1}/.+?/>";
		Pattern pa = Pattern.compile(regex);
		// 3.处理数据得到引擎对象
		Matcher matcher = pa.matcher(this.webLine);
		// 4.遍历引擎对象
		matcher.find();
		// <img src="http://avatar.csdn.net/0/8/9/1_qq_20607829.jpg"
		// title="访问我的空间" style="max-width:90%"/>
		// 首先得到还有无用信息的链接,然后使用"进行切割,获取到第二段,就是需要的链接
		return matcher.group().split("\"")[1];
	}

	public String[] getBlogHomePage() {
		// 这句话得到的网址是:href="http://blog.csdn.net/wangquanjava"
		String regex = "href=\"http://blog.csdn.net/\\w+\"";
		Pattern pa = Pattern.compile(regex);
		Matcher ma = pa.matcher(this.webLine);
		// 使用HashSet集合的唯一性,把相同的链接去掉,但是这时链接中还有没用的部分
		HashSet<String> tempLinks = new HashSet<>();
		while (ma.find()) {
			tempLinks.add(ma.group());
		}
		// 新建一个集合用来放真正的链接
		HashSet<String> links = new HashSet<>();
		for (String link : tempLinks) {
			// 对之前的连接使用"进行截取,取其第二部分
			link = link.split("\"")[1];
			links.add(link);
		}
		return links.toArray(new String[0]);
	}

	public static void main(String[] args) throws Exception {
		GetCsdn gc = new GetCsdn("http://blog.csdn.net/wangquannetwork");
		System.out.println(gc.getBloger());
		System.out.println("----------------------------");
		System.out.println(gc.getImgUrl());
		System.out.println("----------------------------");
		System.out.println(gc.getWebName());
		System.out.println("----------------------------");
		System.out.println(Arrays.toString(gc.getTitles()));
		System.out.println("----------------------------");
		System.out.println(Arrays.toString(gc.getVisits()));
		System.out.println("----------------------------");

	}
}

5.显示结果


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值