当前位置:   article > 正文

C# 网络爬虫+HtmlAgilityPack+Xpath+爬虫工具类的封装的使用_c# xpath

c# xpath

目录

1 工具准备

2 思路准备

3 附加知识准备——XPath

简述

看看例子

用XPath来寻找标签

获取所有同名的标签

获取指定标签

一个实例

最后的补充

4 代码实现

5 爬虫工具类的封装

6 使用爬虫工具类爬虫


1 工具准备

1  Visual Studio 需要安装包 HtmlAgilityPack

 

 2 命名空间的引入

在新建的程序头顶加入

  1. using HtmlAgilityPack;
  2. using HtmlDocument = HtmlAgilityPack.HtmlDocument;

3 注备好一双可以复制粘贴的小手,和一个还能跑的电脑,咯咯~

2 思路准备

图我已经给各位画好了,请参看

 

3 附加知识准备——XPath

简述

XPath 是一门在 XML 文档中查找信息的语言,虽然是被设计用来搜寻 XML 文档的,但是它也能应用于 HTML 文档,并且大部分浏览器也支持通过 XPath 来查询节点。在 Python 爬虫开发中,经常使用 XPath 查找提取网页中的信息,因此 XPath 非常重要。

XPath 使用路径表达式来选取 XML 文档中的节点或节点集。节点是沿着路径(path)或者步(steps)来选取的。接下来介绍如何选取节点,首先了解一下常用的路径表达式,来进行节点的选取,如下表所示:

表达式描述
nodename选取此节点的所有子节点
/从根节点选取
//选择任意位置的某个节点
.选取当前节点
..选取当前节点的父节点
@选取属性

看看例子

bookstore选取 bookstore 元素的所有子节点。
/bookstore

选取根元素 bookstore。

注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!

bookstore/book选取属于 bookstore 的子元素的所有 book 元素。
//book选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang选取名为 lang 的所有属性。

用XPath来寻找标签

获取所有同名的标签

我们只需要用:  //标签名

即可,比如看下图我们使用了//ul寻找到了所有名为ul的标签了

获取指定标签

那么我们想要去选取具体的那个标签怎么办那?

有童鞋可能会想到,直接加下表访问但是!!在有时候是行不通的,

很简单,我们先将获取的的所以ul块对象存在数组中,然后使用下标访问就好了

只是这些我们要在C#中进行操作了,不能直接在网络控制台上进行操作了,咯咯~

/html/body/div[1]/div[2]/ul

一个实例

 我们使用这串Xpath代码就可以获取到所有在指定位置下的li标签了

/html/body/div[1]/div[2]/ul/li

最后的补充

XPath 在进行节点选取的时候可以使用通配符*匹配未知的元素,同时使用操作符|一次选取多条路径,使用示例如下表所示。

