爬虫学习4-HTML和XML数据的分析与解析

目前在 Java 中,解析 HTML 工具主要包含以下几种:
1,jsoup:强大的 HTML 解析工具,支持以 jQuery 中 CSS Selector 的方式提取 HTML 中的元素,学习成本较低。,
2,HtmlCleaner:另外一款开源的 Java 语言的 HTML 文档解析器,支持以 XPath 的方式提取 HTML 中的元素。另外,在此说明,学习 XPath 语法对于使用另外一款基于 Selenium 的爬虫工具特别有帮助。
3,Htmlparser:对 HTML 进行有效信息搜索和提取的一款 Java 工具,但该工具已长时间不维护了。
我在前面的篇章中,已介绍了 jsoup 工具解析 HTML 的内容,因此,在本文将主要介绍 HtmlCleaner 和 HtmlParser 工具对 HTML 的解析。

针对 XML 数据,Java 也有很多工具进行解析,,主要介绍 jsoup 解析 XML。

HtmlCleaner 解析 HTML

     引入HtmlCleaner的jar包,maven依依赖如下:


		<!--一款开源的 Java 语言的 HTML 文档解析器,支持以 XPath 的方式提取 HTML 中的元素https://mvnrepository.com/artifact/net.sourceforge.htmlcleaner/htmlcleaner -->
		<dependency>
			<groupId>net.sourceforge.htmlcleaner</groupId>
			<artifactId>htmlcleaner</artifactId>
			<version>2.22</version>
		</dependency>

Xpath

     Xpath学习教程:xpath

         XPath 是一门在 XML 文档中查找信息的语言,其可用来在 XML 文档中对元素和属性进行遍历。在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档节点(或称为根节点)。其在 HTML 解析中,主要是对节点进行选取,而在选取的过程中,需要路径进行定位。

       Xpath主要语法:语法

解析HTML

      使用 HtmlCleaner 首先要对其进行初始化,初始化之后,我们便可以使用 Xpath 语法操作节点。以下为 w3school 页面的解析案例。解析的内容如下:

代码如下:

public static void test1() throws IOException, XPatherException {
        //这里笔者使用jsoup获取html文件
        Document doc = Jsoup.connect("http://www.w3school.com.cn/b.asp").timeout(5000).get();
        //转化成String格式
        String html =doc.html();
        //使用Htmlcleaner解析数据
        //初始化对象
        HtmlCleaner cleaner = new HtmlCleaner();
        //System.out.println(html);
        //解析HTML文件
        TagNode node = cleaner.clean(html);
        //通过Xpath定位标题的位置,这里使用//h1和/h1的结果是一样的
        Object[]  ns = node.evaluateXPath("//div[@id='w3school']//h1");
        System.out.println("HTML中的标题是:\t" + ((TagNode)ns[0]).getText());
        Object[]  ns1 = node.evaluateXPath("//*[@id='w3school']/h1");
        System.out.println("HTML中的标题是:\t" + ((TagNode)ns1[0]).getText());
        //遍历获取课程名以及课程地址
        //这里使用//a表示不考虑位置,如果使用/a获取不到内容
        Object[]  ns2 = node.evaluateXPath("//*[@id='course']/ul//a");
        for(Object on : ns2) {
            TagNode n = (TagNode) on;
            System.out.println("课程名为:\t" + n.getText() + "\t地址为:\t" + n.getAttributeByName("href"));
        }
        //获取每个课程名称以及其对应的简介
        Object[]  ns3 = node.evaluateXPath("//*[@id='maincontent']//div");
        for (int i = 1; i < ns3.length; i++) {
            TagNode n = (TagNode) ns3[i];
            //获取课程名称
            String courseName = n.findElementByName("h2", true).getText().toString();
            //循环遍历所有的p节点获取课程简介
            Object[] objarrtr = n.evaluateXPath("//p");
            String summary = "";
            for(Object on : objarrtr) {
                summary += ((TagNode) on).getText().toString();
            }
            System.out.println(courseName + "\t" + summary);
        }
    }

