WebClient html中的汉字字符与网站

时间:2018-04-15 20:20:12

标签: c# html unicode webclient system.net

所以,我正试图从一个名为Kanji-A-Day.com的网站上获取一部分文字,但我遇到了问题。

你知道,我正试图从网站上获取日常汉字,我能够将HTML缩小到我想要的范围,但似乎字符不同......?

What it looks like

What it should look like

更奇怪的是,我通过直接从网站复制和粘贴来生成第二张图像的结果,所以这不是字体问题。

这是我用来获取角色的代码:

public void UpdateDailyKanji() // Called at the initialization of a new main form
{
    string kanji;
    using (WebClient client = new WebClient()) // Grab the string 
        kanji = client.DownloadString("http://www.kanji-a-day.com/level4/index.php"); 
    // Trim the HTML to just the Kanji
    kanji = kanji.Remove(0, kanji.IndexOf(@"<div class=""glyph"">") + 19);
    kanji = kanji.Remove(kanji.IndexOf("</div>")-2);
    kanji = kanji.Trim();
    Text_DailyKanji.Text = kanji; // Set the Kanji
}

有谁知道这里发生了什么?我猜它是一些Unicode的东西,但我不太了解它。

提前致谢。

1 个答案:

答案 0 :(得分:2)

您尝试以字符串形式下载的页面使用charset=EUC-JP进行编码,也称为Japanese (EUC)(CodePage 51932)。这显然在页眉中设置。

为什么WebClient.DownloadString返回的字符串使用错误的编码器进行编码?

MSDN Docs说明了这一点:

  

此方法检索指定的资源。下载之后   资源,该方法使用编码中指定的编码   将资源转换为String的属性。

因此,您必须事先知道将使用哪种编码并指定它,设置WebClient.Encoding属性。

要验证这一点,请检查.NET Reference Source for the WebClient.DownloadString方法:

try {
    WebRequest request;
    byte [] data = DownloadDataInternal(address, out request);
    string stringData = GetStringUsingEncoding(request, data);
    if(Logging.On)Logging.Exit(Logging.Web, this, "DownloadString", stringData);
    return stringData;
    } finally {
        CompleteWebClientState();
    }

使用请求设置设置编码,而不是响应设置。
结果是,下载的字符串使用默认的CodePage进行编码。

你现在可以做的是:
- 下载页面两次,第一次检查WebClient编码和Html页面编码是否匹配。
- 使用正确的编码重新编码字符串。

这是执行后一项任务的方法:
WebClient返回的字符串将转换为字节数组并传递给MemoryStream,然后使用StreamReader重新编码,并从Content-Type: charset响应标头中检索编码。

修改
现在使用Reflection从基础Encoding获取页面HttpWebResponse。这应避免在解析远程响应定义的原始CharacterSet时出错。

using System.IO;
using System.Net;
using System.Reflection;
using System.Text;

public string WebClient_DownLoadString(Uri URI)
{
    using (WebClient webclient = new WebClient())
    {
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

        webclient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache);
        webclient.Headers.Add(HttpRequestHeader.Accept, "ext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        webclient.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-US,en;q=0.8");
        webclient.Headers.Add(HttpRequestHeader.KeepAlive, "keep-alive");

        string result = webclient.DownloadString(URI);
        using (HttpWebResponse wc_response = (HttpWebResponse)webclient
                        .GetType()
                        .GetField("m_WebResponse", BindingFlags.Instance | BindingFlags.NonPublic)
                        .GetValue(webclient))
        {
            Encoding PageEncoding = Encoding.GetEncoding(wc_response.CharacterSet);
            byte[] bresult = webclient.Encoding.GetBytes(result);
            using (MemoryStream memstream = new MemoryStream(bresult, 0, bresult.Length))
            using (StreamReader reader = new StreamReader(memstream, PageEncoding))
            {
                memstream.Position = 0;
                return reader.ReadToEnd();
            };
        };
    }
}

现在你的代码应该以正确的形式获得日文字符。

Uri URI = new Uri("http://www.kanji-a-day.com/level4/index.php", UriKind.Absolute);
string kanji = WebClient_DownLoadString(URI);

kanji = kanji.Remove(0, kanji.IndexOf(@"<div class=""glyph"">") + 19);
kanji = kanji.Remove(kanji.IndexOf("</div>")-2);
kanji = kanji.Trim();

Text_DailyKanji.Text = kanji; // Set the Kanji