XPath路径表达式含义
/bookstore/*选取 bookstore 元素的所有子元素
//*选取文档中的所有元素
//title[@*]选取所有带有属性的 title 元素
//book/title 丨 //book/price选取 book 元素的所有 title 和 price 元素
//title 丨 //price选取文档中的所有 title 和 price 元素
/bookstore/book/title 丨 //price选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素

4 代码实现

其实有了上面的基础知识,就可以自由发挥了,我这里抛砖引玉一下。

我们以美女图片大全_高清美女图片_性感美女写真_极品美女图片 - 美图131为例对MV图片的源地址,以及标签进行提取。

以下代码我们只用理解逻辑以及方法即可,可能也有很多漏洞与BUG,但这些不是重点滴!

  1. public void getdata()
  2. {
  3. //----全网首发----//
  4. //建立实例化htmlweb对象用于加载,处理网页
  5. HtmlWeb htmlWeb = new HtmlWeb();
  6. //设置为Encoding.UTF8编码,防止乱码
  7. htmlWeb.OverrideEncoding = Encoding.UTF8;
  8. //初始化网页地址
  9. String init_url = @"https://www.meitu131.com/meinv/";
  10. 加载网页返回值为HtmlDocument类型,用var也行,哈哈
  11. HtmlDocument htmlDoc = htmlWeb.Load(init_url);
  12. //打印一下网页的HTML文档,看看效果
  13. //Console.WriteLine(htmlDoc.Text);
  14. //使用XPath定位元素
  15. string xpath = "";
  16. string init_xpath = "/html/body/div[1]/div[2]/ul/li";
  17. //获取本页所有li的节点数目,这便是本页图集的个数
  18. int new_page_sum = htmlDoc.DocumentNode.SelectNodes(init_xpath).Count;
  19. //对每个li节点进行提取,并拼接图集的网址
  20. for (int a_ = 0; a_ < new_page_sum; a_++)
  21. {
  22. xpath = "/html/body/div[1]/div[2]/ul/li[" + (a_ + 1) + "]/div[1]/a";
  23. init_img_src.Add("https://www.meitu131.com" + htmlDoc.DocumentNode.SelectSingleNode(xpath).Attributes["href"].Value.ToString());
  24. }
  25. //对每一页进行遍历,获取
  26. for (int b_ = 0; b_ < new_page_sum; b_++)
  27. {
  28. string temp_src = @init_img_src[b_];
  29. string temp_paxth_ = "//*[@id='main-wrapper']/div[2]/p/a/img";
  30. string temp_paxth = "//*[@id='pages']/a[1]";
  31. HtmlDocument htmlDoc_1 = htmlWeb.Load(temp_src);
  32. string c = htmlDoc_1.DocumentNode.SelectSingleNode(temp_paxth).InnerHtml.ToString();
  33. //获取当前图集所有页数page_sum[1]
  34. String[] page_sum = c.Split('/');
  35. for (int c_ = 0; c_ < 1; c_++)
  36. {
  37. string temp_url;
  38. if (c_ == 0)
  39. {
  40. temp_url = temp_src + "index.html";
  41. }
  42. else
  43. {
  44. temp_url = temp_src + "index_" + (c_ + 1) + ".html";
  45. }
  46. HtmlDocument htmlDoc_2 = htmlWeb.Load(temp_url);
  47. end_img_url.Add(htmlDoc_1.DocumentNode.SelectSingleNode(temp_paxth_).Attributes["src"].Value.ToString());
  48. end_img_name.Add(htmlDoc_1.DocumentNode.SelectSingleNode(temp_paxth_).Attributes["alt"].Value.ToString());
  49. }
  50. }
  51. textBox1.AppendText("数据获取完成,开始保存文件......");
  52. }

5 爬虫工具类的封装

为了更方便的爬虫,我对常用的方法进一步进行了封装,开箱即用。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Net;
  7. using System.IO;
  8. using System.Diagnostics;
  9. using HtmlAgilityPack;
  10. using System.Net.Http;
  11. namespace 爬虫
  12. {
  13. public static class pc_Help
  14. {
  15. /// <summary>
  16. /// Url网络资源下载
  17. /// </summary>
  18. /// <param name="Download_Path">下载地址</param>
  19. /// <param name="resource_name">资源名列表</param>
  20. /// <param name="resource_url">资源Url列表</param>
  21. /// <param name="Download_Type">下载文件后缀(不加.)</param>
  22. /// <returns> 毫秒运行时间 float</returns>
  23. public static string Download_Url(string Download_Path, List<string> resource_name, List<string> resource_url, string Download_Type)
  24. {
  25. try
  26. {
  27. string Download_Path_ = Download_Path;
  28. Stopwatch sw = new Stopwatch();
  29. sw.Start();
  30. int len = resource_name.Count;
  31. int num = 0;
  32. WebClient wb = new WebClient();
  33. DirectoryInfo info = new DirectoryInfo(Download_Path_);
  34. if (!info.Exists)
  35. {
  36. Directory.CreateDirectory(Download_Path_);
  37. }
  38. for (int d_ = 0; d_ < len; d_++)
  39. {
  40. Download_Path = $@"{Download_Path_}\{(num + 1)}{resource_name[d_]}.{Download_Type}";
  41. num++;
  42. wb.DownloadFile(resource_url[d_], Download_Path);
  43. }
  44. sw.Stop();
  45. return $"文件保存完成!耗时:{sw.ElapsedMilliseconds/1000}s\r\n";
  46. }
  47. catch (Exception e)
  48. {
  49. throw new Exception("保存数据出错", e);
  50. }
  51. }
  52. /// <summary>
  53. /// 从Url地址下载HTML页面
  54. /// </summary>
  55. /// <param name="url"></param>
  56. /// <returns></returns>
  57. public async static ValueTask<HtmlDocument> LoadHtmlFromUrlAsync(string url)
  58. {
  59. //如果web不是空就异步下载html文档
  60. HtmlWeb web = new HtmlWeb();
  61. web.OverrideEncoding = Encoding.UTF8;
  62. return await web?.LoadFromWebAsync(url);
  63. }
  64. /// <summary>
  65. /// 获取单个节点的扩展方法
  66. /// </summary>
  67. /// <param name="htmlDocument">文档对象</param>
  68. /// <param name="xPath">xPath路径</param>
  69. /// <returns></returns>
  70. public static HtmlNode GetSingleNode(this HtmlDocument htmlDocument, string xPath)
  71. {
  72. return htmlDocument?.DocumentNode?.SelectSingleNode(xPath);
  73. }
  74. /// <summary>
  75. /// 获取单个节点扩展方法
  76. /// </summary>
  77. /// <param name="htmlDocument">文档对象</param>
  78. /// <param name="xPath">xPath路径</param>
  79. /// <returns></returns>
  80. public static HtmlNode GetSingleNode(this HtmlNode htmlNode, string xPath)
  81. {
  82. return htmlNode?.SelectSingleNode(xPath);
  83. }
  84. /// <summary>
  85. /// 获取多个节点扩展方法
  86. /// </summary>
  87. /// <param name="htmlDocument">文档对象</param>
  88. /// <param name="xPath">xPath路径</param>
  89. /// <returns>一个列表</returns>
  90. public static HtmlNodeCollection GetNodes(this HtmlDocument htmlDocument, string xPath)
  91. {
  92. return htmlDocument?.DocumentNode?.SelectNodes(xPath);
  93. }
  94. /// <summary>
  95. /// 获取多个节点扩展方法
  96. /// </summary>
  97. /// <param name="htmlDocument">文档对象</param>
  98. /// <param name="xPath">xPath路径</param>
  99. /// <returns>一个列表</returns>
  100. public static HtmlNodeCollection GetNodes(this HtmlNode htmlNode, string xPath)
  101. {
  102. return htmlNode?.SelectNodes(xPath);
  103. }
  104. /// <summary>
  105. /// 下载图片
  106. /// </summary>
  107. /// <param name="url">地址</param>
  108. /// <param name="filpath">文件路径</param>
  109. /// <returns>存在即覆盖</returns>
  110. ///
  111. //同步完成时的ValueTask<TResult>,<>里可以是任何类型
  112. public async static ValueTask<bool> DownloadImg(string url, string filpath)
  113. {
  114. HttpClient hc = new HttpClient();
  115. try
  116. {
  117. //字节流异步写入
  118. var bytes = await hc.GetByteArrayAsync(url);
  119. //存在即覆盖
  120. using (FileStream fs = File.Create(filpath))
  121. {
  122. fs.Write(bytes, 0, bytes.Length);
  123. }
  124. return File.Exists(filpath);
  125. }
  126. catch (Exception ex)
  127. {
  128. throw new Exception("下载图片异常", ex);
  129. }
  130. }
  131. }
  132. }

6 使用爬虫工具类爬虫

这边给个例子,还是以我们以美女图片大全_高清美女图片_性感美女写真_极品美女图片 - 美图131为例

以下代码我们只用理解逻辑以及方法即可,可能也有很多漏洞与BUG,但这些不是重点滴!

  1. public async ValueTask<bool> getdata_()
  2. {
  3. try
  4. {
  5. HtmlDocument html_3 = await pc_Help.LoadHtmlFromUrlAsync(init_url);
  6. string stack_all_page_sum_string = pc_Help.GetSingleNode(html_3, "//*[@id='pages']/a[11]").Attributes["href"].Value.ToString();
  7. //正则匹配全站所有图集的个数
  8. Regex regex = new Regex(@"\d{2}");
  9. int stack_all_page_sum_int = Convert.ToInt32(regex.Match(stack_all_page_sum_string).ToString());
  10. if (pagesum < 24)
  11. {
  12. HtmlDocument htmlDoc;
  13. htmlDoc = await pc_Help.LoadHtmlFromUrlAsync(init_url);
  14. string xpath = "";
  15. //获取此页面上(具有多个图集封面的页面)的所有图集的初始页的数目
  16. int new_page_sum = pc_Help.GetNodes(htmlDoc, "/html/body/div[1]/div[2]/ul/li").Count;
  17. //拼接当前页面上(具有多个图集封面的页面)的所有图集的初始页的地址
  18. for (int a_ = 0; a_ < pagesum; a_++)
  19. {
  20. xpath = "/html/body/div[1]/div[2]/ul/li[" + (a_ + 1) + "]/div[1]/a";
  21. init_img_src.Add("https://www.meitu131.com" + pc_Help.GetSingleNode(htmlDoc, xpath).Attributes["href"].Value.ToString());
  22. }
  23. for (int b_ = 0; b_ < pagesum; b_++)
  24. {
  25. string temp_src = @init_img_src[b_];
  26. string temp_paxth_ = "//*[@id='main-wrapper']/div[2]/p/a/img";
  27. string temp_paxth = "//*[@id='pages']/a[1]";
  28. HtmlDocument htmlDoc_1 = await pc_Help.LoadHtmlFromUrlAsync(temp_src);
  29. string c = pc_Help.GetSingleNode(htmlDoc_1, temp_paxth).InnerHtml.ToString();
  30. //获取本图集所有页数page_sum[1]
  31. string[] page_sum = c.Split('/');
  32. //Convert.ToInt32(page_sum[1])
  33. //每个图集页面的拼接,与请求保存图片
  34. for (int c_ = 0; c_ < length; c_++)
  35. {
  36. string temp_url;
  37. if (c_ == 0)
  38. {
  39. temp_url = temp_src + "index.html";
  40. }
  41. else
  42. {
  43. temp_url = temp_src + "index_" + (c_ + 1) + ".html";
  44. }
  45. HtmlDocument htmlDoc_2 = await pc_Help.LoadHtmlFromUrlAsync(temp_url);
  46. string src = pc_Help.GetSingleNode(htmlDoc_2, temp_paxth_).Attributes["src"].Value.ToString();
  47. string alt = pc_Help.GetSingleNode(htmlDoc_2, temp_paxth_).Attributes["alt"].Value.ToString();
  48. end_img_url.Add(src);
  49. end_img_name.Add(alt);
  50. num++;
  51. textBox1.AppendText($"{num}-->{alt}-->{src}\r\n");
  52. }
  53. }
  54. }
  55. else
  56. {
  57. for (int x_ = 0; x_ < pagesum; x_++)
  58. {
  59. }
  60. ero = false;
  61. MessageBox.Show("待实现中....");
  62. }
  63. if (ero)
  64. {
  65. textBox1.AppendText("数据获取完成,正在保存文件......\r\n");
  66. }
  67. else {
  68. textBox1.AppendText("数据获取失败......\r\n");
  69. }
  70. return true;
  71. }
  72. catch (Exception ex)
  73. {
  74. throw new Exception("数据获取异常", ex);
  75. }
  76. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/848640
推荐阅读
相关标签
  

闽ICP备14008679号