12.java程序员必知必会类库之HTML解析库

前言

HTML是开发经常遇见的一种报文格式。但是我们日常中,更多是用它来渲染数据。利用他的很多各种标签,格式化我们的数据。一般前端接触的比较多。

但是,随着爬虫技术在互联网上越来越流行,如何处理我们爬到的HTML。。。我们当然可以针对性的代码处理每个HTML,但是每个网站的每个HTML格式,样式都可能会有比较大的差异。市场上急需要一个类库,可以将html中的数据,正常解析,抽取出来。解析HTML的框架组件,受到大家的欢迎追捧。

本节,我就java如何实现HTML解析,做简单介绍

1 JSoup

1.1 介绍

官网英文翻译如下:
jsoup 是一个处理真实世界HTML的java类库。提供了方便的api用于抽取和操作数据,使用最好的HTML5DOM方法和CSS选择器。JSoup实现了 WHATWG 这家公司的h5规范,像浏览器一样,解析HTML到同一个DOM对象。

  1. 支持从文件,URL,或者字符串中获取解析HTML
  2. dom遍历或者CSS选择器发现和抽取数据
  3. 操作HTML元素,属性和内容
  4. 根据安全列表清除用户提交的内容,以防止XSS攻击
  5. 输出整洁的HTML
  6. jsoup的设计目的是处理各种各样的HTML,jsoup将创建一个合理的解析树。

1.2 pom坐标引入

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.10.2</version>
</dependency>

1.3 使用

1.3.1 加载文档的三种方式

只要解析的不是空字符串,就能返回一个结构合理的文档,其中包含(至少) 一个head和一个body元素。

一旦拥有了一个Document,你就可以使用Document中适当的方法或它父类 Element和Node中的方法来取得相关数据。

1.3.1.1 从字符串加载文档
@Test
public void testHtml1() {
    String html = "<html><head><title>First parse</title></head>"
            + "<body><p>Parsed HTML into a doc.</p></body></html>";
    Document doc = Jsoup.parse(html);
    System.out.println(doc);
}
1.3.1.2 从文件中加载文档
@Test
public void testHtml2() throws Exception {
    Document doc = Jsoup.parse(new File("E:\\weixinData\\WeChat Files\\wxid_gv8xbkloz0wc22\\FileStorage\\File\\2023-03\\test\\src\\main\\resources\\html\\test1.html"), "utf-8");
    System.out.println(doc);
}
1.3.1.3 从URL中加载文档
@Test
public void testHtml3() throws Exception {
    Document doc = Jsoup.connect("https://blog.csdn.net/wlyang666")
    		//可以在请求头添加cookie
            .cookie("token","232893asfasddfasfdas")
            //设置爬取超时时间
            .timeout(10000)
            //get请求
            .get();
    System.out.println(doc);
}
1.3.1.4 解析一个body片段
/**
 * @Description:解析body片段
 * @Author: wanlong
 * @Date: 2023/4/26 14:43
 * @return void
 **/
@Test
public void testParsePart() {
    String html = "<table><div><p>Lorem ipsum.</p>";
    Document doc = Jsoup.parseBodyFragment(html);
    Element body = doc.body();
    System.out.println(doc);
    System.out.println("=============");
    System.out.println(body);
}

使用正常的 Jsoup.parse(String html) 方法,通常也可以得到相同的结果,但是明确将用户输入作为 body片段处理,以确保用户所提供的任何糟糕的HTML都将被解析成body元素。

1.3.2 dom主要api介绍

1.3.2.1 获取元素
getElementById(String id);
getElementsByTag(String tag);
getElementsByClass(String className);
getElementsByAttribute(String key);

siblingElements();
firstElementSibling();
lastElementSibling();
nextElementSibling();
previousElementSibling();

siblingElements();
firstElementSibling();
lastElementSibling();
nextElementSibling();
previousElementSibling();

parent();
children();
child(int index);
1.3.2.2 元素数据和属性
//获取属性
attr(String key);
//设置属性
attr(String key, String value);
//获取所有属性
attributes();
//获取元素ID
id();
//获取元素类名
className(); 
//获取元素所有类名
classNames();
//获取元素文本内容
text();
//设置元素文本内容
text(String value);
//获取元素内HTML
html();
//获取元素外HTML内容
outerHtml();
//获取元素数据内容(例如:script和style标签)
data();
//获取元素tag  和 tag名字
tag();
tagName();

1.4 测试案例

1.4.1 需求:

需要获得CSDN排行榜作者榜每个作者的用户名和名次,这里只简单演示排名如何用解析HTML的方式爬取,方式不一定合理,甚至也能通过直接api接口的方式获取数据。只是为了演示解析HTML。

1.4.2 步骤

  1. 调接口获取前100个用户的用户名
@Test
public void test(){
    Map<String,String> resultMap=new LinkedHashMap<>();
    for (int i = 1; i <5 ; i++) {
        String url = String.format("https://blog.csdn.net/phoenix/web/v2/rank?page=%s&pageSize=25&rankType=total_author", "" + i);
        String data = HttpUtil.get(url);
        JSONObject jsonData = JSONObject.parseObject(data);
        JSONArray list = jsonData.getJSONObject("data").getJSONArray("list");
        for (Object o : list) {
            JSONObject json=(JSONObject)o;
            resultMap.put(json.getString("userName"),json.getString("currentRank"));
        }
    }
    System.out.println(JSONObject.toJSONString(resultMap));
}

在这里插入图片描述
2. 逐个到这100个用户首页,爬取用户首页HTML,解析HTML,获取排名

@Test
public void testHtml3() throws Exception {
   //这里正常维护的是前100个用户的用户名和接口获取的排名信息,这里考虑到用户隐私不展示,用我的账号做测试
   String str="{\"wlyang666\":\"22\"}";
   Map<String, String> resultMap = new LinkedHashMap<>();
   //1.读取博客总榜
   JSONObject json = JSONObject.parseObject(str);
   for (Map.Entry<String, Object> stringObjectEntry : json.entrySet()) {
       String username = stringObjectEntry.getKey();
       String url = String.format("https://blog.csdn.net/%s", username);
       //2.遍历每个作者,读取每个作者排名
       Document doc = Jsoup.connect(url)
               .cookie("token", "232893asfasddfasfdas")
               .timeout(10000)
               .get();
       //解析文档
       Elements paimingDiv = doc.getElementsMatchingOwnText("排名");
       for (Element element : paimingDiv) {
           try {
               String paiming = element.firstElementSibling().text();
               resultMap.put(username, paiming);
           } catch (Exception e) {
               System.out.println("有异常" + element);
               e.printStackTrace();
           }
       }
   }
   System.out.println(JSONObject.toJSONString(resultMap));
}

1.4.3 运行结果

{“wlyang666”:“17,152”}

1.5 注意事项:

  1. 解析HTML可传参数 baseUri 是用来将相对 URL 转成绝对URL,并指定从哪个网站获取文档。
  2. 解析html有各种可能失败的场景,包括上面的案例,在真实测试的时候,也有个别客户解析失败,这种建议先捕获异常,后期考虑看是否做兼容处理,还是个别数据不重要直接丢弃
  3. 爬取网页过程,可能需要校验登录信息等,此时可以在请求头封装token,cokkie等信息

参考文档:

jsoup官网

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值