c#抓取网页数据(最省事的做法是去需要的网站看看具体是什么编码 )

优采云 发布时间: 2022-01-05 22:11

  c#抓取网页数据(最省事的做法是去需要的网站看看具体是什么编码

)

  在做一些需要抓取网页的项目时,经常会遇到乱码。最简单的方法就是去需要爬取的网站看看具体的编码是什么,然后使用正确的编码进行解码。可以,但是总是一一判断也不是问题,尤其是当你需要从不同站点抓取大量页面的时候,比如一个网络爬虫程序,那么我们就需要做一个比较通用的程序来正确识别页面编码。

  乱码问题基本上是编码不一致造成的。比如网页编码使用UTF-8,如果使用GB2312读取,肯定会出现乱码。知道了本质问题之后,剩下的就是如何判断网页编码了。GBK、GB2312、UTF-8、BIG-5,一般来说,遇到的中文网页编码大多是这几种编码。简单来说,只有GBK和UTF-8两种,一点都不夸张。,目前的网站要么是GBK编码,要么是UTF-8编码,所以接下来的问题就是确定网站具体是UTF-8还是GBK。

  如何确定页面的具体编码?首先检查响应头的Content-Type。如果在响应头中找不到,请到网页中查找元头。如果还是找不到,那就没办法了。设置默认编码。个人建议设置为UTF-8。比如访问博客园的首页,可以看到Content-Type:text/html;响应头中的charset=utf-8,所以我们知道博客园使用的是utf-8编码,但是并不是所有的网站都会在响应头的Content-Type中添加页面编码。比如百度的就是Content-Type:text/html,查不到charset。这时候只能在网页中找到它来确认网页的最终编码。总结就是以下步骤

  1.在响应头中的 Content-Type 中找到字符集。如果找到charset,则跳过第2步和第3步,直接进入第4步。2.如果第1步没有找到charset,先读取网页的Content,解析meta中的charset得到页面编码< @3.如果在第2步还是没有获取到页面编码,则没有办法设置默认编码为UTF-84. 使用获取到的charset重新读取响应流

  基本上,通过上述方法大部分页面都可以正确解析,但无法识别的则需要亲自验证具体代码。

  注意:

  1.几乎所有站点都启用了gzip压缩支持,所以在请求头中添加Accept-Encoding:gzip,deflate,这样站点会返回一个压缩流,可以显着提高请求的效率。2.由于网络流不支持流搜索操作,即只能读取一次。为了提高效率,建议先将http响应流读入内存,方便二次解码。无需重新请求检索响应流。

  下面给出了Java和C#的实现代码,页面底部给出了源码的git链接。需要童鞋的请自行下载

  Java实现

  C# 实现

  using System;

using System.Collections;

using System.IO;

using System.Linq;

using System.Net;

using System.Net.Security;

using System.Security.Cryptography.X509Certificates;

using System.Text;

using System.Text.RegularExpressions;

using System.Web;

using System.IO.Compression;

using System.Collections.Generic;

using System.Collections.Specialized;

namespace CSharp.Util.Net

{

public class HttpHelper

{

private static bool RemoteCertificateValidate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)

{

//用户https请求

return true; //总是接受

}

public static string SendPost(string url, string data)

{

return Send(url, "POST", data, null);

}

public static string SendGet(string url)

{

return Send(url, "GET", null, null);

}

public static string Send(string url, string method, string data, HttpConfig config)

{

if (config == null) config = new HttpConfig();

string result;

using (HttpWebResponse response = GetResponse(url, method, data, config))

{

Stream stream = response.GetResponseStream();

if (!String.IsNullOrEmpty(response.ContentEncoding))

{

if (response.ContentEncoding.Contains("gzip"))

{

stream = new GZipStream(stream, CompressionMode.Decompress);

}

else if (response.ContentEncoding.Contains("deflate"))

{

stream = new DeflateStream(stream, CompressionMode.Decompress);

}

}

byte[] bytes = null;

using (MemoryStream ms = new MemoryStream())

{

int count;

byte[] buffer = new byte[4096];

while ((count = stream.Read(buffer, 0, buffer.Length)) > 0)

{

ms.Write(buffer, 0, count);

}

bytes = ms.ToArray();

}

#region 检测流编码

Encoding encoding;

//检测响应头是否返回了编码类型,若返回了编码类型则使用返回的编码

//注:有时响应头没有编码类型,CharacterSet经常设置为ISO-8859-1

if (!string.IsNullOrEmpty(response.CharacterSet) && response.CharacterSet.ToUpper() != "ISO-8859-1")

{

encoding = Encoding.GetEncoding(response.CharacterSet == "utf8" ? "utf-8" : response.CharacterSet);

}

else

{

//若没有在响应头找到编码,则去html找meta头的charset

result = Encoding.Default.GetString(bytes);

//在返回的html里使用正则匹配页面编码

Match match = Regex.Match(result, @"", RegexOptions.IgnoreCase);

if (match.Success)

{

encoding = Encoding.GetEncoding(match.Groups[1].Value);

}

else

{

//若html里面也找不到编码,默认使用utf-8

encoding = Encoding.GetEncoding(config.CharacterSet);

}

}

#endregion

result = encoding.GetString(bytes);

}

return result;

}

private static HttpWebResponse GetResponse(string url, string method, string data, HttpConfig config)

{

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

request.Method = method;

request.Referer = config.Referer;

//有些页面不设置用户代理信息则会抓取不到内容

request.UserAgent = config.UserAgent;

request.Timeout = config.Timeout;

request.Accept = config.Accept;

request.Headers.Set("Accept-Encoding", config.AcceptEncoding);

request.ContentType = config.ContentType;

request.KeepAlive = config.KeepAlive;

if (url.ToLower().StartsWith("https"))

{

//这里加入解决生产环境访问https的问题--Could not establish trust relationship for the SSL/TLS secure channel

ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(RemoteCertificateValidate);

}

if (method.ToUpper() == "POST")

{

if (!string.IsNullOrEmpty(data))

{

byte[] bytes = Encoding.UTF8.GetBytes(data);

if (config.GZipCompress)

{

using (MemoryStream stream = new MemoryStream())

{

using (GZipStream gZipStream = new GZipStream(stream, CompressionMode.Compress))

{

gZipStream.Write(bytes, 0, bytes.Length);

}

bytes = stream.ToArray();

}

}

request.ContentLength = bytes.Length;

request.GetRequestStream().Write(bytes, 0, bytes.Length);

}

else

{

request.ContentLength = 0;

}

}

return (HttpWebResponse)request.GetResponse();

}

}

public class HttpConfig

{

public string Referer { get; set; }

///

/// 默认(text/html)

///

public string ContentType { get; set; }

public string Accept { get; set; }

public string AcceptEncoding { get; set; }

///

/// 超时时间(毫秒)默认100000

///

public int Timeout { get; set; }

public string UserAgent { get; set; }

///

/// POST请求时,数据是否进行gzip压缩

///

public bool GZipCompress { get; set; }

public bool KeepAlive { get; set; }

public string CharacterSet { get; set; }

public HttpConfig()

{

this.Timeout = 100000;

this.ContentType = "text/html; charset=" + Encoding.UTF8.WebName;

this.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36";

this.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";

this.AcceptEncoding = "gzip,deflate";

this.GZipCompress = false;

this.KeepAlive = true;

this.CharacterSet = "UTF-8";

}

}

}

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线