继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

一个简单c#爬虫程序

至尊宝的传说
关注TA
已关注
手记 129
粉丝 82
获赞 463


这篇文章只是简单展示一个基于HTTP请求如何抓取数据的文章,如觉得简单的朋友,后续我们再慢慢深入研究探讨。

1:

 https://img4.mukewang.com/5b17cf20000110b608280491.jpg

 如图1,我们工作过程中,无论平台网站还是企业官网,总少不了新闻展示。如某天产品经理跟我们说,推广人员想要抓取百度新闻中热点要闻版块提高站点百度排名。要抓取百度的热点要闻版本,首先我们先要了解站点https://news.baidu.com/请求头(Request headers)信息。

为什么要了解请求头(Request headers)信息? 

原因是我们可以根据请求头信息某部分报文信息伪装这是一个正常HTTP请求而不是人为爬虫程序躲过反爬人员封杀,从而成功获取响应数据(Response data)

 

如何查看百度新闻网址请求头信息?

 2:

 https://img2.mukewang.com/5b17cf370001577e10560477.jpg

如图2,我们可以打开谷歌浏览器或者其他浏览器查看该站点请求头报文信息。从图中可以了解到该百度新闻站点可以接受text/html等数据类型;语言是中文;浏览器版本是Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36等等报文信息,在我们发起一个HTTP请求的时候直接携带该报文信息过去。当然并不是每个报文信息参数都必须携带过去,携带一部分能够请求成功即可。

 

那什么是响应数据(Response data)?

3:

 https://img.mukewang.com/5b17cf5300017b3810860461.jpg

如图3,响应数据(Response data)是可以从谷歌浏览器或者其他浏览器中查看到的,响应可以是json数据,可以是DOM树数据,方便我们后续解析数据。

 

当然您可以学习任意一门开发语言开发爬虫程序:C#、NodeJs、Python、Java、C++。

但这里主要讲述是C#开发爬虫程序。微软为我们提供两个关于HTTP请求HttpWebRequest,HttpWebResponse对象,方便我们发送请求获取数据。以下展示下C# HTTP请求代码:

        private SimpleCrawlResult RequestAction()
        {
            SimpleCrawlResult _simpleCrawlResult = new SimpleCrawlResult();
            IWebProxy proxy = GetProxy(options.ProxyTypeEnum);            var request = (HttpWebRequest)WebRequest.Create(options.Uri);
            request.Accept = options.Accept;            //在使用curl做POST的时候, 当要POST的数据大于1024字节的时候, curl并不会直接就发起POST请求, 而是会分为俩步,            //发送一个请求, 包含一个Expect: 100 -continue, 询问Server使用愿意接受数据            //接收到Server返回的100 - continue应答以后, 才把数据POST给Server            //并不是所有的Server都会正确应答100 -continue, 比如lighttpd, 就会返回417 “Expectation Failed”, 则会造成逻辑出错.
            request.ServicePoint.Expect100Continue = false;
            request.ServicePoint.UseNagleAlgorithm = false;//禁止Nagle算法加快载入速度
            if (!string.IsNullOrEmpty(options.XHRParams)) { request.AllowWriteStreamBuffering = true; } else { request.AllowWriteStreamBuffering = false; }; //禁止缓冲加快载入速度
            request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");//定义gzip压缩页面支持
            request.ContentType = options.ContentType;//定义文档类型及编码
            request.AllowAutoRedirect = options.AllowAutoRedirect;//禁止自动跳转
            request.UserAgent = UserAgentHelper.GetUserAgent;//设置User-Agent,伪装成Google Chrome浏览器
            request.Timeout = options.Timeout;//定义请求超时时间为5秒
            request.KeepAlive = options.KeepAlive;//启用长连接
            if (!string.IsNullOrEmpty(options.Referer)) request.Referer = options.Referer;//返回上一级历史链接
            request.Method = options.Method.ToString();//定义请求方式为GET
            if (proxy != null) request.Proxy = proxy;//设置代理服务器IP,伪装请求地址
            if (!string.IsNullOrEmpty(options.RequestCookies)) request.Headers[HttpRequestHeader.Cookie] = options.RequestCookies;
            request.ServicePoint.ConnectionLimit = options.ConnectionLimit;//定义最大连接数
            if (options.WebHeader != null && options.WebHeader.Count > 0) request.Headers.Add(options.WebHeader);//添加头部信息
            if (!string.IsNullOrEmpty(options.XHRParams))//如果是POST请求,加入POST数据            {                byte[] buffer = Encoding.UTF8.GetBytes(options.XHRParams);                if (buffer != null)
                {
                    request.ContentLength = buffer.Length;
                    request.GetRequestStream().Write(buffer, 0, buffer.Length);
                }
            }            using (var response = (HttpWebResponse)request.GetResponse())
            {                ////获取请求响应
                //foreach (Cookie cookie in response.Cookies)                //    options.CookiesContainer.Add(cookie);//将Cookie加入容器,保存登录状态
                if (response.ContentEncoding.ToLower().Contains("gzip"))//解压                {                    using (GZipStream stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress))
                    {                        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                        {
                            _simpleCrawlResult.Contents = reader.ReadToEnd();
                        }
                    }
                }                else if (response.ContentEncoding.ToLower().Contains("deflate"))//解压                {                    using (DeflateStream stream = new DeflateStream(response.GetResponseStream(), CompressionMode.Decompress))
                    {                        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                        {
                            _simpleCrawlResult.Contents = reader.ReadToEnd();
                        }
                    }
                }                else
                {                    using (Stream stream = response.GetResponseStream())//原始                    {                        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                        {
                            _simpleCrawlResult.Contents = reader.ReadToEnd();
                        }
                    }
                }
            }
            _simpleCrawlResult.HttpRequest = request;
            request.Abort();
        }

