zoukankan      html  css  js  c++  java
  • .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     "CategoryType":"SiteHome",
    3     "ParentCategoryId":0,
    4     "CategoryId":808,
    5     "PageIndex":3,
    6     "TotalPostCount":4000,
    7     "ItemListActionName":"PostList"
    8

    请求数据中,我们应当关心的是  PageIndex  代表的是 页数,我们可通过变换这个参数的值来获取不同页面的数据。

     我们先使用HttpCode.Core来试一试获取数据:

    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 <div class="post_item">
     2 <div class="digg">
     3     <div class="diggit" onclick="DiggPost('yaoxiaowen',7470460,318439,1)"> 
     4     <span class="diggnum" id="digg_count_7470460">4</span>
     5     </div>
     6     <div class="clear"></div>
     7     <div id="digg_tip_7470460" class="digg_tip"></div>
     8 </div>      
     9 <div class="post_item_body">
    10     <h3><a class="titlelnk" href="http://www.cnblogs.com/yaoxiaowen/p/7470460.html" target="_blank">关于跨平台的一些认识</a></h3>                   
    11     <p class="post_item_summary">
    12 <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虚拟机》。对于 平台无关性 问题,有了一些新的认识。所以特写一篇博客来进行总结。 这是我的第一篇不针对具体技术,而只针对计算机系统和原理的博客文章,而这种话题,总是比较宽泛,而我本人的水平有限,所以我也只能泛泛的写写,思考的不对的地方,还望读者不吝批评。 ...
    13     </p>              
    14     <div class="post_item_foot">                    
    15     <a href="http://www.cnblogs.com/yaoxiaowen/" class="lightblue">eleven_yw</a> 
    16     发布于 2017-09-03 22:12 
    17     <span class="article_comment"><a href="http://www.cnblogs.com/yaoxiaowen/p/7470460.html#commentform" title="2017-09-04 15:23" class="gray">
    18         评论(2)</a></span><span class="article_view"><a href="http://www.cnblogs.com/yaoxiaowen/p/7470460.html" class="gray">阅读(210)</a></span></div>
    19 </div>
    20 <div class="clear"></div>
    21 </div>
    22 <div class="post_item">
    23 <div class="digg">
    24     <div class="diggit" onclick="DiggPost('loseheart',7471197,375716,1)"> 
    25     <span class="diggnum" id="digg_count_7471197">0</span>
    26     </div>
    27     <div class="clear"></div>
    28     <div id="digg_tip_7471197" class="digg_tip"></div>
    29 </div>      
    30 <div class="post_item_body">
    31     <h3><a class="titlelnk" href="http://www.cnblogs.com/loseheart/p/7471197.html" target="_blank">2017年9月3日  实现网站的权限管理</a></h3>                   
    32     <p class="post_item_summary">
    33 <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>    现在各个企业管理网站对登录的账号都要进行权限管理,并且相当重要,每个账号登录进去所能看到的东西大不相同,下面是实现该功能的一个的一种方法。 需求: 权限:权限是使用者操作系统中功能模块的能力,如“角色管理”模块、“资费管 理”模块和“账单管理”模块等。通过指定权限,可将使用者的操作限定在指定的 范围 ...
    34     </p>              
    35     <div class="post_item_foot">                    
    36     <a href="http://www.cnblogs.com/loseheart/" class="lightblue">Loseheart</a> 
    37     发布于 2017-09-03 21:34 
    38     <span class="article_comment"><a href="http://www.cnblogs.com/loseheart/p/7471197.html#commentform" title="" class="gray">
    39         评论(0)</a></span><span class="article_view"><a href="http://www.cnblogs.com/loseheart/p/7471197.html" class="gray">阅读(354)</a></span></div>
    40 </div>
    41 <div class="clear"></div>
    42 </div>
    View Code

     从中我们不难看出每一个数据是以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 HtmlDocument doc=new HtmlDocument();
     3 //加载html
     4 doc.LoadHtml(hr.Html);
     5 
     6 //获取 class=post_item_body 的div列表
     7 HtmlNodeCollection itemNodes = doc.DocumentNode.SelectNodes("div[@class='post_item']/div[@class='post_item_body']");
     8 
     9 //循环根据每个div解析我们想要的数据
    10 
    11 foreach (var item in itemNodes)
    12 {
    13     //获取包含博文标题和地址的 a 标签
    14     var nodeA = item.SelectSingleNode("h3/a");
    15     //获取博文标题
    16     string title = nodeA.InnerText;
    17     //获取博文地址 a标签的 href 属性
    18     string url = nodeA.GetAttributeValue("href", "");
    19 
    20     //获取包含作者名字的 a 标签
    21     var nodeAuthor = item.SelectSingleNode("div[@class='post_item_foot']/a[@class='lightblue']");
    22     string author = nodeAuthor.InnerText;
    23 
    24     Console.WriteLine($"标题:{title} | 作者:{author} | 地址:{url}");
    25 }

     运行截图:

    四.循环抓取多个分页

    前面我们分析出请求参数中的 PageIndex  是页数,分析单个页面的代码我们也写出来来,那么我们可以通过循环递增页数,来达到抓取不同分页数据的要求。

    贴一下完整的代码

     1 int pageIndex = 1;//页数
     2 int maxPageIndex = 10;//最大页数
     3 HttpHelpers httpHelpers=new HttpHelpers();
     4 
     5 for (int i = 0; i < maxPageIndex; i++)
     6 {
     7     HttpItems items = new HttpItems();
     8     items.Url = "https://www.cnblogs.com/mvc/AggSite/PostList.aspx";//请求地址
     9     items.Method = "Post";//请求方式 post
    10     items.Postdata = "{"CategoryType":"SiteHome"," +
    11                         ""ParentCategoryId":0," +
    12                         ""CategoryId":808," +
    13                         ""PageIndex":" + (i+1) + "," + //因为i从0开始 所以此处我们要加1
    14                         ""TotalPostCount":4000," +
    15                         ""ItemListActionName":"PostList"}";//请求数据
    16     HttpResults hr = httpHelpers.GetHtml(items);
    17 
    18     //解析数据
    19     HtmlDocument doc = new HtmlDocument();
    20     //加载html
    21     doc.LoadHtml(hr.Html);
    22 
    23     //获取 class=post_item_body 的div列表
    24     HtmlNodeCollection itemNodes = doc.DocumentNode.SelectNodes("div[@class='post_item']/div[@class='post_item_body']");
    25 
    26     Console.WriteLine($"第{i+1}页数据:");
    27 
    28     //循环根据每个div解析我们想要的数据
    29     foreach (var item in itemNodes)
    30     {
    31         //获取包含博文标题和地址的 a 标签
    32         var nodeA = item.SelectSingleNode("h3/a");
    33         //获取博文标题
    34         string title = nodeA.InnerText;
    35         //获取博文地址 a标签的 href 属性
    36         string url = nodeA.GetAttributeValue("href", "");
    37 
    38         //获取包含作者名字的 a 标签
    39         var nodeAuthor = item.SelectSingleNode("div[@class='post_item_foot']/a[@class='lightblue']");
    40         string author = nodeAuthor.InnerText;
    41         //输出数据
    42         Console.WriteLine($"标题:{title} | 作者:{author} | 地址:{url}");
    43     }
    44 
    45     //每抓取一页数据 暂停三秒
    46     Thread.Sleep(3000);
    47 }
    48             
    49 Console.ReadKey();

     运行截图:

    一个简单的.net core实现的简单爬虫就此完成!

     Demo下载

  • 相关阅读:
    【已解决】github中git push origin master出错:error: failed to push some refs to
    好记心不如烂笔头,ssh登录 The authenticity of host 192.168.0.xxx can't be established. 的问题
    THINKPHP 5.0目录结构
    thinkphp5.0入口文件
    thinkphp5.0 生命周期
    thinkphp5.0 架构
    Django template
    Django queryset
    Django model
    Python unittest
  • 原文地址:https://www.cnblogs.com/stulzq/p/7474334.html
Copyright © 2011-2022 走看看