欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java学习之Java爬虫Jsoup学习

程序员文章站 2022-05-05 15:05:55
...

今天学习了一下Java爬虫,感觉还是挺有趣的,在这里写一下今天的收获,方便自己以后如有遗忘,好重新来温习,毕竟温故而知新。

废话不多说,我要开始啦。

在说Jsoup之前我得先说一下java.net.Socket,这个东西,为什么要说这个呢,接触过Java网络编程的猿友们应该都知道这个是Java中的套接字,是Java中网络编程的一个关键类,简单介绍一下他的使用方式吧:

//这里的address,就是我们的ip,也可以是域名,而port就是端口,每一个程序都对应一个独立的端口
Socket socket = new Socket(address,port)

其实我要说的是我们爬虫便可以用Socket来做,但是这个东西并不友好对于开发人员来说,为什么呢?我们来看下面代码就知道了:

public class TestSocket {

	/**
	 * 网络访问java世界归于流操作,类似文件操作
	 * (1)创建输出流。发送协议HTTP
	 * (2)GET访问网站:www.baidu.com http1.1
	 * (3)标识:长连接Connection:Keep-Alive
	 * (4)接收输入流,转换成文字,while((str == br.readLine)!=null)
	 * (5)打印
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws  Exception {
		//baidu.com(域名),xxx.baidu.com(二级域名),xxx.xxx.baidu.com(三级域名)
		//主域名 (一级域名)
		String host = "www.baidu.com";
		int port = 80;
		Socket socket = new Socket(host, port);
		//创建输出流
		BufferedWriter bw = new BufferedWriter(
				new OutputStreamWriter(socket.getOutputStream()));
		
		//模拟发起http1.1协议,
		//http1.0:表示是短链接,连接后就会断开,用于以前网络不稳定
		//http1.1:表示是长链接,发送请求后一直保持链接,当下流行,毕竟网络越来越发达,越来越稳定
		//"/"代表请求网站的根(类似Linux的文件目录)
		bw.write("GET / HTTP/1.1\r\n");
		bw.write("Host: "+host+"\r\n");
		bw.write("Connection: Keep-Alive\r\n\r\n");
		bw.flush();
		
		//接收返回值
		BufferedReader br = new BufferedReader(
				new InputStreamReader(socket.getInputStream(),"utf-8"));
		
		String str="";
		while((str = br.readLine())!=null) {
			System.out.println(str);
		}
		bw.close();
		socket.close();
	}
}

看到上面相信大家看到就觉得很烦有没有,本人反正是看不惯这东西,开始写这东西的时候就因为斜杠和空格一直没有结果,而且这种得到的结果难以进行解析。

那么牛X的就来了就是Jsoup,这个东西就很牛了,他可以解析HTML页面,是一个HTML解析器,能够通过HTML页面中的一些标签来爬取网页上的信息,我这里用某东学习了一下;那么他强大在哪里呢
1.它可以通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据
2.他操作简单,往往几行代码便能从网上爬取到自己想要的信息
3.他的选择器取值就像是js取值操作一样简单,通过标签中的属性来取值,也可以通过标签来取 值
话不多说,我们上代码:
1)下面是爬取某东网站的商品标题

@Test
	public void title() throws Exception {
		//这是要爬去取的网站的地址
		String url = "http://item.jd.com/7437690.html";
		//这里是建立连接,发起对该网站的请求
		Connection con = Jsoup.connect(url);
		//这里是获取一个document对象,这里面存储的是页面的源代码
		Document doc = con.get();
		//这里是通过选择器用class属性来获取相应的一个Elements集合,这里面存储的是与这个class有关的内容(包括标签和文本内容)
		Elements els = doc.select(".sku-name");
		//这里是获取集合中的第一个元素中的文本内容
		String title = els.get(0).text();
		System.out.println(title);
	}

这里有一点要注意:我们现在很多网站的样式都是用的bootstrap,故而一个属性会是如下形式:

<div class = "btn btn-sm p-img"></div>

对于这种形式我们在用选择器时要这样写:

doc.selec(".btn.btn-sm.p-img")

要用".“来代替之间的空格,而且对于class属性要在前面加一个”.",如果是id则在前面加一个“#”;这样是不是跟jQuery的方式很像呢。如果时选择器中的内容是HTML标签的话标签之间用空格隔开即可。
2)下面是图片的获取方式(表现了上面说的选择器的类容为id属性和标签)

public void image() throws Exception {
		String url = "http://item.jd.com/7437690.html";
		Connection con = Jsoup.connect(url);
		Document doc = con.get();
		//这里的#spec-list就是标签的id属性,ul、li、img 都是html标签
		Elements els = doc.select("#spec-list ul li img");
		String img = "";
		for (Element el : els) {
			img = "http:" + el.attr("src");
			System.out.println(img);
		}

	}

3)有些网站的价格看着有值,而在获取时却并没有值,这是为什么呢,这个就涉及到Ajax了,我们的Jsoup在做请求时只能对第一的请求做处理,而Ajax就是通过二次请求来对价格进行设置值的,想要能获取到价格,我们的找到这个二次请求,因为这个才是价格的真实请求,上代码,不多说,至于怎么找这个请求,在浏览器上就可以找到,开发者工具,最好用谷歌浏览器,毕竟别人还是有别人牛逼的道理的:

public void price() throws Exception {
		// https://p.3.cn/prices/mgets
		// ?callback=jQuery7306041
		// &type=1
		// &area=4_48205_48332_0
		// &pdtk=
		// &pduid=15663839387931114997946
		// &pdpin=
		// &pin=null
		// &pdbp=0
		// &skuIds=J_7437690%2CJ_49820781340%2CJ_4741808%2CJ_33239063849%2CJ_33341525798%2CJ_3494451%2CJ_797802%2CJ_1875996%2CJ_37652171093
		// &ext=11100000
		// &source=item-pc
		// 真实地址:https://p.3.cn/prices/mgets?skuIds=J_7437690
		String url = "https://p.3.cn/prices/mgets?skuIds=J_7437690";
		// 默认早期不管,当成html,新的规范强制要求要告诉返回是什么
		String json = Jsoup.connect(url).userAgent(
				"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36")
				.ignoreContentType(true).execute().body();
		// System.out.println(json);

		// 利用jackson解析json串
		ObjectMapper MAPPER = new ObjectMapper();
		// 转换成jackson自己的对象
		JsonNode node = MAPPER.readTree(json);

		// 获取key值为p所对应的值
		JsonNode nodeSub = node.get(0);
		JsonNode priceNode = nodeSub.get("p");
		Double price = priceNode.asDouble();
		System.out.println(price);
	}

由于这里价格他是以json格式存储的故而我们才会进行数据处理注释写的都比较清楚,可以仔细读一**释

对了json数据处理与jsoup的使用都需要导入一些包哦。
暂时就只学了这么多,猿友们有什么不同的见解或者有什么指正的地方本人一定虚心接受,欢迎大家留言评论哦