2010-04-23 24 views
9

Sử dụng đoạn mã sau, tôi có thể tải về HTML của một tập tin từ internet:Nhân vật trong chuỗi thay đổi sau khi tải về HTML từ internet

WebClient wc = new WebClient(); 

// .... 

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

Tuy nhiên, đôi khi các tập tin chứa các ký tự "thú vị" như é để é, đến â†フシギダネ đến フシギダãƒ.

Tôi nghĩ nó có thể liên quan đến các loại unicode khác nhau, vì mỗi nhân vật được thay đổi thành 2 cái mới, có lẽ mỗi nhân vật bị chia làm đôi nhưng tôi có rất ít kiến ​​thức trong lĩnh vực này. Bạn nghĩ gì là sai?

+1

Máy chủ có thể trả về mã hóa sai trong tiêu đề 'Loại nội dung'. – dtb

+4

Bạn nên đọc [bài viết này] (http://www.joelonsoftware.com/articles/Unicode.html) để có được một số hiểu biết cơ bản về Unicode. Nó sẽ bao gồm tất cả các lý do tại sao một số mặt hàng xuất hiện dưới dạng hai ví dụ. Nhưng quan trọng, nó sẽ giúp bạn hiểu những điều cơ bản bạn cần biết về Unicode. –

+1

HTML UTF-8 khá chắc chắn này được xem trong ISO-8859-1 hoặc mã hóa một byte khác. –

Trả lời

43

Đây là lớp tải xuống được gói hỗ trợ gzip và kiểm tra tiêu đề mã hóa và thẻ meta để giải mã chính xác.

Khởi tạo lớp học và gọi 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

Hey, điều đó chỉ hoạt động. Cảm ơn. –

+1

Một cái gì đó tôi đã viết năm ngoái cho một dự án azure :) Vui mừng nó có thể được sử dụng cho bạn. –

+0

Cảm ơn bạn đã chia sẻ Mikael này. Tôi đã sử dụng nó và tôi tìm thấy một vấn đề với việc phát hiện mã hóa. Nếu tiêu đề chứa 'bộ ký tự ', nó không nên kiểm tra thẻ meta vì các quy tắc ưu tiên nêu rõ rằng trong trường hợp tiêu đề xung đột có mức độ ưu tiên cao nhất. http://goo.gl/5q0Yg – Diadistis

-4

Hãy thử điều này

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

i allways tháo cuối cùng "Slash" và nó làm việc cho đến bây giờ giống như một nét duyên dáng. Nhưng tôi cũng có thể là mối nguy hiểm

+5

Dấu gạch chéo ở cuối URL không liên quan gì đến mã hóa. –

2

Vì tôi không được phép nhận xét (danh tiếng không đủ), tôi sẽ phải đăng câu trả lời bổ sung. Tôi thường xuyên sử dụng lớp học tuyệt vời của Mikael, nhưng tôi gặp phải một vấn đề thực tế với regex cố gắng tìm meta-thông tin ký tự. Đây

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

thất bại về vấn đề này

<meta charset="UTF-8"/> 

khi này

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

không.

Cảm ơn, Mikael.

+0

Cảm ơn bạn. Đã thay đổi mã của tôi :) –

Các vấn đề liên quan