.net core 实现简单爬虫—抓取博客园的博文列表
概述
详细
一、介绍一个Http请求框架HttpCode.Core
HttpCode.Core 源自于HttpCode(传送门),不同的是 HttpCode.Core是基于.net standard 2.0实现的,移除了HttpCode与windows相耦合的api,且修改了异步实现,其余特性完全与HttpCode相同,大家 如果在使用中有什么问题可以查看在线文档(传送门)
HttpCode.Core完全开源,已传到github,地址:https://github.com/stulzq/HttpCode.Core
为了方便大家使用,也传到了nuget,地址:https://www.nuget.org/packages/HttpCode.Core/,在nuget中搜索 HttpCode.Core 或执行命令 Install-Package HttpCode.Core 就可以使用了。
具体的使用方法大家可以查阅在线文档,或者查看github。
简单、易用、高效 一个有态度的开源.Net Http请求框架!
二、分析抓取地址
首先使用谷歌浏览器的开发者工具,抓取博客园首页获取博文列表的地址:
从中我们可以分析出:
1. 请求地址 https://www.cnblogs.com/mvc/AggSite/PostList.aspx
2.请求方式 Post
3.请求数据
1 2 3 4 5 6 7 8 | { "CategoryType" : "SiteHome" , "ParentCategoryId" :0, "CategoryId" :808, "PageIndex" :3, "TotalPostCount" :4000, "ItemListActionName" : "PostList" } |
请求数据中,我们应当关心的是 PageIndex 代表的是 页数,我们可通过变换这个参数的值来获取不同页面的数据。
我们先使用HttpCode.Core来试一试获取数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | int pageIndex = 1; //页数 HttpHelpers httpHelpers= new HttpHelpers(); HttpItems items= new HttpItems(); items.Url = "https://www.cnblogs.com/mvc/AggSite/PostList.aspx" ;//请求地址 items.Method = "Post" ; //请求方式 post items.Postdata = "{\"CategoryType\":\"SiteHome\"," + "\"ParentCategoryId\":0," + "\"CategoryId\":808," + "\"PageIndex\":" + pageIndex + "," + "\"TotalPostCount\":4000," + "\"ItemListActionName\":\"PostList\"}" ; //请求数据 HttpResults hr = httpHelpers.GetHtml(items); Console.WriteLine(hr.Html); Console.ReadKey(); |
运行截图:
可以看到我们已经成功获取了数据,证明我们的分析是正确的。
三、解析返回的数据
刚刚我们测试接口返回的数据可以看出返回的是一堆html字符串。我们只想要博文的标题、作者、博文地址等等信息,我们不需要多余的html字符串,下面我们使用 HtmlAgilityPack 这个解析网页的组件来获得我们想要的数据。
关于这个组件的使用,博客园已经有不少介绍此组件的文档,大家可以搜索查看,使用此组件需具备xpath相关知识,我就不在此详细叙述了。
1.首先通过nuget安装 HtmlAgilityPack 组件
打开程序包控制台
执行命令 Install-Package HtmlAgilityPack -Version 1.5.2-beta6
2. 解析返回的数据
贴一下返回的部分数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | < div class="post_item"> < div class="digg"> < div class="diggit" onclick="DiggPost('yaoxiaowen',7470460,318439,1)"> < span class="diggnum" id="digg_count_7470460">4</ span > </ div > < div class="clear"></ div > < div id="digg_tip_7470460" class="digg_tip"></ div > </ div > < div class="post_item_body"> < h3 >< a class="titlelnk" href="http://www.cnblogs.com/yaoxiaowen/p/7470460.html" target="_blank">关于跨平台的一些认识</ a ></ h3 > < p class="post_item_summary"> < a href="http://www.cnblogs.com/yaoxiaowen/" target="_blank">< img width="48" height="48" class="pfs" src="//pic.cnblogs.com/face/918357/20161122225949.png" alt=""/></ a > 前段时间看了 周志明的那本 《深入理解java虚拟机》。对于 平台无关性 问题,有了一些新的认识。所以特写一篇博客来进行总结。 这是我的第一篇不针对具体技术,而只针对计算机系统和原理的博客文章,而这种话题,总是比较宽泛,而我本人的水平有限,所以我也只能泛泛的写写,思考的不对的地方,还望读者不吝批评。 ... </ p > < div class="post_item_foot"> < a href="http://www.cnblogs.com/yaoxiaowen/" class="lightblue">eleven_yw</ a > 发布于 2017-09-03 22:12 < span class="article_comment">< a href="http://www.cnblogs.com/yaoxiaowen/p/7470460.html#commentform" title="2017-09-04 15:23" class="gray"> 评论(2)</ a ></ span >< span class="article_view">< a href="http://www.cnblogs.com/yaoxiaowen/p/7470460.html" class="gray">阅读(210)</ a ></ span ></ div > </ div > < div class="clear"></ div > </ div > < div class="post_item"> < div class="digg"> < div class="diggit" onclick="DiggPost('loseheart',7471197,375716,1)"> < span class="diggnum" id="digg_count_7471197">0</ span > </ div > < div class="clear"></ div > < div id="digg_tip_7471197" class="digg_tip"></ div > </ div > < div class="post_item_body"> < h3 >< a class="titlelnk" href="http://www.cnblogs.com/loseheart/p/7471197.html" target="_blank">2017年9月3日 实现网站的权限管理</ a ></ h3 > < p class="post_item_summary"> < a href="http://www.cnblogs.com/loseheart/" target="_blank">< img width="48" height="48" class="pfs" src="//pic.cnblogs.com/face/1224591/20170823222646.png" alt=""/></ a > 现在各个企业管理网站对登录的账号都要进行权限管理,并且相当重要,每个账号登录进去所能看到的东西大不相同,下面是实现该功能的一个的一种方法。 需求: 权限:权限是使用者操作系统中功能模块的能力,如“角色管理”模块、“资费管 理”模块和“账单管理”模块等。通过指定权限,可将使用者的操作限定在指定的 范围 ... </ p > < div class="post_item_foot"> < a href="http://www.cnblogs.com/loseheart/" class="lightblue">Loseheart</ a > 发布于 2017-09-03 21:34 < span class="article_comment">< a href="http://www.cnblogs.com/loseheart/p/7471197.html#commentform" title="" class="gray"> 评论(0)</ a ></ span >< span class="article_view">< a href="http://www.cnblogs.com/loseheart/p/7471197.html" class="gray">阅读(354)</ a ></ span ></ div > </ div > < div class="clear"></ div > </ div > |
从中我们不难看出每一个数据是以class=post_item的div来进行区分的,我们想要的博文地址、标题等是在这个div里面的class=post_item_body的div里面,以此类推我们可以分析出:
-
博文标题 <div class="post_item"> | <div class="post_item_body"> | h3 | a | Text
-
博文地址 <div class="post_item"> | <div class="post_item_body"> | h3 | a | href
-
..以此类推
因为HtmlAgilityPack是通过xpath来解析网页的,所以现在我们要根据我们上面分析出的路径来写xpath,这里不明白xpath的可以去w3cschool学习一下,非常简单。
下面是我写好的解析博文标题、地址和作者的代码,抓取其他信息可以自己参考试一试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | //解析数据 HtmlDocument doc= new HtmlDocument(); //加载html doc.LoadHtml(hr.Html); //获取 class="post_item_body" 的div列表 HtmlNodeCollection itemNodes = doc.DocumentNode.SelectNodes( "div[@class='post_item']/div[@class='post_item_body']" ); //循环根据每个div解析我们想要的数据 foreach ( var item in itemNodes) { //获取包含博文标题和地址的 a 标签 var nodeA = item.SelectSingleNode( "h3/a" ); //获取博文标题 string title = nodeA.InnerText; //获取博文地址 a标签的 href 属性 string url = nodeA.GetAttributeValue( "href" , "" ); //获取包含作者名字的 a 标签 var nodeAuthor = item.SelectSingleNode( "div[@class='post_item_foot']/a[@class='lightblue']" ); string author = nodeAuthor.InnerText; Console.WriteLine($ "标题:{title} | 作者:{author} | 地址:{url}" ); } |
运行截图:
四、循环抓取多个分页
前面我们分析出请求参数中的 PageIndex 是页数,分析单个页面的代码我们也写出来来,那么我们可以通过循环递增页数,来达到抓取不同分页数据的要求。
贴一下完整的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | int pageIndex = 1; //页数 int maxPageIndex = 10; //最大页数 HttpHelpers httpHelpers= new HttpHelpers(); for (int i = 0; i < maxPageIndex; i++) { HttpItems items = new HttpItems(); items.Url = "https://www.cnblogs.com/mvc/AggSite/PostList.aspx" ;//请求地址 items.Method = "Post" ; //请求方式 post items.Postdata = "{\"CategoryType\":\"SiteHome\"," + "\"ParentCategoryId\":0," + "\"CategoryId\":808," + "\"PageIndex\":" + (i+1) + "," + //因为i从0开始 所以此处我们要加1 "\"TotalPostCount\":4000," + "\"ItemListActionName\":\"PostList\"}" ; //请求数据 HttpResults hr = httpHelpers.GetHtml(items); //解析数据 HtmlDocument doc = new HtmlDocument(); //加载html doc.LoadHtml(hr.Html); //获取 class="post_item_body" 的div列表 HtmlNodeCollection itemNodes = doc.DocumentNode.SelectNodes( "div[@class='post_item']/div[@class='post_item_body']" ); Console.WriteLine($ "第{i+1}页数据:" ); //循环根据每个div解析我们想要的数据 foreach ( var item in itemNodes) { //获取包含博文标题和地址的 a 标签 var nodeA = item.SelectSingleNode( "h3/a" ); //获取博文标题 string title = nodeA.InnerText; //获取博文地址 a标签的 href 属性 string url = nodeA.GetAttributeValue( "href" , "" ); //获取包含作者名字的 a 标签 var nodeAuthor = item.SelectSingleNode( "div[@class='post_item_foot']/a[@class='lightblue']" ); string author = nodeAuthor.InnerText; //输出数据 Console.WriteLine($ "标题:{title} | 作者:{author} | 地址:{url}" ); } //每抓取一页数据 暂停三秒 Thread.Sleep(3000); } Console.ReadKey(); |
五、运行截图
六、项目文件截图
一个简单的.net core实现的简单爬虫就此完成!
注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?