c#实现爬⾍程序
图1
为什么要了解请求头(Request headers)信息?
原因是我们可以根据请求头信息某部分报⽂信息伪装这是⼀个正常HTTP请求⽽不是⼈为爬⾍程序躲过站点封杀,⽽成功获取响应数据(Response data)。
如何查看百度新闻⽹址请求头信息?
图2
如图2,我们可以打开⾕歌浏览器或者其他浏览器开发⼯具(按F12)查看该站点请求头报⽂信息。从图中可以了解到该百度新闻站点可以接受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
如图3,响应数据(Response data)是可以从⾕歌浏览器或者其他浏览器中开发⼯具(按F12)查看到的,响应可以是json数据,可以是DOM树数据,⽅便我们后续解析数据。
当然您可以学习任意⼀门开发语⾔开发爬⾍程序:C#、NodeJs、Python、Java、C++。
但这⾥主要讲述是C#开发爬⾍程序。微软为我们提供两个关于HTTP请求HttpWebRequest,HttpWebResponse对象,⽅便我们发送请求获取数据。以下展⽰下C# HTTP请求代码:
private string RequestAction(RequestOptions options)
{
string result = string.Empty;
IWebProxy proxy = GetProxy();
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 = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36";//设置User-Agent,伪装成Google Chrome浏览器 request.Timeout = options.Timeout;//定义请求超时时间为5秒
request.KeepAlive = options.KeepAlive;//启⽤长连接
if (!string.IsNullOrEmpty(options.Referer)) request.Referer = options.Referer;//返回上⼀级历史链接python正则表达式爬虫
request.Method = options.Method;//定义请求⽅式为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))
{
result = 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))
{
result = reader.ReadToEnd();
}
}
}
else
{
using (Stream stream = response.GetResponseStream())//原始
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
result = reader.ReadToEnd();
}
}
}
}
request.Abort();
return result;
}
还有⼀个我⾃定义传参对象,当然⽆论传⼊或者传出的对象都是你们根据⾃⼰实际业务需求定义的:
public class RequestOptions
{
/
// <summary>
/// 请求⽅式,GET或POST
/// </summary>
public string Method { get; set; }
/// <summary>
/// URL
/// </summary>
public Uri Uri { get; set; }
/// <summary>
/// 上⼀级历史记录链接
/// </summary>
public string Referer { get; set; }
/// <summary>
/// 超时时间(毫秒)
/// </summary>
public int Timeout = 15000;
/// <summary>
/// 启⽤长连接
/// </summary>
public bool KeepAlive = true;
/// <summary>
/// 禁⽌⾃动跳转
/
// </summary>
public bool AllowAutoRedirect = false;
/// <summary>
/// 定义最⼤连接数
/// </summary>
public int ConnectionLimit = int.MaxValue;
/// <summary>
/// 请求次数
/// </summary>
public int RequestNum = 3;
/// <summary>
/
// 可通过⽂件上传提交的⽂件类型
/// </summary>
public string Accept = "*/*";
/// <summary>
/// 内容类型
/// </summary>
public string ContentType = "application/x-www-form-urlencoded";
/// <summary>
/// 实例化头部信息
/// </summary>
private WebHeaderCollection header = new WebHeaderCollection();
/
// <summary>
/// 头部信息
/// </summary>
public WebHeaderCollection WebHeader
{
get { return header; }
set { header = value; }
}
/// <summary>
/// 定义请求Cookie字符串
/// </summary>
public string RequestCookies { get; set; }
/// <summary>
/// 异步参数数据
/// </summary>
public string XHRParams { get; set; }
}
根据展⽰的代码,我们可以发现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()
{
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)
{
Console.WriteLine("获取代理信息异常", DateTime.Now.ToString(), ex.Message);
}
return webProxy;
}
关于 System.Net.WebProxy对象参数说明,我在代码⾥⾯也做了解释。
如果获取到Response data数据是json,xml等格式数据,这类型解析数据⽅法我们这⾥就不详细说了,请⾃⾏百度。这⾥主要讲的是DOM树 HTML数据解析,对于这类型数据有⼈会⽤正则表达式来解析,也有⼈⽤组件。当然只要能获取到⾃⼰想要数据,怎么解析都是可以。这⾥主要讲我经常⽤到解析组件HtmlAgilityPack,引⽤DLL为(using 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);
}
}
下⾯主要展⽰抓取结果。
图4
如图4,抓取效果,⼀个简单爬⾍程序就这样⼦完成了。
到此这篇关于c#实现爬⾍程序的⽂章就介绍到这了。希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论