所以,我正试图从一个名为Kanji-A-Day.com的网站上获取一部分文字,但我遇到了问题。
你知道,我正试图从网站上获取日常汉字,我能够将HTML缩小到我想要的范围,但似乎字符不同......?
更奇怪的是,我通过直接从网站复制和粘贴来生成第二张图像的结果,所以这不是字体问题。
这是我用来获取角色的代码:
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的东西,但我不太了解它。
提前致谢。
答案 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