输出如下:

HTML中的标题是:	浏览器脚本教程
HTML中的标题是:	浏览器脚本教程
课程名为:	JavaScript	地址为:	/js/index.asp
课程名为:	HTML DOM	地址为:	/htmldom/index.asp
课程名为:	jQuery	地址为:	/jquery/index.asp
课程名为:	AJAX	地址为:	/ajax/index.asp
课程名为:	JSON	地址为:	/json/index.asp
课程名为:	DHTML	地址为:	/dhtml/index.asp
课程名为:	E4X	地址为:	/e4x/index.asp
课程名为:	WMLScript	地址为:	/wmlscript/index.asp
Disconnected from the target VM, address: '127.0.0.1:51921', transport: 'socket'
JavaScript	JavaScript 是世界上最流行的脚本语言。JavaScript 是属于 web 的语言,它适用于 PC、笔记本电脑、平板电脑和移动电话。JavaScript 被设计为向 HTML 页面增加交互性。许多 HTML 开发者都不是程序员,但是 JavaScript 却拥有非常简单的语法。几乎每个人都有能力将小的 JavaScript 片段添加到网页中。如果您希望学习更多关于 JavaScript 的知识,请马上访问我们的 JavaScript 教程。
HTML DOM	HTML DOM 定义了访问和操作 HTML 文档的标准方法。DOM 以树结构表达 HTML 文档。开始学习 HTML DOM !
jQuery 教程	jQuery 是一个 JavaScript 库。jQuery 极大地简化了 JavaScript 编程。jQuery 很容易学习。开始学习 jQuery !
jQuery Mobile 教程	jQuery Mobile 是一个为触控优化的框架,用于创建移动 web 应用程序。jQuery 适用于所有流行的智能手机和平板电脑。jQuery Mobile 构建于 jQuery 库之上,这使其更易学习,如果您通晓 jQuery 的话。它使用 HTML5、CSS3、JavaScript 和 AJAX 通过尽可能少的代码来完成对页面的布局。开始学习 jQuery Mobile !
AJAX	AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。AJAX 不是新的编程语言,而是一种使用现有标准的新方法。AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。开始学习 AJAX !
JSON	JSON:JavaScript 对象表示法(JavaScript Object Notation)。JSON 是存储和交换文本信息的语法。类似 XML。JSON 比 XML 更小、更快,更易解析。假如您希望学习更多关于 JSON 的知识,请访问我们的 JSON 教程。
DHTML	DHTML 是一种使 HTML 页面具有动态特性的艺术。DHTML 是一种创建动态和交互 WEB 站点的技术集。对大多数人来说,DHTML 意味着 HTML、样式表和 JavaScript 的组合。开始学习 DHTML !
E4X	E4X 是对 JavaScript 的新扩展。E4X 向 JavaScript 添加了对 XML 的直接支持。E4X 是正式的 JavaScript 标准。开始学习 E4X !
WMLScript	WMLScript 是用于 WML 页面的脚本语言。WML 页面可以在 WAP 浏览器中显示。WMLScript 用于验证用户输入、生成对话框、显示出错消息以及访问用户代理设备等等。开始学习 WMLScript !

       在使用 evaluateXPath(String xPathExpression) 操作 TagNode 时得到的是 Object[] 数组,通过对该数组的操作便能够获取数据。另外,HtmlCleaner 还提供了很多种用法,例如上述程序中的 findElementByName()、getAttributeByName() 等操作方法

HtmlParser解析HTML

    引入HtmlParser解析HTML的jar包:

<!--对 HTML 进行有效信息搜索和提取的一款 Java 工具,但该工具已长时间不维护了 https://mvnrepository.com/artifact/org.htmlparser/htmlparser -->
		<dependency>
			<groupId>org.htmlparser</groupId>
			<artifactId>htmlparser</artifactId>
			<version>2.1</version>
		</dependency>

HtmlParser基础教程:基础教程

HTMLParser 的核心模块是 Parser 类,在实际的应用中也是通过该类分析 HTML 文件。该类中常用的构造方法总结如下:

方法 说明
Parser() 无参数构造。
Parser(Lexer lexer) 通过 Lexer 构造 Parser,在案例程序中我会使用到。
Parser(String resource) 给定一个 URL 或文件资源,构造 Parser。
Parser(URLConnection connection) 使用 URLConnection 构造 Parser。

对大多数使用这来说,可以通过 URLConnection 或者通过其他工具获取的 HTML 字符串来初始化 Parser。HTMLParser 将解析过的信息保存为树结构,其中重要的是 Node 数据类型。Node 中包含的方法有对树结构操作的函数以及获取 Node 节点中包含内容的函数。

方法 说明
NodeList getChildren() 取得子节点的列表
Node getParent () 取得父节点
Node getFirstChild () 取得第一个子节点
Node getLastChild () 取得最后一个子节点
Node getPreviousSibling () 取得上一个兄弟节点
Node getNextSibling () 取得下一个兄弟节点
String getText () 获取节点中的文本
String toPlainTextString() 获取纯文本信息
String toHtml () 返回该节点对应的 HTML
Page getPage () 取得这个 Node 对应的 Page 对象
int getStartPosition () 取得这个 Node 在 HTML 页面中的起始位置
int getEndPosition () 取得这个 Node 在 HTML 页面中的结束位置

同时在 HTMLParser 提供了 Filter 操作,即对结果进行过滤。常用的过滤器有:

过滤器 说明
TagNameFilter 根据 Tag 的名字进行过滤。
HasChildFilter 返回有符合条件的子节点的节点,需要另外一个 Filter 作为过滤子节点的参数。
HasAttributeFilter 匹配出包含指定名称的属性,或者指定属性的节点。
StringFilter 过滤显示字符串中包含指定内容的标签节点。
RegexFilter 正则表达式匹配节点。
NodeClassFilter 根据已定义的标签类获取节点。
LinkStringFilter 判断链接中是否包含某个特定的字符串,可以用来过滤出指向某个特定网站的链接。
OrFilter 是结合几种过滤条件的“或”过滤器。
AndFilter 结合几种过滤条件的“与”过滤器。

