投稿者 るきお  (社会人) 投稿日時 2011/3/1 22:28:49
おっしゃるように文字コードが異なると文字化けします。

>文字コードなども設定してみましたがうまく行きません。
今回のように「○○したが、うまくいかない」という場合は、その○○したうまくうごかないプログラムを載せていただくようお願いします。
「○○すればできますよ」という回答と、具体的なプログラムが書いてある回答とでは具体的なプログラムが書いてある回答の方がありがたいことが多いと思いますが、
質問でも同じです。
回答者が太郎さんが困っていることを推理してゼロから回答を組み立てなければいけないか、既に目の前にあるものを直せばいいだけかの違いは大きいです。

さて、本題ですが、文字コードを気にせずに正確なhtmlをダウンロードするにはバイト型の配列としてhtmlを取得します。それにはDownloadDataメソッドを使用します。
そのあと、System.Text.Encodingを使用してそのバイト型の配列を適切な文字コードで翻訳すればよいのですが、この「適切な文字コード」が何かを取得するところが一癖あります。

ひょっとすると、バイト型の配列から文字コードを判別する簡単な方法があるかもしれません。知っている方がいたら教えてください。

とりあえず、htmlのMETAタグに記載されている文字コードはhtmlの上の方にあり半角英数で構成されているタグですので、まずutf-8と仮定して読み込んで、文字コードを確認後utf-8でなければ改めて出コードしなおすという方式をとりました。

プログラムが複雑になったのでこの部分をHtmlDocumentクラスにカプセル化しました。


    
Imports System.Text.RegularExpressions

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click

        Dim url1 As String = "http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=10062"
        Dim url2 As String = "http://homepage1.nifty.com/rucio/main/material/UpDate.htm"

        Dim html1 As New HtmlDocument(url1)
        Dim html2 As New HtmlDocument(url2)

        MsgBox(html1.Title & vbNewLine & html1.EncodeName)
        MsgBox(html2.Title & vbNewLine & html2.EncodeName)

    End Sub
End Class

Public Class HtmlDocument

    Public Source As String 'VB2010ならPublic Propertyと書きたい。 

    Public Sub New(ByVal url As String)
        DownloadHtml(url)
    End Sub

    Public Function DownloadHtml(ByVal url As StringAs String

        Dim bytes() As Byte

        Using client As New Net.WebClient
            bytes = client.DownloadData(url)
        End Using

        'まずutf-8ででコードしてみる 
        Dim utf8 = System.Text.Encoding.UTF8
        Me.Source = utf8.GetString(bytes)

        'utf8じゃなかったら指定された文字コードでデコードしなおす 
        Select Case Me.EncodeName
            Case "UTF-8""UTF8"
            Case Else
                Dim encode = System.Text.Encoding.GetEncoding(Me.EncodeName)
                Me.Source = encode.GetString(bytes)
        End Select

        Return Me.Source

    End Function

    Public ReadOnly Property EncodeName As String
        Get
            Dim pattern As String = "\<meta.*?charset\=(.*?)\"""
            Dim results = ExtractAsMatch(pattern)
            Dim value As String = Nothing

            If results.Count > 0 Then
                For Each result As System.Text.RegularExpressions.Match In results
                    If result.Groups.Count > 0 Then
                        value = result.Groups(1).Value
                        Exit For
                    End If
                Next
            End If

            If value Is Nothing Then
                value = "utf-8"
            End If

            Return value

        End Get
    End Property

    Public ReadOnly Property Title As String
        Get
         
            Dim regop As RegexOptions = RegexOptions.IgnoreCase Or RegexOptions.Singleline
            Dim pattern As String = "<title.*?>(.*?)</title>"
            Dim regex As New Regex(pattern, regop)
            Dim match As Match = regex.Match(Me.Source)

            If match.Success Then
                Return match.Groups(1).Value
            Else
                Return ""
            End If

        End Get
    End Property

    Public Function ExtractAsMatch(ByVal expression As StringAs System.Text.RegularExpressions.MatchCollection

        Dim re As New Regex(expression, RegexOptions.IgnoreCase Or RegexOptions.Multiline)

        Dim results = re.Matches(Me.Source)

        Return results

    End Function

End Class