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

в Windows-1252 представление октетовEF BB BF
. Это маркер порядка байтов UTF-8, что означает, что ваша удаленная веб-страница закодирована в UTF-8, но Вы читаете ее, как если бы это была windows-1252. согласно документам,WebClient.DownloadString
используетWebclient.Encoding
как его кодировка, когда он преобразует удаленный ресурс в строку. Установите его вSystem.Text.Encoding.UTF8
и все должно теоретически работать.
путь
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);
...и это все.
var client = new WebClient { Encoding = System.Text.Encoding.UTF8 }; var json = client.DownloadString(url);
в моем случае возвращенные данные были gzipped и должны были быть распакованы сначала, поэтому я нашел этот ответ полезным:
в моем случае я удалил когда-либо заголовок, связанный с языком, кодировкой и т. д Кроме агента пользователя и куки . это сработало..
// 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");
ни один из них не работал для меня на некоторых специальных сайтах, таких как "www.yahoo.com". единственный способ, которым я решаю свою проблему, - это изменение
DownloadString
toOpenRead
и с помощью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();