C#爬虫,HttpClient请求,HtmlAgilityPack,HtmlDocument使用

爬虫简介

网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。

在这里插入图片描述

算法分析

网页分析算法可以归纳为基于网络拓扑、基于网页内容和基于用户访问行为三种类型。
拓扑分析算法
基于网页之间的链接,通过已知的网页或数据,来对与其有直接或间接链接关系的对象(可以是网页或网站等)作出评价的算法。又分为网页粒度、网站粒度和网页块粒度这三种。

(1)网页(Webpage)粒度的分析算法

PageRank和HITS算法是最常见的链接分析算法,两者都是通过对网页间链接度的递归和规范化计算,得到每个网页的重要度评价。PageRank算法虽然考虑了用户访问行为的随机性和Sink网页的存在,但忽略了绝大多数用户访问时带有目的性,即网页和链接与查询主题的相关性。针对这个问题,HITS算法提出了两个关键的概念:权威型网页(authority)和中心型网页(hub)。
基于链接的抓取的问题是相关页面主题团之间的隧道现象,即很多在抓取路径上偏离主题的网页也指向目标网页,局部评价策略中断了在当前路径上的抓取行为。文献提出了一种基于反向链接(BackLink)的分层式上下文模型(Context Model),用于描述指向目标网页一定物理跳数半径内的网页拓扑图的中心Layer0为目标网页,将网页依据指向目标网页的物理跳数进行层次划分,从外层网页指向内层网页的链接称为反向链接。

(2)网站粒度的分析算法

网站粒度的资源发现和管理策略也比网页粒度的更简单有效。网站粒度的爬虫抓取的关键之处在于站点的划分和站点等级(SiteRank)的计算。SiteRank的计算方法与PageRank类似,但是需要对网站之间的链接作一定程度抽象,并在一定的模型下计算链接的权重。
网站划分情况分为按域名划分和按IP地址划分两种。文献讨论了在分布式情况下,通过对同一个域名下不同主机、服务器的IP地址进行站点划分,构造站点图,利用类似PageRank的方法评价SiteRank。同时,根据不同文件在各个站点上的分布情况,构造文档图,结合SiteRank分布式计算得到DocRank。文献证明,利用分布式的SiteRank计算,不仅大大降低了单机站点的算法代价,而且克服了单独站点对整个网络覆盖率有限的缺点。附带的一个优点是,常见PageRank 造假难以对SiteRank进行欺骗。

(3)网页块粒度的分析算法

在一个页面中,往往含有多个指向其他页面的链接,这些链接中只有一部分是指向主题相关网页的,或根据网页的链接锚文本表明其具有较高重要性。但是,在PageRank和HITS算法中,没有对这些链接作区分,因此常常给网页分析带来广告等噪声链接的干扰。在网页块级别(Block level)进行链接分析的算法的基本思想是通过VIPS网页分割算法将网页分为不同的网页块(page block),然后对这些网页块建立page to block和block to page的链接矩阵,分别记为Z和X。于是,在page to page图上的网页块级别的PageRank为 W§=X×Z;在block to block图上的BlockRank为 W(b)=Z×X。已经有人实现了块级别的PageRank和HITS算法,并通过实验证明,效率和准确率都比传统的对应算法要好。
网页内容分析算法
基于网页内容的分析算法指的是利用网页内容(文本、数据等资源)特征进行的网页评价。网页的内容从原来的以超文本为主,发展到后来动态页面(或称为Hidden Web)数据为主,后者的数据量约为直接可见页面数据(PIW,Publicly Indexable Web)的400~500倍。另一方面,多媒体数据、Web Service等各种网络资源形式也日益丰富。因此,基于网页内容的分析算法也从原来的较为单纯的文本检索方法,发展为涵盖网页数据抽取、机器学习、数据挖掘、语义理解等多种方法的综合应用。本节根据网页数据形式的不同,将基于网页内容的分析算法,归纳以下三类:第一种针对以文本和超链接为主的无结构或结构很简单的网页;第二种针对从结构化的数据源(如RDBMS)动态生成的页面,其数据不能直接批量访问;第三种针对的数据界于第一和第二类数据之间,具有较好的结构,显示遵循一定模式或风格,且可以直接访问。
基于文本的网页分析算法
(1)纯文本分类与聚类算法
很大程度上借用了文本检索的技术。文本分析算法可以快速有效的对网页进行分类和聚类,但是由于忽略了网页间和网页内部的结构信息,很少单独使用。
(2)超文本分类和聚类算法
根据网页链接网页的相关类型对网页进行分类,依靠相关联的网页推测该网页的类型。

HttpClient

HttpClient实现了所有 HTTP 的方法(GET、POST、PUT、HEAD、DELETE、HEAD、OPTIONS 等)
支持 HTTPS 协议
支持代理服务器(Nginx等)等
支持自动(跳转)转向

由于今天我们主要讲解爬虫,所以不详细讲解HttpClient用法,最基础用法如下

string url = String.Format("https:/##########/");

            HttpClient client = new HttpClient();
            //结果
            string result = client.GetStringAsync(url).Result;

这样 result内就可以拿到请求的值

HtmlAgilityPack

HtmlAgilityPack是.net下的一个HTML解析类库。支持用XPath来解析HTML。这个意义不小,为什么呢?因为对于页面上的元素的xpath某些强大的浏览器能够直接获取得到,并不需要手动写。节约了大半写正则表达式的时间,当然正则表达式有时候在进一步获取的时候还需要写,但是通过xpath解析之后,正则表达式已经要匹配的范围已经非常小了。而且,不用正则表达式在整个页面源代码上匹配,速度也会有提升。总而言之,通过该类库,先通过浏览器获取到xpath获取到节点内容然后再通过正则表达式匹配到所需要的内容,无论是开发速度,还是运行效率都有提升。

HtmlAttribute  对应  Html元素的属性

HtmlAttributeCollection  一个元素属性的集合,实现了IList, ICollection, IEnumerable, IEnumerable,都是集合的那一套东西,没有新东西。

HtmlNode    对应  HTML节点,包括注释,文本,元素等

HtmlNodeCollection  一个HtmlNode节点集合,实现了HtmlNodeCollection : IList, ICollection, IEnumerable, IEnumerable继承了这些东西就没什么需要说的了,都是集合的东西,没有新的东西。完全是集合那一套。

HtmlNodeType  一个枚举  表示节点的类型,文档,注释,元素,文本。

HtmlTextNode  对应Html文本节点,很简单的一个类,继承自HtmlNode。

HtmlEntity   对应实体   实用程序类以替换特殊字符的实体,反之亦然

HtmlParseError   表示文档在解析过程中发现的解析错误。

实战教学

首先先添加 HtmlAgilityPack 的 NuGet 的引用包
在这里插入图片描述

网页请求

我们以99医药网为例,网址为https://yyk.99.com.cn/

下面我们尝试爬取南京市的所有医院

首先请求网址 https://yyk.99.com.cn/nanjing/

 string url = String.Format("https://yyk.99.com.cn/nanjing/");

            HttpClient client = new HttpClient();
            //结果
            string result = client.GetStringAsync(url).Result;

打开网站后首先对网页进行分析
在这里插入图片描述
我们发现所有医院的信息都存放在的标签下,且除了医院之外没有其他标签

所以我们用以下代码筛选出医院信息

  string url = String.Format("https://yyk.99.com.cn/nanjing/");

            HttpClient client = new HttpClient();
            //结果
            string result = client.GetStringAsync(url).Result;
            var doc = new HtmlDocument();
            //加载结果
            doc.LoadHtml(result);
            //筛选出所有TD标签
            HtmlNodeCollection maincontent = doc.DocumentNode.SelectNodes("//td");
            if (maincontent != null)
            {
                foreach (var item in maincontent)
                {
                	//遍历得到医院名称
                    var name = item.ChildNodes[0].InnerText;
                }
            }

目前到这一步,就可以拿到所有南京市医院的名称了。是不是很容易。下面我们更上一层楼。拿出所有医院的简介。如下图
请添加图片描述

我们接着回去分析网站结构,发现,想要进入到详情界面是更具href加上https://yyk.99.com.cn/ +href_+/jianjie.html 组成的请求地址。

请添加图片描述

所以改动代码为

  string url = String.Format("https://yyk.99.com.cn/nanjing/");

            HttpClient client = new HttpClient();
            //结果
            string result = client.GetStringAsync(url).Result;

            var doc = new HtmlDocument();
            
            doc.LoadHtml(result);
            HtmlNodeCollection maincontent = doc.DocumentNode.SelectNodes("//td");
            if (maincontent != null)
            {
                foreach (var item in maincontent)
                {
                  
                    var name = item.ChildNodes[0].InnerText;
                    var href = item.ChildNodes[0].Attributes["href"].Value;
                    string url1 = String.Format("https://yyk.99.com.cn"+href+ "/jianjie.html");
                    HttpClient client1 = new HttpClient();
                    //结果
                    string result1 = client1.GetStringAsync(url1).Result;

                    var doc1 = new HtmlDocument();
                    doc1.LoadHtml(result1);
                  
                }

            }

这样我们就可以请求南京市所有的医院详情页面
下面接着分析详情界面 发现 相关信息存放在</dl class=‘wrap-info’> 和 </divclass=‘wrap-box’> 这两个标签内。
在这里插入图片描述

下面完整代码,将爬取到的数据存放在本地文件内。

  public class YIYAO99
    {
        public YIYAO99()
        {

        }

        public string Savepath = @"H:\医院信息";

        public void Start()
        {

            string url = String.Format("https://yyk.99.com.cn/nanjing/");

            HttpClient client = new HttpClient();
            //结果
            string result = client.GetStringAsync(url).Result;

            var doc = new HtmlDocument();
            
            doc.LoadHtml(result);
            HtmlNodeCollection maincontent = doc.DocumentNode.SelectNodes("//td");
            if (maincontent != null)
            {
                foreach (var item in maincontent)
                {
                  
                    var name = item.ChildNodes[0].InnerText;
                    var href = item.ChildNodes[0].Attributes[0].Value;
                    string url1 = String.Format("https://yyk.99.com.cn"+href+ "/jianjie.html");
                    HttpClient client1 = new HttpClient();
                    //结果
                    string result1 = client1.GetStringAsync(url1).Result;

                    var doc1 = new HtmlDocument();
                    doc1.LoadHtml(result1);
                    var maincontent1 = doc1.DocumentNode.SelectNodes("//dl[@class='wrap-info']");
                    var maincontent2 = doc1.DocumentNode.SelectNodes("//div[@class='wrap-box']");
                    FileStream fs = new FileStream(Savepath+$"\\{name}.txt", System.IO.FileMode.Create, System.IO.FileAccess.Write);
                    StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8);
                    sw.WriteLine(maincontent1[0].InnerText);
                    sw.WriteLine(maincontent2[0].InnerText);
                    sw.Close();
                }

            }
        }
    }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新标签页

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值