C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: htmlドキュメントの文字コード自動認識テクニック


(過去ログ 88 を表示中)

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■52591 / inTopicNo.1)  htmlドキュメントの文字コード自動認識テクニック
  
□投稿者/ やんまー (18回)-(2010/08/17(Tue) 02:02:09)

分類:[VB.NET/VB2005 以降] 

いつもお世話になっております><;

htmlドキュメントを取得する方法はネットで検索してもすぐ出てきますが、
文字コードを任意で指定する方法が主で、不明な場合にどうすればいいか・・・なにかいい方法はあるのでしょうか?

よくある例だとこんな感じでしょうか。。
------------------------------
Dim url As String = "http://www.yahoo.co.jp/"
Dim wc As New System.Net.WebClient()
wc.Encoding = System.Text.Encoding.GetEncoding(51932)
Dim sorce As String = wc.DownloadString(url)
wc.Dispose()
------------------------------

実は以前あまりにもいい方法が思いつかなくて
1回UTFで読み込んでから charset を正規表現で読み取ってから、
もう一度読み込み直す、、、

という方法を使っていたのですが、2回も読み込むなんて無駄だし、ほかに何か方法があるのでは??
とおもいご質問させていただきました。

どうぞよろしくお願いします><。
引用返信 編集キー/
■52592 / inTopicNo.2)  Re[1]: htmlドキュメントの文字コード自動認識テクニック
□投稿者/ 魔界の仮面弁士 (1751回)-(2010/08/17(Tue) 10:17:34)
No52591 (やんまー さん) に返信
> なにかいい方法はあるのでしょうか?
判断基準としては、
 (1) HTTP ヘッダから調べる:Content-Type ヘッダの charset
 (2) META タグを読み取る:http-equiv="content-type" な content 属性の charset
 (3) HTML文書内の各要素の charset 属性
 (4) 実際のバイナリから判断。
の 4 つがあります。
XHTML の場合は、XML宣言の Charset を調べるという選択肢も加わります。

優先順位がもっとも高いのは本来 1 ですが、設定ミスなどの理由により、これらの値が
当てにならないケースもあります。(Windows Home Server のリモート アクセス サイトとか)

たとえば、指定された charset と実際の文字コードが一致していないケースを時折見かけますし、
極端な話、(1)≠(2)≠(4) なサーバーもあったりします。
中には、chraset の多重指定が行われているケースさえもありました。
http://forum.mozilla.gr.jp/cbbs.cgi?mode=al2&namber=42106&rev=&KLOG=269


まぁ、そういった物は除外するとして、とりあえず一通りの手順について述べると、
(1) については WebClient/HttpWebResponse に対して .Headers プロパティから
.Headers.Item("Content-Type") を得ることで調査できます。
 Dim url As String = "http://www.yahoo.co.jp/"
 Dim wc As New System.Net.WebClient()
 Dim bin() As Byte = wc.DownloadData(url)
 Console.WriteLine(wc.ResponseHeaders.Item("Content-Type"))

(2) や (3) については、バイナリの内容から判断となります。ただし、時々
<!--
<meta http-equiv="content-type" content="text/html;charset=shift_jis">
-->
<meta http-equiv="content-type" content="text/html;charset=utf-8">
のように指定されているサイトもあるので注意が必要です。


(4) については厄介ですが、これについては
 ・ADODB.Stream で、.Charset = "_autodetect" を利用する。
 ・http://dobon.net/vb/dotnet/string/detectcode.html を利用。
などの手法があります。あるいは、DecoderExceptionFallback 指定で
各種 Encoding を試していき、変換に失敗した物を除外するという方法も。
引用返信 編集キー/
■52593 / inTopicNo.3)  Re[1]: htmlドキュメントの文字コード自動認識テクニック
□投稿者/ aetos (324回)-(2010/08/17(Tue) 10:17:39)
No52591 (やんまー さん) に返信
> htmlドキュメントを取得する方法はネットで検索してもすぐ出てきますが、
> 文字コードを任意で指定する方法が主で、不明な場合にどうすればいいか・・・なにかいい方法はあるのでしょうか?

1:HTTP レスポンスヘッダに Content-Type があれば、それを使います。
2:データに BOM があれば、Unicode と判断します。
3:そうでなければ、US-ASCII と仮定して meta 要素を探します。
  Shift-JIS、UTF-8 をはじめとして、多くの文字コードは 0x7f 以下の値で US-ASCII 互換です。
  http://htmllint.itc.keio.ac.jp/htmllint/explain.html#non-ascii-early
4:それでもわからなければ…えっと、頑張ります。
引用返信 編集キー/
■52610 / inTopicNo.4)  Re[2]: htmlドキュメントの文字コード自動認識テクニック
□投稿者/ やんまー (19回)-(2010/08/18(Wed) 00:37:34)
魔界の仮面弁士 様

ご丁寧にありがとうございます。

wc.ResponseHeaders.Item("Content-Type")

text/html; charset=utf-8
のように取れてきましたので、正規表現でcharset=の右側をとるようにしてみました。
さらに、
(4)のコードを拝借して、Content−Typeがとれなかった場合は使うようにしようと思います。


で、一応サンプルをつくっていろいろ試していたのですが、少し奇妙なことが起こりました。
たまたまなんですが、、、
http://www.tanteifile.com/
でやってみたところ
なぜか
text/html;
しかとれませんでした。

