所以,我试图从一个名为 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的东西,但我对此知之甚少。
提前谢谢。
您尝试下载为字符串的页面使用charset=EUC-JP
进行编码,也称为Japanese (EUC)
(CodePage 51932)。这在页眉中明确设置。
为什么 WebClient.DownloadString 返回的字符串使用错误的编码器进行编码?
MSDN 文档指出:
此方法检索指定的资源。下载后 资源,该方法使用编码中指定的编码 属性,以将资源转换为字符串。
因此,您必须事先知道将使用哪种编码并指定它,设置 WebClient.Encoding 属性。
若要验证这一点,请检查 WebClient.DownloadString 方法的 .NET 引用源:
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();
}
编码是使用请求设置设置的,而不是响应设置的。
结果是,下载的字符串使用默认代码页进行编码。
您现在可以做的是:
- 下载页面两次,第一次检查Web客户端编码和Html页面编码是否不匹配。
- 使用在基础 Web 响应中设置的正确编码重新编码字符串。
- 不要使用 WebClient,直接使用 HttpClient 或 WebRequest。或者,如果您喜欢此工具,请创建自定义 WebClient 类以更直接的方式处理 WebRequest/WebResponse。
这是一种执行重新编码任务的方法:
WebClient 返回的字符串被转换为字节数组并传递给MemoryStream
,然后使用从Content-Type: charset
响应标头检索编码的StreamReader
重新编码。
编辑:
现在使用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;