DOBON.NET DOBON.NETプログラミング掲示板過去ログ

どの文字コードでも化ける?

環境/言語:[OS : Windows XP / 言語 : Visual Basic .NET / .NET Framework : 2.0]
分類:[.NET]

【解決したい問題】

http://dobon.net/vb/dotnet/internet/webclientopenread.html
こちらを参考にHTMLの取得を行っているのですが、とあるサイトのデータを取得し、UTF-8にてエンコードしたところ、「�」という文字列が出てきました。(変な記号)

もしやと思い、Shift_JISやEUC-JPなどでも試してみましたが、同じような結果でした。
http://www.xmleditor.jp/blog/archives/40
こちらを参考に全部試してみたものの、どれもほぼ同じような結果になりました。

そのサイトにIE7.0でアクセスするとちゃんと表示され、文字コードやソースを確認してもUTF-8となっています。
また、WebClientでなく、WebBrowserを使用しアクセスしてもちゃんと表示されます。.Document.Encodingを確認するとutf-8と表示されました。
.Document.Body.OuterHtmlを確認すると<body>〜</body>がちゃんと表示されました。

一ヶ月ほど前はそのサイトはEUCだったようで、化けることなくきちんと取得出来ましたが、今日試してみたらできなくなっていました。
急にできなくなってしまったのでとても不思議です(´・ω・`)
その数文字しか受け取れないのでしょうか? それとも受け取った文字列の一部にそう言う文字が含まれているのでしょうか? サイズは元ページと同じぐらいで全部そう言う文字で埋め尽くされているとか?
DownloadData でバイト配列として受け取った場合、どんな状態でしょうか?
DownloadDataの結果をDebug.Printにて確認したところ、
約5000要素のByte配列。表示された記号は2つのみ。
配列の中身は31, 139, 8, 0, 0, 0, 0, 0, 0, 3, 221, 92,・・・ という内容でした。

WebBrowser.Document.Body.OuterHtmlをUTF-8にエンコードしてみると、約20000要素のByte配列となりました。
13, 10, 60, 66, 79, 68, 89, 32, 115, 115, 121, 108, 101,・・・という内容でした。
> 配列の中身は31, 139, 8, 0, 0, 0, 0, 0, 0, 3, 221, 92,・・・ という内容でした。
明らかに受信データがおかしいですね。
WebClient の ResponseHeaders でレスポンスヘッダを確認したり、あるいはパケットモニタとか使ってブラウザでの送受信時と通信内容がどう違うかを確認したりしましょう。
// https ならパケットモニタは使えませんが。
私見ですが、1F 8B 08 で始まるデータというと gzip エンコーディングされているものではないかと思います。
WebClient の場合特に追加しなければ Accept-Encoding は設定されないはずですから、サーバがクライアントの要求を無視して強制的に gzip エンコーディングしているのではないかな、と。
レスポンスの Content-Encoding ヘッダはちゃんと gzip を返しているんでしょうか?
// WebClient は gzip にも対応していますが、こちらから要求してない場合はどうなるんだろ?
WebClient.Headers に Accept-Encoding を gzip,deflate で追加すれば良いかもしれません。
あるいは DownloadData で受信したデータを MemoryStream でくるみ、GZipStream で読み出すという手もありますが……。

> WebBrowser.Document.Body.OuterHtmlをUTF-8にエンコードしてみると、
HTML 全体を取得するなら、Body.Parent.OuterHtml で HTML 要素から取得できます。
これで取得できる HTML は HTML DOM パーサが解析した結果を HTML に再変換したものですが、今回の場合は生のバイナリが重要です。
WebBrowser.DocumentStream を取得して Byte 配列にコピーし中身を確認すると、ブラウザが受信したままのバイナリを見ることができます。

> 急にできなくなってしまったのでとても不思議です(´・ω・`)
急にサイトの仕様が変わるなんて良くあることです。
レスポンスのContent-Encodingを確認したところ、gzipと表示されました。
ということは圧縮されたデータをUTF-8にしようとしたために、変な記号がちょろっと出て終了だったんですね。

> WebClient.Headers に Accept-Encoding を gzip,deflate で追加すれば良いかもしれません。
> あるいは DownloadData で受信したデータを MemoryStream でくるみ、GZipStream で読み出すという手もありますが……。
GZipStreamで読み出す方法がうまくいきました。HTMLが綺麗に取得出来ました。

> HTML 全体を取得するなら、Body.Parent.OuterHtml で HTML 要素から取得できます。
> これで取得できる HTML は HTML DOM パーサが解析した結果を HTML に再変換したものですが、今回の場合は生のバイナリが重要です。
> WebBrowser.DocumentStream を取得して Byte 配列にコピーし中身を確認すると、ブラウザが受信したままのバイナリを見ることができます。
ふむふむ。なるほど。
Document.Streamを使えばWebClientのDownloadDataと同じような使い方が出来るのですね。

今のプログラムは別のスレッドでサイトのデータ受信を行っているため、
DownloadData → MemoryStream → GZipStream という流れでHTMLの取得にしたいと思います。

受信したデータが正しく(?)扱えない問題が解決したので、解決済みにしたいと思います。
丁寧な回答と解説、ありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板