ソースを見ると
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=shift_jis">
となっているのに、です。

こちらはどういった理由で取得できないのでしょうか?


引用返信 編集キー/
■52611 / inTopicNo.5)  Re[2]: htmlドキュメントの文字コード自動認識テクニック
□投稿者/ やんまー (20回)-(2010/08/18(Wed) 00:39:51)
aetos 様

なかなか難しいのですね。

BOMをユニコードの判定に使えるのですね?!

ありがとうございます!
引用返信 編集キー/
■52612 / inTopicNo.6)  Re[3]: htmlドキュメントの文字コード自動認識テクニック
□投稿者/ Hongliang (687回)-(2010/08/18(Wed) 01:21:03)
> http://www.tanteifile.com/
> でやってみたところ
> なぜか
> text/html;
> しかとれませんでした。
>
> ソースを見ると
> <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=shift_jis">
> となっているのに、です。
>
> こちらはどういった理由で取得できないのでしょうか?

Headers プロパティは HTTP ヘッダの内容を取得する物です。meta 要素は HTML レベルの話であって、レイヤが異なります。
Content-Type ヘッダフィールドにおいて charset は別に必須ではないので、そのサーバが付けなかっただけのことでしょう。
魔界の仮面弁士さんが ■52592 で書かれているように、HTTP ヘッダの内容と meta 要素の内容が異なっていたり矛盾していたりというのはよくある話です。
引用返信 編集キー/
■52615 / inTopicNo.7)  Re[3]: htmlドキュメントの文字コード自動認識テクニック
□投稿者/ 魔界の仮面弁士 (1753回)-(2010/08/18(Wed) 11:36:25)
No52610 (やんまー さん) に返信
> なぜか
> text/html;
> しかとれませんでした。
Content-Typeヘッダーに charset 指定が無い場合、それ以外の方法で判定してください。

ただし現実問題として、Content-Type はあまりあてになりません。
(charset 指定が無いのはまだマシな方です)
一部のレンタルサーバーでは、Content-Typeヘッダーの charset を変更できず、
結果として実際とは異なるエンコーディングが指示されているケースがあるためです。

とはいえ HTML 4.01 の仕様では、優先順位は
 1. HTTPにおけるContent-Typeヘッダのcharsetパラメータ
 2. <meta http-equiv="Content-Type" content="text/html; charset=何某">
 3. HTML文書内の各要素のcharset属性
と定義されているので、建前上はもっとも優先するべき項目だったりします。

なお、Content-Type ヘッダーに charset が指定されなかった場合には
.GetEncoding(1252) として扱う事になっていたりもします。
実際のところ、日本語圏で 1252 となることは稀ですけれども。


> ソースを見ると
> <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=shift_jis">
> となっているのに、です。
meta タグは、先述の (2) にあたります。
ResponseHeaders は (1) を取得するためのもので、meta タグとは無関係です。


> (4)のコードを拝借して、Content−Typeがとれなかった場合は使うようにしようと思います。
(4) だけでは正確に判断することはできません。
現実的には、先述の(2)と(4)を組み合わせて使うことになると思います。

たとえばE0 DD E0 EA というバイナリがあった場合、それが Shift_JIS の "珎瑕" なのか、
それとも EUC-JP の "珈琲" なのかは判断がつきません。
http://vsug.jp/tabid/63/forumid/51/threadid/2824/scope/posts/Default.aspx

同様に「UTF-8、Shift_JIS、ISO-8859-1 のいずれにも解釈可能な HTML」文書や
時には「その文字コードでは、本来扱えないバイナリが混入している HTML」さえも
あるので、万能な方法はありません。(IE でさえ、自動判定に時々失敗しますよね)
引用返信 編集キー/
■52637 / inTopicNo.8)  Re[4]: htmlドキュメントの文字コード自動認識テクニック
□投稿者/ やんまー (21回)-(2010/08/18(Wed) 18:49:17)
Hongliang 様

ヘッダーとは違ったのですね、、、

申し訳ありませんでした。

引用返信 編集キー/
■52659 / inTopicNo.9)  Re[4]: htmlドキュメントの文字コード自動認識テクニック
□投稿者/ やんまー (22回)-(2010/08/19(Thu) 10:37:18)
魔界の仮面弁士様

遅くなってすみません!
書き込んだつもりが、うまく送信できていなかったようです;;

(2)のメタタグを調査するとなると

------------------------------
Dim url As String = "http://www.yahoo.co.jp/"
 Dim wc As New System.Net.WebClient()
 Dim bin() As Byte = wc.DownloadData(url)

 'wc.ResponseHeaders.Item("Content-Type") から判定

'判定不能だったら1度読み込む
 Dim sorce As String = wc.DownloadString(url)

 'sourceの・・・
 'metaを調べる
 '判定不能だったら、文字コードを調べる

 wc.Encoding = System.Text.Encoding.GetEncoding( ここに取得した文字コード )

'再び読み直し
 sorce = wc.DownloadString(url)


------------------------------

みたいになるでしょうか・・・

あ、バイト配列で取れてるので文字コードを変換すればよいのですかね?!

バイト型配列を文字列に変換する
http://dobon.net/vb/dotnet/string/getencoding.html

ちょっとやってみます。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -