WebClient 中的汉字 html 与网站中的实际汉字不同
Kanji characters from WebClient html different from actual Kanji in website
因此,我试图从名为 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 的东西,但我不太了解它。
提前致谢。
您尝试以字符串形式下载的页面使用 charset=EUC-JP
编码,也称为 Japanese (EUC)
(代码页 51932)。这个在页面headers.
中设置的很清楚
为什么 WebClient.DownloadString 返回的字符串使用错误的编码器编码?
MSDN 文档说明了这一点:
This method retrieves the specified resource. After it downloads the
resource, the method uses the encoding specified in the Encoding
property to convert the resource to a 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();
}
编码是使用 Request 设置设置的,而不是 Response 设置。
结果是,下载的字符串使用默认代码页进行编码。
您现在可以做的是:
- 下载页面两次,第一次检查WebClient编码是否与Html页面编码不匹配
- Re-encode 具有正确编码的字符串,在基础 WebResponse 中设置。
- 不要使用WebClient,直接使用HttpClient或WebRequest。或者,如果您喜欢此工具,请创建自定义 WebClient class 以更直接的方式处理 WebRequest/WebResponse。
这是执行re-encoding任务的方法:
WebClient 返回的字符串被转换为字节数组并传递给 MemoryStream
,然后 re-encoded 使用 StreamReader
和从 Content-Type: charset
响应中检索到的编码 Header.
编辑:
现在使用 Reflection
从底层 HttpWebResponse
获取页面 Encoding
。这应该避免在解析远程响应定义的原始 CharacterSet
时出错。
using System.IO;
using System.Net;
using System.Reflection;
using System.Text;
public string WebClient_DownLoadString(Uri uri)
{
using (var client = new WebClient())
{
// If Windows 7 - Windows Server 2008 R2
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
client.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache);
client.Headers.Add(HttpRequestHeader.Accept, "ext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
client.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-US,en;q=0.8");
client.Headers.Add(HttpRequestHeader.KeepAlive, "keep-alive");
string result = client.DownloadString(uri);
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
using (var response = (HttpWebResponse)client.GetType().GetField("m_WebResponse", flags).GetValue(client))
{
var pageEncoding = Encoding.GetEncoding(wc_response.CharacterSet);
byte[] bytes = client.Encoding.GetBytes(result);
using (var ms = new MemoryStream(bytes, 0, bytes.Length))
using (var reader = new StreamReader(ms, pageEncoding))
{
ms.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;
因此,我试图从名为 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 的东西,但我不太了解它。
提前致谢。
您尝试以字符串形式下载的页面使用 charset=EUC-JP
编码,也称为 Japanese (EUC)
(代码页 51932)。这个在页面headers.
为什么 WebClient.DownloadString 返回的字符串使用错误的编码器编码?
MSDN 文档说明了这一点:
This method retrieves the specified resource. After it downloads the resource, the method uses the encoding specified in the Encoding property to convert the resource to a 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();
}
编码是使用 Request 设置设置的,而不是 Response 设置。
结果是,下载的字符串使用默认代码页进行编码。
您现在可以做的是:
- 下载页面两次,第一次检查WebClient编码是否与Html页面编码不匹配
- Re-encode 具有正确编码的字符串,在基础 WebResponse 中设置。
- 不要使用WebClient,直接使用HttpClient或WebRequest。或者,如果您喜欢此工具,请创建自定义 WebClient class 以更直接的方式处理 WebRequest/WebResponse。
这是执行re-encoding任务的方法:
WebClient 返回的字符串被转换为字节数组并传递给 MemoryStream
,然后 re-encoded 使用 StreamReader
和从 Content-Type: charset
响应中检索到的编码 Header.
编辑:
现在使用 Reflection
从底层 HttpWebResponse
获取页面 Encoding
。这应该避免在解析远程响应定义的原始 CharacterSet
时出错。
using System.IO;
using System.Net;
using System.Reflection;
using System.Text;
public string WebClient_DownLoadString(Uri uri)
{
using (var client = new WebClient())
{
// If Windows 7 - Windows Server 2008 R2
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
client.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache);
client.Headers.Add(HttpRequestHeader.Accept, "ext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
client.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-US,en;q=0.8");
client.Headers.Add(HttpRequestHeader.KeepAlive, "keep-alive");
string result = client.DownloadString(uri);
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
using (var response = (HttpWebResponse)client.GetType().GetField("m_WebResponse", flags).GetValue(client))
{
var pageEncoding = Encoding.GetEncoding(wc_response.CharacterSet);
byte[] bytes = client.Encoding.GetBytes(result);
using (var ms = new MemoryStream(bytes, 0, bytes.Length))
using (var reader = new StreamReader(ms, pageEncoding))
{
ms.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;