• C#爬虫(04):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. Jumony(2014年不更新了):https://github.com/Ivony/Jumony

    二、HtmlAgilityPack介绍

    参考:

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

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

    https://www.nuget.org/packages/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

    三、属性和方法

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

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

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

    属性:

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

          方法:

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

              示例2:下载微软文档

              using HtmlAgilityPack;
              using System;
              using System.Collections.Generic;
              using System.IO;
              using System.Text;
              
              namespace ConsoleApp4
              {
                  internal class Program
                  {
                      private static void Main(string[] args)
                      {
                          //网页地址:
                          string Url = "https://docs.microsoft.com/zh-cn/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/implementing-inheritance-with-the-entity-framework-in-an-asp-net-mvc-application";
              
                          List<string> list = new List<string>(); ;
                          HtmlWeb htmlWeb = new HtmlWeb();
                          htmlWeb.OverrideEncoding = Encoding.UTF8;
              
                          HtmlDocument htmlDoc = htmlWeb.Load(Url);
              
                          HtmlNode node = htmlDoc.DocumentNode.SelectSingleNode("//main[@id='main']");
              
                          //去掉英文翻译
                          var a = node.SelectNodes("//span[@class='sxs-lookup']");
                          foreach (HtmlNode b in a)
              
                          {
                              b.Remove();
                          }
              
                          string src = "";
                          //图片相对路径改成绝对路径
                          var imgNode = node.SelectNodes("//img[@data-linktype='relative-path']");
                          foreach (HtmlNode node1 in imgNode)
                          {
                              src = node1.GetAttributeValue("src", "");
                              var url = new Uri(htmlWeb.ResponseUri, src);
                              node1.SetAttributeValue("src", url.AbsoluteUri);
                          }
              
                          //链接路径转换
                          var hrefNode = node.SelectNodes("//a[@data-linktype='relative-path']|//a[@data-linktype='absolute-path']");
                          foreach (HtmlNode node1 in hrefNode)
                          {
                              src = node1.GetAttributeValue("href", "");
                              var url = new Uri(htmlWeb.ResponseUri, src);
                              node1.SetAttributeValue("href", url.AbsoluteUri);
                          }
              
                          //找到所有的H2标签,然后加上顺序。
                          var h2Node = node.SelectNodes("//h2");
                          var arr = new string[] { "", "", "", "", "", "", "", "", "", "", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十" };
                          if (h2Node != null)
                          {
                              for (int i = 0; i < h2Node.Count; i++)
                              {
                                  h2Node[i].InnerHtml = arr[i] + "" + h2Node[i].InnerHtml;
                                  //找到所有的H3标签,然后加上顺序。
              
                                  var h3Node = h2Node[i].SelectNodes("following-sibling::h2|following-sibling::h3");
                                  if (h3Node is null)
                                      break;
                                  for (int j = 0; j < h3Node.Count; j++)
                                  {
                                      if (h3Node[j].Name == "h2")
                                          break;
                                      else
                                          h3Node[j].InnerHtml = (j + 1) + "" + h3Node[j].InnerHtml;
                                  }
                              }
                          }
                          HtmlNode myNOde = htmlDoc.CreateElement("div");
              
                          //去掉前面无用的部分
                          var OK = node.SelectNodes("nav[1]/following-sibling::*");
                          myNOde.AppendChildren(OK);
              
                          //添加原文连接:
                          HtmlNode nodeOriUrl = htmlDoc.CreateElement("p");
                          nodeOriUrl.InnerHtml = "原文:<a href='" + htmlWeb.ResponseUri + "'>" + htmlWeb.ResponseUri + "</a>";
                          myNOde.PrependChild(nodeOriUrl);
              
                          //写入到本地文件
                          TextWriter wr = new StreamWriter(@"aa.html");
                          myNOde.WriteTo(wr);
                          wr.Close();
                      }
                  }
              }

              扒特定HTML图片下载并替换

              from clipboard

              using System;
              using System.Collections.Generic;
              using System.ComponentModel;
              using System.Data;
              using System.Drawing;
              using System.Linq;
              using System.Text;
              using System.Threading.Tasks;
              using System.Windows.Forms;
              using HtmlAgilityPack;
              using System.Text.RegularExpressions;
              using System.Net;
               
              namespace papapa
              {
                  public partial class Form1 : Form
                  {
                      public Form1()
                      {
                          InitializeComponent();
                      }
                      private static int j = 0;
                      private void button1_Click(object sender, EventArgs e)
                      {
                          j = 0;
                          string tou = textBox1.Text;
                          string html = qian.Text;
                          HtmlAgilityPack.HtmlDocument htmlDocument = new HtmlAgilityPack.HtmlDocument();
                          htmlDocument.LoadHtml(html);
                          var lilist = htmlDocument.DocumentNode.SelectNodes("//li");
                          for(int i = 0;i<lilist.Count;i  ) {
                              string Ys = "";
                              string script = "<script type='text/html' id='temp_00" i "'>
              ";
                              string foots = "</script>";
                              Ys = script   lilist[i].InnerHtml  "
              "   foots  "
              ";
                
                            var lio=  GetString(lilist[i].InnerHtml, @"http(s)?://([w-] .) [w-] (/[w- ./?%&=]*)?");
                              string paths = "";
                              foreach (Match m in lio) {
                                  string houzhui = m.Value.Remove(0,m.Length-3);
                                  if (houzhui != "jpg" && houzhui != "png" && houzhui != "gif" && houzhui != "peg") {
                                      houzhui = "png";
                                  }
                                  if (m.Value.Remove(0, m.Length - 4) == "jpeg") {
                                      houzhui = "jpeg";
                                  }
                                  paths = GetImg(m.Value, tou "_"   j.ToString() "."   houzhui);
                                Ys =  Ys.Replace(m.Value, textBox2.Text  paths);
                              }
                              hou.AppendText(Ys);
                          }
               
                      }
               
               
                      public string GetImg(string url,string paths) {
                          j  ;
                          string m_keleyiPicture = @"D:images"  paths;
                          //根据网址下载文件
                          WebClient mywebclient = new WebClient();
                          mywebclient.DownloadFile(url, m_keleyiPicture);
                          return paths;
                      }
                      public  MatchCollection GetString(string str, string zz)
                      {
                          Regex reg = new Regex(zz);
                          MatchCollection match = reg.Matches(str);
                          return match;
                      }
                      private void hou_KeyDown(object sender, KeyEventArgs e)
                      {
               
                          if (e.Modifiers == Keys.Control && e.KeyCode == Keys.A)
                          {
                              ((TextBox)sender).SelectAll();
                          }
                      }
                  }
              }

              五、Fizzler.Systems.HtmlAgilityPack:

              Hazz为HTMLAgilityPack实现CSS选择器。它基于Fizzler,一个通用的CSS选择器解析器和生成器库。

              Hazz以前称为Fizzler.Systems.HtmlAgilityPack。

              // Load the document using HTMLAgilityPack as normal
              var html = new HtmlDocument();
              html.LoadHtml(@"
                <html>
                    <head></head>
                    <body>
                      <div>
                        <p class='content'>Fizzler</p>
                        <p>CSS Selector Engine</p></div>
                    </body>
                </html>");
              
              // Fizzler for HtmlAgilityPack is implemented as the
              // QuerySelectorAll extension method on HtmlNode
              
              var document = html.DocumentNode;
              
              // yields: [<p class="content">Fizzler</p>]
              document.QuerySelectorAll(".content");
              
              // yields: [<p class="content">Fizzler</p>,<p>CSS Selector Engine</p>]
              document.QuerySelectorAll("p");
              
              // yields empty sequence
              document.QuerySelectorAll("body>p");
              
              // yields [<p class="content">Fizzler</p>,<p>CSS Selector Engine</p>]
              document.QuerySelectorAll("body p");
              
              // yields [<p class="content">Fizzler</p>]
              document.QuerySelectorAll("p:first-child");
            • 相关阅读:
              #背包方案 ——整数划分(Acwing900)
              #分组背包 #背包方案 ——Acwing 1013 机器分配
              #背包 #二进制优化 ——Acwing 5. 多重背包问题 II(二进制优化)
              #背包方案 AcWing 532. 货币系统
              #背包方案 ——AcWing 1021. 货币系统2
              背包问题求方案数
              有依赖的背包问题
              分组背包问题
              二维费用的背包问题
              混合背包问题
            • 原文地址:https://www.cnblogs.com/springsnow/p/13278283.html
            Copyright © 2020-2023  润新知