使用案例:

           首先我给出第一个使用案例。给定 HTML 字符串,使用 Parser(Lexer lexer) 构造,结合过滤器的使用提取网页中的所有链接(即 href 对应的内容以及链接对应的标题),仍以上面的 w3school 的页面为案例(http://www.w3school.com.cn/b.asp)

案例1代码:

public static void test1() throws ParserException, IOException {
        //这里笔者使用Jsoup获取html文件
        Document doc = Jsoup.connect("http://www.w3school.com.cn/b.asp").timeout(5000).get();
        //转化成String格式
        String html =doc.html();
         //使用Lexer构造
        Lexer lexer = new Lexer(html);
        Parser parser = new Parser(lexer);
       //过滤页面中的链接标签
        NodeFilter filter = new NodeClassFilter(LinkTag.class);
        //获取匹配到的节点
        NodeList list = parser.extractAllNodesThatMatch(filter);
       //遍历每一个节点
        for(int i=0; i<list.size();i++){
            Node node = (Node)list.elementAt(i);
            System.out.println("链接为:" + ((LinkTag) node).getLink() + "\t标题为:" + node.toPlainTextString() );
        }
    }

输出:

链接为:/index.html	标题为:w3school 在线教程
链接为:/h.asp	标题为:HTML 系列教程
链接为:/b.asp	标题为:浏览器脚本
链接为:/s.asp	标题为:服务器脚本
链接为:/d.asp	标题为:ASP.NET 教程
链接为:/x.asp	标题为:XML 系列教程
链接为:/ws.asp	标题为:Web Services 系列教程
链接为:/w.asp	标题为:建站手册
链接为:/js/index.asp	标题为:JavaScript
链接为:/htmldom/index.asp	标题为:HTML DOM
链接为:/jquery/index.asp	标题为:jQuery
链接为:/ajax/index.asp	标题为:AJAX
链接为:/json/index.asp	标题为:JSON
链接为:/dhtml/index.asp	标题为:DHTML
链接为:/e4x/index.asp	标题为:E4X
链接为:/wmlscript/index.asp	标题为:WMLScript
链接为:/js/index.asp	标题为:JavaScript 教程
链接为:/htmldom/index.asp	标题为:开始学习 HTML DOM
链接为:/jquery/index.asp	标题为:开始学习 jQuery
链接为:/jquerymobile/index.asp	标题为:开始学习 jQuery Mobile
链接为:/ajax/index.asp	标题为:开始学习 AJAX
链接为:/json/index.asp	标题为:JSON 教程
链接为:/dhtml/index.asp	标题为:开始学习 DHTML
链接为:/e4x/index.asp	标题为:开始学习 E4X
链接为:/wmlscript/index.asp	标题为:开始学习 WMLScript
链接为:/jsref/index.asp	标题为:JavaScript
链接为:/jquery/jquery_reference.asp	标题为:jQuery
链接为:/vbscript/vbscript_ref_functions.asp	标题为:VBScript
链接为:/jsref/index.asp	标题为:HTML DOM
链接为:/example/jseg_examples.asp	标题为:JavaScript 实例
链接为:/example/jsrf_examples.asp	标题为:JavaScript 对象实例
链接为:/example/hdom_examples.asp	标题为:HTML DOM 实例
链接为:/jquery/jquery_examples.asp	标题为:jQuery 实例
链接为:/jquerymobile/jquerymobile_examples.asp	标题为:jQuery Mobile 实例
链接为:/example/dhtm_examples.asp	标题为:DHTML 实例
链接为:/example/ajax_examples.asp	标题为:AJAX 实例
链接为:/example/vbst_examples.asp	标题为:VBScript 实例
链接为:/js/js_quiz.asp	标题为:JavaScript 测验
链接为:/jquery/jquery_quiz.asp	标题为:jQuery 测验
链接为:http://www.ykinvestment.com/	标题为:上海赢科投资有限公司

案例2:

            基于 Filter 层层过滤的方式解析想要的数据,案例程序使用 Parser(String resource) 构造

代码:

public static void test2() throws ParserException, IOException{
        //生成一个解析器对象,用网页的 url 作为参数
        Parser parser = new Parser("http://www.w3school.com.cn/b.asp");
        //设置网页的编码(GBK)
        parser.setEncoding("gbk");
        //过滤页面中的标签
        NodeFilter filtertag= new TagNameFilter("ul");
        //父节点包含ul
        NodeFilter filterParent = new HasParentFilter(filtertag);
        //选择的节点为每个li
        NodeFilter filtername = new TagNameFilter("li");
        //并且li节点中包含id属性
        NodeFilter filterId= new HasAttributeFilter("id");
        //并操作
        NodeFilter filter = new AndFilter(filterParent,filtername);
        //并操作
        NodeFilter filterfinal = new AndFilter(filter,filterId);
        //选择匹配到的内容
        NodeList list = parser.extractAllNodesThatMatch(filterfinal);  
        //循环遍历
        for(int i=0; i<list.size();i++){
            //获取li的第一个子节点
            Node node = (Node)list.elementAt(i).getFirstChild();
            System.out.println( "链接为:" + ((LinkTag) node).getLink() +"\t标题为:" + node.toPlainTextString() );
        }
    }

输出:

链接为:http://www.w3school.com.cn/h.asp	标题为:HTML 系列教程
Disconnected from the target VM, address: '127.0.0.1:52743', transport: 'socket'
链接为:http://www.w3school.com.cn/b.asp	标题为:浏览器脚本
链接为:http://www.w3school.com.cn/s.asp	标题为:服务器脚本
链接为:http://www.w3school.com.cn/d.asp	标题为:ASP.NET 教程
链接为:http://www.w3school.com.cn/x.asp	标题为:XML 系列教程
链接为:http://www.w3school.com.cn/ws.asp	标题为:Web Services 系列教程
链接为:http://www.w3school.com.cn/w.asp	标题为:建站手册

案例3:

  该案例是基于 CSS 选择器来解析想要的数据

代码:

public static void test3() throws ParserException, IOException{
        //使用URLConnection请求数据
        URL url = new URL("http://www.w3school.com.cn/b.asp");
        URLConnection conn = url.openConnection();
        Parser parser = new Parser(conn);
       //通过css选择器解析内容
        CssSelectorNodeFilter Filter=new CssSelectorNodeFilter ("#course > ul > li");
        //选择匹配到的内容
        NodeList list = parser.extractAllNodesThatMatch(Filter);
        //循环遍历
        for(int i=0; i<list.size();i++){
            //获取li的第一个子节点
            Node node = (Node)list.elementAt(i).getFirstChild();
            System.out.println( "链接为:" + ((LinkTag) node).getLink() +"\t标题为:" + node.toPlainTextString() );
        }
    }

jsoup 解析XML

为讲解 XML 数据的解析,我选取的案例是爬取网易汽车的销量数据,例如捷达汽车的销量,页面为:

   http://db.auto.sohu.com/cxdata/xml/sales/model/model1001sales.xml

其部分 XML 文件如下:

利用 jsoup 选择器,可以快速的解析 XML 文件中的数据。解析捷达汽车的销售月份以及该月份的汽车

代码:

 //获取URL对应的HTML内容
        Document doc = Jsoup.connect("http://db.auto.sohu.com/cxdata/xml/sales/model/model1001sales.xml").timeout(5000).get();
       //Jsoup选择器解析
        Elements sales_ele = doc.select("sales");
        for (Element elem:sales_ele) {
            int salesnum=Integer.valueOf(elem.attr("salesnum"));
            String date = elem.attr("date");
            System.out.println("月份:" + date + "\t销量:" + salesnum);

        }

输出:

月份:2007-01-01	销量:14834
月份:2007-02-01	销量:9687
月份:2007-03-01	销量:18173
月份:2007-04-01	销量:18508
月份:2007-05-01	销量:19710
月份:2007-06-01	销量:20311
月份:2007-07-01	销量:17516
月份:2007-08-01	销量:17535
月份:2007-09-01	销量:17743
月份:2007-10-01	销量:15255
月份:2007-11-01	销量:17250
月份:2007-12-01	销量:14609
月份:2008-01-01	销量:25126
月份:2008-02-01	销量:9077
月份:2008-03-01	销量:20396
月份:2008-04-01	销量:18967
月份:2008-05-01	销量:18243
月份:2008-06-01	销量:17738
月份:2008-07-01	销量:17449
月份:2008-08-01	销量:18927
月份:2008-09-01	销量:15586
月份:2008-10-01	销量:14945
月份:2008-11-01	销量:17204
月份:2008-12-01	销量:8645
月份:2009-01-01	销量:12240
月份:2009-02-01	销量:12586
月份:2009-03-01	销量:21139
月份:2009-04-01	销量:21534
月份:2009-05-01	销量:20934
月份:2009-06-01	销量:20722
月份:2009-07-01	销量:17091
月份:2009-08-01	销量:21053
月份:2009-09-01	销量:20667
月份:2009-10-01	销量:21278
月份:2009-11-01	销量:20535

源码地址:

源码

猜你喜欢

转载自blog.csdn.net/wj903829182/article/details/84195858
今日推荐