2010-04-23 45 views
9

下載HTML使用下面的代碼改變後,我可以從互聯網上下載的文件的HTML:字符字符串從互聯網

WebClient wc = new WebClient(); 

// .... 

string downloadedFile = wc.DownloadString("http://www.myurl.com/"); 

但是,有時文件包含像é以「有趣」的字符é,â†フシギダネフシギダãƒ

我認爲這可能是是與不同的Unicode類型或東西,因爲每個字符被改爲2分新的,也許每個字符被劈成兩半,但我在這方面知之甚少。你認爲什麼是錯的?

+1

服務器可能在'Content-Type'標頭中返回錯誤的編碼。 – dtb 2010-04-23 17:31:42

+4

您應該閱讀[本文](http://www.joelonsoftware.com/articles/Unicode.html)以獲得對Unicode的一些基本理解。例如,它將涵蓋爲什麼有些項目顯示爲兩個的所有原因。但重要的是,它將幫助您瞭解您需要了解的關於Unicode的基礎知識。 – 2010-04-23 17:31:53

+1

這非常肯定UTF-8 HTML在ISO-8859-1或其他單字節編碼中查看。 – 2010-04-23 17:35:14

回答

43

下面是支持gzip和檢查編碼標題和meta標籤,以便將其正確地解碼包的下載類。

實例化類,並調用GetPage()

public class HttpDownloader 
{ 
    private readonly string _referer; 
    private readonly string _userAgent; 

    public Encoding Encoding { get; set; } 
    public WebHeaderCollection Headers { get; set; } 
    public Uri Url { get; set; } 

    public HttpDownloader(string url, string referer, string userAgent) 
    { 
     Encoding = Encoding.GetEncoding("ISO-8859-1"); 
     Url = new Uri(url); // verify the uri 
     _userAgent = userAgent; 
     _referer = referer; 
    } 

    public string GetPage() 
    { 
     HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url); 
     if (!string.IsNullOrEmpty(_referer)) 
      request.Referer = _referer; 
     if (!string.IsNullOrEmpty(_userAgent)) 
      request.UserAgent = _userAgent; 

     request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate"); 

     using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
     { 
      Headers = response.Headers; 
      Url = response.ResponseUri; 
      return ProcessContent(response); 
     } 

    } 

    private string ProcessContent(HttpWebResponse response) 
    { 
     SetEncodingFromHeader(response); 

     Stream s = response.GetResponseStream(); 
     if (response.ContentEncoding.ToLower().Contains("gzip")) 
      s = new GZipStream(s, CompressionMode.Decompress); 
     else if (response.ContentEncoding.ToLower().Contains("deflate")) 
      s = new DeflateStream(s, CompressionMode.Decompress); 

     MemoryStream memStream = new MemoryStream(); 
     int bytesRead; 
     byte[] buffer = new byte[0x1000]; 
     for (bytesRead = s.Read(buffer, 0, buffer.Length); bytesRead > 0; bytesRead = s.Read(buffer, 0, buffer.Length)) 
     { 
      memStream.Write(buffer, 0, bytesRead); 
     } 
     s.Close(); 
     string html; 
     memStream.Position = 0; 
     using (StreamReader r = new StreamReader(memStream, Encoding)) 
     { 
      html = r.ReadToEnd().Trim(); 
      html = CheckMetaCharSetAndReEncode(memStream, html); 
     }    

     return html; 
    } 

    private void SetEncodingFromHeader(HttpWebResponse response) 
    { 
     string charset = null; 
     if (string.IsNullOrEmpty(response.CharacterSet)) 
     { 
      Match m = Regex.Match(response.ContentType, @";\s*charset\s*=\s*(?<charset>.*)", RegexOptions.IgnoreCase); 
      if (m.Success) 
      { 
       charset = m.Groups["charset"].Value.Trim(new[] { '\'', '"' }); 
      } 
     } 
     else 
     { 
      charset = response.CharacterSet; 
     } 
     if (!string.IsNullOrEmpty(charset)) 
     { 
      try 
      { 
       Encoding = Encoding.GetEncoding(charset); 
      } 
      catch (ArgumentException) 
      { 
      } 
     } 
    } 

    private string CheckMetaCharSetAndReEncode(Stream memStream, string html) 
    { 
     Match m = new Regex(@"<meta\s+.*?charset\s*=\s*""?(?<charset>[A-Za-z0-9_-]+)""?", RegexOptions.Singleline | RegexOptions.IgnoreCase).Match(html);    
     if (m.Success) 
     { 
      string charset = m.Groups["charset"].Value.ToLower() ?? "iso-8859-1"; 
      if ((charset == "unicode") || (charset == "utf-16")) 
      { 
       charset = "utf-8"; 
      } 

      try 
      { 
       Encoding metaEncoding = Encoding.GetEncoding(charset); 
       if (Encoding != metaEncoding) 
       { 
        memStream.Position = 0L; 
        StreamReader recodeReader = new StreamReader(memStream, metaEncoding); 
        html = recodeReader.ReadToEnd().Trim(); 
        recodeReader.Close(); 
       } 
      } 
      catch (ArgumentException) 
      { 
      } 
     } 

     return html; 
    } 
} 
+1

嘿,那只是工作。謝謝。 – 2010-04-23 17:51:45

+1

去年我爲一個天藍色的項目寫的東西:)很高興它可以爲你使用。 – 2010-04-23 17:56:21

+0

感謝分享這Mikael。我使用過它,並發現編碼檢測有問題。如果標題包含「charset」,它不應該檢查元標記,因爲優先規則明確指出在衝突標題具有最高優先級的情況下。 http://goo.gl/5q0Yg – Diadistis 2011-03-20 23:14:00

-4

試試這個

string downloadedFile = wc.DownloadString("http://www.myurl.com"); 

我永諾刪除最後一個「溼地」,它現在的工作,直到就像一個魅力。但我可能是也危害

+5

URL末尾的斜線與編碼無關。 – 2012-09-14 23:51:21

2

因爲我不能發表評論(口碑不足),我會發佈一個附加的應答。我常規使用Mikael的優秀課程,但是我遇到了一個嘗試查找字符集元信息的正則表達式的實際問題。這

Match m = new Regex(@"<meta\s+.*?charset\s*=\s*(?<charset>[A-Za-z0-9_-]+)", RegexOptions.Singleline | RegexOptions.IgnoreCase).Match(html); 

失敗這個

<meta charset="UTF-8"/> 

,而這

Match m = new Regex(@"<meta\s+.*?charset\s*=\s*""?(?<charset>[A-Za-z0-9_-]+)""?", RegexOptions.Singleline | RegexOptions.IgnoreCase).Match(html); 

沒有。

謝謝Mikael。

+0

謝謝。更改我的代碼:) – 2018-03-06 17:32:13