WebClient.DownloadString () devuelve una cadena con caracteres peculiares

Tengo un problema con algunos contenidos que estamos descargando de la web para una herramienta de raspado de pantalla que estoy creando.

en el siguiente código, la cadena devuelta por el método de cadena de descarga del cliente web devuelve algunos caracteres extraños para la descarga de la fuente de algunos (no todos) los sitios web.

Recientemente agregué encabezados http como a continuación. Anteriormente, se llamaba al mismo código sin los encabezados para el mismo efecto. No he intentado variaciones en el encabezado ‘Aceptar-Charset’, no sé mucho sobre encoding de texto que no sean los básicos.

Los personajes o secuencias de personajes a los que me refiero son:

ï» ¿

y

Â

Estos caracteres no se ven cuando usa “ver fuente” en un navegador web. ¿Qué podría estar causando esto y cómo puedo rectificar el problema?

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); 

 es la representación de Windows-1252 de los octetos EF BB BF . Ese es el marcador de orden de bytes UTF-8 , lo que implica que su página web remota está codificada en UTF-8, pero la está leyendo como si fuera windows-1252. De acuerdo con los documentos , WebClient.DownloadString utiliza Webclient.Encoding como su encoding cuando convierte el recurso remoto en una cadena. System.Text.Encoding.UTF8 en System.Text.Encoding.UTF8 y las cosas deberían funcionar teóricamente.

La forma en que se implementa WebClient.DownloadString es muy tonto. Debería obtener la encoding de caracteres del encabezado Content-Type en la respuesta, pero en su lugar espera que el desarrollador cuente la encoding esperada de antemano. No sé qué pensaban los desarrolladores de esta clase.

Creé una clase auxiliar que recupera el nombre de encoding del encabezado Content-Type de la respuesta:

 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 es una clase de excepción personalizada, puede reemplazar InvalidOperationException o cualquier otra cosa si lo desea)

Entonces el siguiente método de extensión para la clase WebClient hará el truco:

 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); } } 

Entonces en tu ejemplo harías:

 urlData = wc.DownloadStringAwareOfEncoding(uri); 

…y eso es.

 var client = new WebClient { Encoding = System.Text.Encoding.UTF8 }; var json = client.DownloadString(url); 

En mi caso, los datos devueltos tenían gzip y tuvieron que descomprimirse primero, así que encontré esta respuesta útil:

https://stackoverflow.com/a/34418228/74585

en mi caso, eliminé el encabezado relacionado con el idioma, el juego de caracteres, etc. Excepto el agente de usuario y la cookie. funcionó..

  // 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"); 

Ninguno de ellos no funcionó para mí en algunos sitios web especiales, como “www.yahoo.com”. La única forma en que OpenRead mi problema fue cambiando DownloadString a OpenRead y usando el encabezado UserAgent como código de muestra. Sin embargo, algunos sitios como “www.varzesh3.com” no funcionaron con ninguno de los métodos.

 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();