WebClient.DownloadString()返回具有特殊字符的字符串

时间:2011-01-17 18:25:31

标签: c# asp.net .net character-encoding special-characters

我遇到了一些问题,我们正在从网上下载我正在制作的屏幕抓取工具。

在下面的代码中,从Web客户端下载字符串方法返回的字符串为少数(并非所有)网站的源下载返回一些奇怪的字符。

我最近添加了http标头,如下所示。以前调用相同的代码而没有标题达到相同的效果。我没有尝试过'Accept-Charset'标题的变体,除了基础知识之外,我对文本编码知之甚少。

我所指的字符或字符序列是:



“的 A

在Web浏览器中使用“查看源”时,看不到这些字符。可能导致这种情况的原因是什么?如何纠正这个问题?

string urlData = String.Empty;
WebClient wc = new WebClient();

// Add headers to impersonate a web browser. Some web sites 
// will not respond correctly without these headers
wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12");
wc.Headers.Add("Accept", "*/*");
wc.Headers.Add("Accept-Language", "en-gb,en;q=0.5");
wc.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");

urlData = wc.DownloadString(uri);

6 个答案:

答案 0 :(得分:98)

是八位字节EF BB BF的windows-1252表示。这是the UTF-8 byte-order marker,这意味着您的远程网页是以UTF-8编码的,但您正在阅读它,就像它是windows-1252一样。 According to the docsWebClient.DownloadString在将远程资源转换为字符串时使用Webclient.Encoding作为编码。将其设置为System.Text.Encoding.UTF8,事情理论上应该有效。

答案 1 :(得分:47)

实施WebClient.DownloadString的方式非常愚蠢。它应该从响应中的Content-Type标头获取字符编码,但是它希望开发人员事先告诉预期的编码。我不知道这个班的开发人员在想什么。

我创建了一个辅助类,它从响应的Content-Type标题中检索编码名称:

public static class WebUtils
{
    public static Encoding GetEncodingFrom(
        NameValueCollection responseHeaders,
        Encoding defaultEncoding = null)
    {
        if(responseHeaders == null)
            throw new ArgumentNullException("responseHeaders");

        //Note that key lookup is case-insensitive
        var contentType = responseHeaders["Content-Type"];
        if(contentType == null)
            return defaultEncoding;

        var contentTypeParts = contentType.Split(';');
        if(contentTypeParts.Length <= 1)
            return defaultEncoding;

        var charsetPart =
            contentTypeParts.Skip(1).FirstOrDefault(
                p => p.TrimStart().StartsWith("charset", StringComparison.InvariantCultureIgnoreCase));
        if(charsetPart == null)
            return defaultEncoding;

        var charsetPartParts = charsetPart.Split('=');
        if(charsetPartParts.Length != 2)
            return defaultEncoding;

        var charsetName = charsetPartParts[1].Trim();
        if(charsetName == "")
            return defaultEncoding;

        try
        {
            return Encoding.GetEncoding(charsetName);
        }
        catch(ArgumentException ex) 
        {
            throw new UnknownEncodingException(
                charsetName,   
                "The server returned data in an unknown encoding: " + charsetName, 
                ex);
        }
    }
}

UnknownEncodingException是一个自定义异常类,如果需要,可随意替换InvalidOperationException或其他任何内容

然后,WebClient类的以下扩展方法将起到作用:

public static class WebClientExtensions
{
    public static string DownloadStringAwareOfEncoding(this WebClient webClient, Uri uri)
    {
        var rawData = webClient.DownloadData(uri);
        var encoding = WebUtils.GetEncodingFrom(webClient.ResponseHeaders, Encoding.UTF8);
        return encoding.GetString(rawData);
    }
}

所以在你的例子中你会这样做:

urlData = wc.DownloadStringAwareOfEncoding(uri);

......那就是它。

答案 2 :(得分:12)

var client = new WebClient { Encoding = System.Text.Encoding.UTF8 };

var json = client.DownloadString(url);

答案 3 :(得分:1)

在我的情况下,返回的数据是gzip并且必须先解压缩,所以我觉得这个答案很有用:

https://stackoverflow.com/a/34418228/74585

答案 4 :(得分:0)

在我的情况下,我删除了与语言,字符集等相关的标题 除了用户代理和cookie。它工作..

 // try commenting
 //wc.Headers.Add("Accept-Language", "en-gb,en;q=0.5");
 //wc.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");

答案 5 :(得分:0)

对于某些特殊网站,例如&#34; www.yahoo.com&#34;,他们都没有为我工作。我解决问题的唯一方法是将DownloadString更改为OpenRead并使用UserAgent标头,例如示例代码。但是,有些网站喜欢&#34; www.varzesh3.com&#34;没有使用任何方法!

WebClient client = new WebClient()    
client.Headers.Add(HttpRequestHeader.UserAgent, "");
var stream = client.OpenRead("http://www.yahoo.com");
StreamReader sr = new StreamReader(stream);
s = sr.ReadToEnd();
相关问题