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

1:

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

为什么要了解请求头(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;//返回上一级历史链接
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 > ) 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, , 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 = ;
/// <summary>
/// 启用长连接
/// </summary>
public bool KeepAlive = true;
/// <summary>
/// 禁止自动跳转
/// </summary>
public bool AllowAutoRedirect = false;
/// <summary>
/// 定义最大连接数
/// </summary>
public int ConnectionLimit = int.MaxValue;
/// <summary>
/// 请求次数
/// </summary>
public int RequestNum = ;
/// <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 = ""; // 代理身份验证的帐号跟密码
//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 > )
{
for (int i = ; 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);
}
}

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

下面主要展示抓取结果。

4:

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

爬虫浅谈一:一个简单c#爬虫程序的更多相关文章

  1. python (1)一个简单的爬虫: python 在windows下 创建文件夹并写入文件

    1.一个简单的爬虫:爬取豆瓣的热门电影的信息 写在前面:如何创建本来存在的文件夹并写入 t_path = "d:/py/inn" #本来不存在inn,先定义路径,然后如果不存在,则 ...

  2. Python并发编程-一个简单的爬虫

    一个简单的爬虫 #网页状态码 #200 正常 #404 网页找不到 #502 504 import requests from multiprocessing import Pool def get( ...

  3. python爬虫系列(1)——一个简单的爬虫实例

    本文主要实现一个简单的爬虫,目的是从一个百度贴吧页面下载图片. 1. 概述 本文主要实现一个简单的爬虫,目的是从一个百度贴吧页面下载图片.下载图片的步骤如下: 获取网页html文本内容:分析html中 ...

  4. 【转】使用webmagic搭建一个简单的爬虫

    [转]使用webmagic搭建一个简单的爬虫 刚刚接触爬虫,听说webmagic很不错,于是就了解了一下. webmagic的是一个无须配置.便于二次开发的爬虫框架,它提供简单灵活的API,只需少量代 ...

  5. 用node.js从零开始去写一个简单的爬虫

    如果你不会Python语言,正好又是一个node.js小白,看完这篇文章之后,一定会觉得受益匪浅,感受到自己又新get到了一门技能,如何用node.js从零开始去写一个简单的爬虫,十分钟时间就能搞定, ...

  6. 浅谈1——用Eclipse调试JAVA程序

    本篇博客主要介绍如何用Eclipse调试简单的JAVA程序. 1.如下图,一个简单的JAVA程序  2.设置断点. 方法:选中需设置断点的行代码,按快捷键Ctrl+Shift+B,设置断点: 断点设置 ...

  7. 编写一个简单的C++程序

    编写一个简单的C++程序 每个C++程序都包含一个或多个函数(function),其中一个必须命名为main.操作系统通过调用main来运行C++程序.下面是一个非常简单的main函数,它什么也不干, ...

  8. 使用Go开发一个简单的服务器程序

    最近有个小项目,需要一个简单的后台程序来支撑,本来想用Nodejs来做,但是由于本人js一直很菜,并且很讨厌callback,虽然我也很喜欢异步模型,但我一直都觉得JS是反人类的.后台就用了go处理, ...

  9. 一个简单的flask程序

    初始化 所有Flask程序都必须创建一个程序实例. 程序实例是Flask类的对象,经常使用下述代码创建: from flask import Flask app = Flask(__name__) F ...

  10. 利用JSP编程技术实现一个简单的购物车程序

    实验二   JSP编程 一.实验目的1. 掌握JSP指令的使用方法:2. 掌握JSP动作的使用方法:3. 掌握JSP内置对象的使用方法:4. 掌握JavaBean的编程技术及使用方法:5. 掌握JSP ...

随机推荐

  1. hdoj1114 Piggy-Bank(DP 完全背包)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1114 思路: 题目看着有些绕,其实就是完全背包的变形,需要注意的是这里求最小值,所以需要将dp数组初始 ...

  2. ubuntu连有线网 无法连接外网

    问题:连上网线后,有ip,但是无法访问外网. 我的解决方案是: .通过命令行ifconfig命令查看以太网(即网线插口)的名称,如下图,'enp3s0'是网线插口(Ethernet以太网): zhum ...

  3. 神龟快跑,2016做的一款UWP游戏

    神龟快跑,2016做的一款UWP游戏, 实际是H5页面, 用LAYA转AS3得到的 安装地址 https://www.microsoft.com/zh-cn/store/p/神龟快跑/9nblggh4 ...

  4. Largest Rectangle in a Histogram(附上几组测试数据)

    Largest Rectangle in a Histogram http://acm.hdu.edu.cn/showproblem.php?pid=1506 Time Limit: 2000/100 ...

  5. .Net多线程 并行编程(三)---并行集合

    为了让共享的数组,集合能够被多线程更新,我们现在(.net4.0之后)可以使用并发集合来实现这个功能. 而System.Collections和System.Collections.Generic命名 ...

  6. PAT 1055 集体照 (25)(STL-list+代码)

    1055 集体照 (25)(25 分)提问 拍集体照时队形很重要,这里对给定的N个人K排的队形设计排队规则如下: 每排人数为N/K(向下取整),多出来的人全部站在最后一排: 后排所有人的个子都不比前排 ...

  7. php调用C#写的dll包

    1.转到需要注册的dll路径下 2.输入regasm命令+文件名 3问题解决

  8. laravel-excel文档翻译笔记

    1.安装      1>composer 安装 "maatwebsite/excel": "~2.1.0"      2>app/config/ap ...

  9. js 数组去重的三种方法(unique)

    方法一: Array.prototype.unique=function(){ var arr=[];//新建一个临时数组 for(var i=0;i<this.length;i++){//遍历 ...

  10. jquery中innerWidth(),outerWidth(),outerWidth(true)和width()的区别

    jquery中innerWidth(),outerWidth(),outerWidth(true)和width()的区别 var a = 元素本身的宽度: width() = a: innerWidt ...