View Code

根据展示的代码,我们可以发现HttpWebRequest对象里面都封装了很多Request headers报文参数,我们可以根据该网站的Request headers信息在微软提供的HttpWebRequest对象里设置(看代码报文参数注释,都有写相关参数说明,如果理解错误,望告之,谢谢),然后发送请求获取Response data解析数据。

 

还有补充一点,爬虫程序能够使用代理IP最好使用代理IP,这样降低被封杀机率,提高抓取效率。但是代理IP也分质量等级,对于某一些HTTPS站点,可能对应需要质量等级更加好的代理IP才能穿透,这里暂不跑题,后续我会写一篇关于代理IP质量等级文章详说我的见解。

 C#代码如何使用代理IP?

 微软NET框架也为了我们提供一个使用代理IP 的System.Net.WebProxy对象,关于使用代码如下:

        private System.Net.WebProxy GetProxy(ProxyType type)
        {
            System.Net.WebProxy webProxy = null;            try
            {                // 代理链接地址加端口
                string proxyHost = "192.168.1.1";                string proxyPort = "9030";                // 代理身份验证的帐号跟密码                //string proxyUser = "xxx";                //string proxyPass = "xxx";                // 设置代理服务器
                webProxy = new System.Net.WebProxy();                // 设置代理地址加端口
                webProxy.Address = new Uri(string.Format("{0}:{1}", proxyHost, proxyPort));                // 如果只是设置代理IP加端口,例如192.168.1.1:80,这里直接注释该段代码,则不需要设置提交给代理服务器进行身份验证的帐号跟密码。                //webProxy.Credentials = new System.Net.NetworkCredential(proxyUser, proxyPass);            }            catch (Exception ex)
            {
                LogHelper.WriteLine(typeof(Requester), 0, "获取代理信息异常", DateTime.Now.ToString(), type.ToString(), ex.Message);
            }            return webProxy;
        }

View Code

关于 System.Net.WebProxy对象参数说明,我在代码里面也做了解释。

 

如果获取到Response data数据是json,xml等格式数据,这类型解析数据方法我们这里就不详细说了,请自行百度。这里主要讲的是DOM树 HTML数据解析,对于这类型数据有人会用正则表达式来解析,也有人用组件。当然只要能获取到自己想要数据,怎么解析都是可以。这里主要讲我经常用到解析组件 HtmlAgilityPack。解析代码如下:

                HtmlDocument htmlDoc = new HtmlDocument();
                htmlDoc.LoadHtml(simpleCrawlResult.Contents);
                HtmlNodeCollection liNodes = htmlDoc.DocumentNode.SelectSingleNode("//div[@id='pane-news']").SelectSingleNode("div[1]/ul[1]").SelectNodes("li");                if (liNodes != null && liNodes.Count > 0)
                {                    for (int i = 0; i < liNodes.Count; i++)
                    {                        string title = liNodes[i].SelectSingleNode("strong[1]/a[1]").InnerText.Trim();                        string href = liNodes[i].SelectSingleNode("strong[1]/a[1]").GetAttributeValue("href", "").Trim();
                        Console.WriteLine("新闻标题:" + title + ",链接:" + href);
                    }
                }

View Code

另外附上HtmlAgilityPack学习链接 http://www.cnblogs.com/asxinyu/p/CSharp_HtmlAgilityPack_XPath_Weather_Data.html

 

下面主要展示抓取结果。

4:

https://img4.mukewang.com/5b17cf9e0001559e06660302.jpg

如图4,抓取效果,一个简单爬虫程序就这样子完成了。。。(这里只是小弟不才个人见解,如有错误,望各位大牛多多指教)

原文出处


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP