【学习笔记】Java网络爬虫实战——分别使用Jsoup和JsoupXpath对w3school网站进行爬取解析

        由于博主前一段时间已经自学过了Python网络爬虫,因此在自学Java网络爬虫时进展还是蛮快的。据我目前所学习的Jsoup来看,可以与Python中的request库作为参照进行学习。因此在昨天刚学完Jsoup获取网页后,今天博主便花了一上午时间对Jsoup解析网页进行了学习和分析。
        首先,我们先来看一下要爬取和解析的HTML页面。因为刚入门Java网络爬虫,并且据我所知现在大多网站都具备反爬虫手段,因此先用w3school作为学习练手(https://www.w3school.com.cn/python/python_ml_getting_started.asp)。
在这里插入图片描述
        其中,上图箭头所指的列表便是我们今天要爬取和解析的目标。要想解析图中所示每个课程表的标题及每个课程表对应的URL,则需要遍历选中的元素。

遍历代码模块如下所示:

// 遍历每一个li节点
		for(Element ele : elements) {
			// .text()为解析标签中的文本内容
			String title = ele.select("a").text();
			// .attr(String)表示获取标签内某属性内容
			String course_url = ele.select("a").attr("href");
			System.out.println("标题为:" + title + "\t\tURL为:" + course_url);
		}

        关于Jsoup解析URL加载的Document,可以先指定URL(可先使用Jsoup请求URL,获取对应的Document)。之后,再使用select(String cssQuery)方法定位要解析的内容。

Jsoup请求及解析URL代码块如下所示:

// 获取URL对应的Document
		Document doc = Jsoup.connect("https://www.w3school.com.cn/python/"
				+ "python_ml_getting_started.asp").timeout(5000).get();
		// 层层定位到要解析的内容,可以发现包含多个li元素
		Elements elements = doc.select("div#course").select("li");

        首先,利用谷歌自带的抓包工具定位到需要解析的HTML片段,分析发现需要解析的每个课程表的标题及URL在元素a标签中,元素a标签在元素li标签中,元素li标签在div[id=course]中。针对这种层层嵌套(禁止套娃x)的结构,可以使用Jsoup中的遍历解析出每部分内容。

程序运行结果:

在这里插入图片描述
        说完了Jsoup解析,我们再来说说支持Xpath语法的JsoupXpath解析。JsoupXpath是在Jsoup的基础上扩展支持了Xpath语法的HTML文件解析器,使用时需要先在Maven工程的pom.xml中添加JsoupXpath对应的dependency。

<dependency>
      <groupId>cn.wanghaomiao</groupId>
      <artifactId>JsoupXpath</artifactId>
      <version>2.2</version>
</dependency>

        接下来我将直接展示通过JsoupXpath编写的解析程序的源代码,并对里面新学的部分内容进行分析。

程序源代码:

package com.test.study;

import java.util.List;
import org.seimicrawler.xpath.JXDocument;
import org.seimicrawler.xpath.JXNode;

public class JsoupXpathTset {

	public static void main(String[] args) {
		// 基于URL创建JXDocument
		JXDocument jxd = JXDocument.createByUrl("https://www.w3school.com.cn/"
				+ "python/python_ml_getting_started.asp");
		// Xpath语句
		String str = "//*[@id='course']/ul/li/a";
		// 获取节点集合
		List<JXNode> list = jxd.selN(str);
		// 遍历节点
		for(int i = 0; i < list.size(); i++) {
			JXNode node = list.get(i);
			System.out.println("标题为:" + node.asElement().text() + 
					"\t\tURL为:" + node.asElement().attr("href"));
		}
	}
}

        使用JsoupXpath编写的程序,总体来说和Jsoup编写的程序是不一样的,但是输出结果是相同的,因此不进行展示。
        其中:

public List<JXNode> selN(String xpath) throws XpathSyntaxErrorException{
        List<JXNode> finalRes = new LinkedList<>();
        List<org.seimicrawler.xpath.JXNode> jxNodeList = jxDoc.selN(xpath);
        for (org.seimicrawler.xpath.JXNode n:jxNodeList){
            if (n.isString()){
                finalRes.add(JXNode.t(n.asString()));
            }else {
                finalRes.add(JXNode.e(n.asElement()));
            }
        }
        return finalRes;
    }

        根据查询解析Xpath语句JXDocument.selN(String Xpath)方法可以发现.asElement()方法用于非字符串(本程序中为JXNode类型的node节点),而.asString()方法用于字符串。
        最后,补充一些JsoupXpath的函数及用法。

String id = element.attr("id");                //获取id的属性值
Elements children = element.children();        //获取元素下的所有子对象元素
String tag = element.tagName();                //获取元素的标签名
String text = element.text();                  //获取元素的标签体内容
  • text() :提取节点的自有文本;
  • node() :提取所有节点;
  • position(): 返回当前节点所处在同胞中的位置;
  • last() :返回同级节点中的最后那个节点;
  • first() :返回同级节点中的第一个节点;
  • allText():提取节点下全部文本,取代类似 //div/h3//text()这种递归取文本用法;
  • html():获取全部节点的内部的html;
  • outerHtml():获取全部节点的 包含节点本身在内的全部html;
  • num():抽取节点自有文本中全部数字,如果知道节点的自有文本(即非子代节点所包含的文本)中只存在一个数字,如阅读数,评论数,价格等那么直接可以直接提取此数字出来。如果有多个数字将提取第一个匹配的连续数字。

猜你喜欢

转载自blog.csdn.net/qq_42506411/article/details/106941076