zoukankan      html  css  js  c++  java
  • HtmlAgilityPack解析html文档

    一、爬虫概述

    C#(99):HttpClient网络HTTP请求和相应

    1、使用浏览器获取页面源码

    1. C#使用Selenium
    2. Web browser控件CefSharp的使用

    2、HTML解析组件

    1. HtmlAgilityPackhttps://github.com/zzzprojects/html-agility-pack/
    2. Fizzler.Systems.HtmlAgilityPackhttps://www.nuget.org/packages/Fizzler.Systems.HtmlAgilityPack
      Fizzler是用于文档层次结构的W3C选择器解析器和通用选择器框架。这个包使Fizzler优于HTMLAgilityPack,为HtmlNode对象添加了QuerySelector和QuerySelectorAll(来自选择器API Level 1)。
    3. HtmlAgilityPack.CssSelectors(2016/6后不更新了):https://www.nuget.org/packages/HtmlAgilityPack.CssSelectors/
    4. AngleSharp(2018/10月后不更新了):https://github.com/AngleSharp/AngleSharp
    5. CsQuery(2015/12月后不更新了):https://github.com/jamietre/CsQuery
    6. Jumony(2017/1月不更新了):https://github.com/Ivony/Jumony
    7. NSoup(2019/2月不更新了)::https://github.com/GeReV/NSoup

    二、HtmlAgilityPack介绍

    HtmlAgilityPack(以下简称HAP)是一个基于.Net的、第三方免费开源的微型类库,主要用于在服务器端解析html文档。

    HtmlAgilityPack为网页提供了标准的DOM API和XPath导航。使用WebBrowser和HttpWebRequest下载的网页可以用Html Agility Pack来解析。

    image

    Xpath表达式的参考文档可见:https://www.cnblogs.com/springsnow/p/11810458.html#_label0

    参考:

    GitHub:https://github.com/zzzprojects/html-agility-pack/releases

    官网:https://html-agility-pack.net/

    https://www.nuget.org/packages/HtmlAgilityPack/

    三、属性和方法

    HtmlAgilityPack中的HtmlNode类与XmlNode类差不多,HtmlDocument类与XmlDocument类差不多。

    参考:https://www.cnblogs.com/springsnow/p/12883050.html

    下面来看看该类提供功能。

    属性:

    • Attributes: 获取节点的属性集合
    • Attributes 获取节点的属性集合
    • ChildNodes获取子节点集合(包括文本节点)
    • Closed该节点是否已关闭(</xxx>)
    • ClosingAttributes在关闭标签的属性集合
    • FirstChild 获取第一个子节点
    • HasAttributes 判断该节点是否含有属性
    • HasChildNodes 判断该节点是否含有子节点
    • HasClosingAttributes  判断该节点的关闭标签是否含有属性(</xxx class="xxx">)
    • Id 获取该节点的Id属性
    • InnerHtml 获取该节点的Html代码
    • InnerText  获取该节点的内容,与InnerHtml不同的地方在于它会过滤掉Html代码,而InnerHtml是连Html代码一起输出
    • LastChild  获取最后一个子节点
    • Line  获取该节点的开始标签或开始代码位于整个HTML源代码的第几行(行号)
    • NameHtml元素名
    • NextSibling 获取下一个兄弟节点
    • NodeType    获取该节点的节点类型
    • OuterHtml 整个节点的代码
    • OwnerDocument节点所在的HtmlDocument文档
    • ParentNode:获取该节点的父节点
    • PreviousSibling: 获取前一个兄弟节点
    • StreamPosition: 该节点位于整个Html文档的字符位置
    • XPath:  根据节点返回该节点的XPath

    方法:

    • Load(string path)  从路径中加载一个文档
    • Ancestors()  返回此元素的所有上级节点的集合。
    • AppendChild(HtmlNode newChild)  将参数元素追加到为调用元素的子元素(追加在最后)
    • PrependChild(HtmlNode newChild)  将参数中的元素作为子元素,放在调用元素的最前面
    • ChildAttributes(string name)  获取所有子元素的属性(参数名要与元素名匹配)
    • Clone()  本节点克隆到一个新的节点
    • CopyFrom(HtmlNode node)  创建重复的节点和其下的子树。
    • CreateNavigator()  返回的一个对于此文档的XPathNavigator
    • CreateNode(string html)  静态方法,允许用字符串创建一个新节点
    • CreateRootNavigator()  创建一个根路径的XPathNavigator
    • DescendantNodes()  获取所有子代节点
    • Element(string name)  根据参数名获取一个元素
    • Elements(string name)  根据参数名获取匹配的元素集合
    • GetAttributeValue(string name, bool def)  帮助方法,用来获取此节点的属性的值(布尔类型)。如果未找到该属性,则将返回默认值。
    • InsertAfter(HtmlNode newChild, HtmlNode refChild)  将一个节点插入到第二个参数节点的后面,与第二个参数是兄弟关系
    • InsertBefore(HtmlNode newChild, HtmlNode refChild)  将一个节点插入到第二个参数节点的后面,与第二个参数是兄弟关系
    • IsEmptyElement(string name)  确定是否一个空的元素节点。
    • IsOverlappedClosingElement(string text)  确定是否文本对应于一个节点可以保留重叠的结束标记。
    • Remove()  从父集合中移除调用节点
    • SelectNodes(string xpath)  根据XPath获取一个节点集合
    • SelectSingleNode(string xpath)  根据XPath获取唯一的一个节点
    • SetAttributeValue(string name, string value)  设置调用节点的属性
    • WriteContentTo()  将该节点的所有子级都保存到一个字符串中。
    • WriteTo()  将当前节点保存到一个字符串中。
    • Save(string filename)  将HTML文档保存到指定的路径

    四、用法

    在这里插入图片描述

    下面是几个简单使用说明:

    1、获取网页title:

    doc.DocumentNode.SelectSingleNode("//title").InnerText;//XPath中:“//title”表示所有title节点。SelectSingleNode用于获取满足条件的唯一的节点。

    2、获取所有的超链接:

    doc.DocumentNode.Descendants("a")

    3、获取name为kw的input,也就是相当于getElementsByName():

    var kwBox = doc.DocumentNode.SelectSingleNode("//input[@name='kw']");

    示例:

    private void Form1_Load(object sender, EventArgs e)
    {
        List<Result> list = new List<Result>();
        HtmlWeb htmlWeb = new HtmlWeb();
        htmlWeb.OverrideEncoding = Encoding.UTF8;//编码,这里网上有些很多写法都不正确
        HtmlAgilityPack.HtmlDocument htmlDoc = htmlWeb.Load(@http://www.cnblogs.com/);
        //选择博客园首页文章列表
        htmlDoc.DocumentNode.SelectNodes("//div[@id='post_list']/div[@class='post_item']").//双斜杠“//”表示从跟节点开始查找
            AsParallel().ToList().ForEach(ac =>
            {
                //抓取图片,因为有空的,所以拿变量存起来
                HtmlNode node = ac.SelectSingleNode(".//p[@class='post_item_summary']/a/img");
                list.Add(new Result
                {
                    url = ac.SelectSingleNode(".//a[@class='titlelnk']").Attributes["href"].Value,
                    title = ac.SelectSingleNode(".//a[@class='titlelnk']").InnerText,
                    //图片如果为空,显示默认图片
                    img = node == null ? "http ://www.cnblogs.com//Content/img/avatar.png" : node.Attributes["src"].Value,
                    content = ac.SelectSingleNode(".//p[@class='post_item_summary']").InnerText
                });
            });
    
        foreach (Result item in list)
        {
            this.listBox1.Items.Add(item.title);
        }
    }
    /// <summary>
    /// 页面抓取结果
    /// </summary>
    public class Result
    {
        /// <summary>
        /// 链接
        /// </summary>
        public string url { get; set; }
        /// <summary>
        /// 标题
        /// </summary>
        public string title { get; set; }
        /// <summary>
        /// 头像地址
        /// </summary>
        public string img { get; set; }
        /// <summary>
        /// 正文内容
        /// </summary>
        public string content { get; set; }
    }
  • 相关阅读:
    ArrayBlockingQueue和LinkedBlockingQueue
    hibernate中保存一个对象后再设置此对象的属性为什么不需要调用update方法了
    Hello World!
    org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction;
    jquery的attr在浏览器发生错误,checkbox的属性总是为undefined
    如何解决设置maven时Could not read settings.xml
    iOS与HTML交互问题
    一个苹果证书怎么多次使用——导出p12文件
    Mac Chrome-点击书签页在新的标签打开之方法
    iOS 开发者中的个人账号与组织账号之间区别
  • 原文地址:https://www.cnblogs.com/springsnow/p/11388673.html
Copyright © 2011-2022 走看看