WebページのTITLEタグの中身の文字列を抜き出したい。

タグの編集
投稿者 太郎  (社会人) 投稿日時 2011/2/22 14:40:40
この掲示板に題名と同じような質問があったので参照してみたのですが、Webbrowserコントロールを使っており、TITLE内のテキストを抜き出そうとしたところ、物凄く時間がかかってしまいました。

Webbrowserコントロール以外の方法でTITLE内のテキストを抜き出したいのですが、方法はないでしょうか?

お願いします。

投稿者 るきお  (社会人) 投稿日時 2011/2/22 17:19:30
<TITLE>~</TITLE>の ~ の部分を抜き出すには、
Net.WebClient.DownloadStringでhtmlを取得して、RegExでTitleを抜き出せばできます。
後で具体的なサンプルを紹介します。
投稿者 るきお  (社会人) 投稿日時 2011/2/22 22:18:08
titleタグの内容を抜き出すサンプルです。

この例ではインターネットのサイトにアクセスしてhtmlを取得していますが、
html取得までの部分はローカルのドキュメントから取得してもよいし、ほかの方法で生成してもよいです。

Dim internet As New Net.WebClient
'プロキシーを通してWebにアクセスする場合は以下の2行を復活させプロキシーのアドレスとユーザー名・パスワードを指定してください。 
'internet.Proxy = New Net.WebProxy("198.100.99.99", 8080) 
'internet.Credentials = New Net.NetworkCredential("rucio", "mypass") 

Dim html As String = internet.DownloadString("http://www.nifty.com/")
internet.Dispose()
Dim regop As System.Text.RegularExpressions.RegexOptions = System.Text.RegularExpressions.RegexOptions.IgnoreCase Or System.Text.RegularExpressions.RegexOptions.Singleline
Dim pattern As String = "<title.*?>(.*?)</title>"
Dim regex As New System.Text.RegularExpressions.Regex(pattern, regop)
Dim match As System.Text.RegularExpressions.Match = regex.Match(html)
Dim title As String
If match.Success Then
    title = match.Groups(1).Value
Else
    title = ""
End If
MsgBox(title)


一般的でない書き方でtitleタグが埋め込まれている場合は、抽出条件に合致せず取得できない可能性はありますが、ほとんどのサイトでこの方法で取得できると思います。

この手法はタイトルだけ取得するのにWebページ全体を読み込んでいる点で効率はあまりよくありません。titleタグはWebページのかなり上のほうにあるはずなので、実際にはWebページを少しだけ読めばtitleタグを探せるはずです。
StreamReaderを使ってhtmlを少しずつ読んでいけば効率化は図れますが、プログラムは複雑になるでしょう。htmlをWebから取得する場合はSystem.Net.WebClient.OpenReadメソッドでStreamを取得できます。
投稿者 太郎  (社会人) 投稿日時 2011/2/23 20:01:47
るきおさんありがとうございました。
大分早くなりました。
投稿者 太郎  (社会人) 投稿日時 2011/2/25 13:23:21
すみません。
るきおさんのやり方でやると時々文字化けを起こしてしまいます。
文字コードなども設定してみましたがうまく行きません。

もしよかったらアドバイスお願いします。
投稿者 るきお  (社会人) 投稿日時 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
投稿者 るきお  (社会人) 投稿日時 2011/3/1 22:32:00
捕捉です。

前にも書きましたが、タグを抜き出す条件判断がとりあえずのものなので、
私が想定した書き方でタグを書いていないサイトがあれば正しいhtmlでもタイトルを抜き出せないことがあります。
この条件は正規表現で書いている部分ですので、必要であれば適宜変更してください。

また、Webブラウザはhtmlが正しくなくても表示してくれる場合が多々ありますが、私のプログラムは少なくともTitleタグと文字コードのMetaタグ近辺が正しく書かれていないとタイトルが抜き出せません。

このあたりをちゃんとやるのはかなり大変です。