WebClient.DownloadString() возвращает строку со специальными символами
У меня есть проблема с некоторым контентом, который мы загружаем из Интернета для инструмента очистки экрана, который я создаю.
в приведенном ниже коде, строка, возвращаемая из метода строки загрузки веб-клиента, возвращает некоторые нечетные символы для загрузки источника для нескольких (не всех) веб-сайтов.
Недавно я добавил заголовки http, как показано ниже. Ранее этот же код вызывался без заголовков с тем же эффектом. Я не пробовал вариации в заголовке "Accept-Charset", я мало что знаю о текстовой кодировке, отличной от основ.
Символами или символьными последовательностями, на которые я ссылаюсь, являются:
" ï" ¿ "
и
" Â"
Эти символы не видны при использовании "источника просмотра" в веб-браузере. Что может быть причиной этого и как я могу исправить проблему?
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);
Ответы
Ответ 1

- это представление октетов EF BB BF
окна-1252. Это маркер порядка байтов UTF-8, что означает, что ваша удаленная веб-страница закодирована в UTF-8, но вы читаете ее так, как будто это были окна-1252. Согласно документам, WebClient.DownloadString
использует Webclient.Encoding
как его кодирование, когда он преобразует удаленный ресурс в строку. Установите его на System.Text.Encoding.UTF8
, и все должно теоретически работать.
Ответ 2
Способ 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);
... и что он.
Ответ 3
var client = new WebClient { Encoding = System.Text.Encoding.UTF8 };
var json = client.DownloadString(url);
Ответ 4
В моем случае возвращаемые данные были gzipped и должны были быть сначала распакованы, поэтому я нашел этот ответ полезным:
fooobar.com/questions/104027/...
Ответ 5
в моем случае, я удалил заголовок, связанный с языком, charset и т.д.
За исключением агента пользователя и файла 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");
Ответ 6
Никто из них не работал у меня на некоторых специальных сайтах, таких как "www.yahoo.com". Единственный способ решить мою проблему - изменить DownloadString
на OpenRead
и использовать заголовок UserAgent
, например, пример кода. Тем не менее, несколько сайтов, таких как "www.varzesh3.com", не работали ни с одним из методов!
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();