HTMLソースから画像のURLを取得したい

タグの編集
投稿者 パル36  (中学生) 投稿日時 2011/1/22 22:13:30
こんばんわ。この掲示板の過去ログをみてもなかったので質問させていただきます。

今、WebBrowserで取得したソース(WebBrowser.Document.Body.OuterHtml)から画像のURLを抜き出したいと思っています。
しかし、あるサイトの正規表現を編集して使用しても反応がありません。


Public Sub GetImg()
Dim Soruce As String = WebBrowser.Document.Body.OuterHtml
Dim search As System.Text.RegularExpressions.MatchCollection = System.Text.RegularExpressions.Regex.Matches(Soruce, "<img\s+[^>]*src\s*=\s*(?:(?<quot>[""'])(?<url>.*?)\k<quot>|" + "(?<url>[^\s>]+))[^>]*>(?<text>.*?)</img>", System.Text.RegularExpressions.RegexOptions.IgnoreCase Or System.Text.RegularExpressions.RegexOptions.Singleline)

For Each m As System.Text.RegularExpressions.Match In search 
Console.WriteLine("URL:{0}", m.Groups("url").Value)
Next
End Sub

参考サイトは、http://dobon.net/vb/dotnet/string/regexmatch.htmlです。

リンクタグとイメージタグは全然違うことは承知しています。だけど、いままで正規表現だけは学習していないためかとても頭に入りません。(難しいと感じてしまいます。)

画像タグに対応させるにはどのようにしたらよいのでしょうか。
取得したいのは、URLの部分だけでその他の属性などは必要ではありません。
このような場合は、そこだけを抽出すればいいのですか。それとも、いったん全て抽出してそれから調べるのですか。

サンプルや助言を書いてくださるとうれしいです。手順だけどもかまいません。
今回は正規表現の部分を質問しているのですが、これを作っているときにWebBrowserのデスクトラクタをしたんですが、なぜかできませんでした。


Dim wc As WebBrowser = New WebBrowser
Dim Soruce As String = wc.Document.Body.OuterHtml
(省略)
wc.Dispose()

「オブジェクト参照がオブジェクト インスタンスに設定されていません。」

なぜでしょう?そもそもデストラクタの使い方が間違ってるでしょうか。

今日やっと、初級講座を終了できたのでできるかと思いましたができませんでした。
どうか二つについて宜しくお願いします。
投稿者 YAS  (社会人) 投稿日時 2011/1/22 22:34:16
正規表現ではなく,DOMを検索する方がよいと思います。

Public Class Form1

    Friend WithEvents Webbrowser1 As New WebBrowser

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.Webbrowser1.Dock = DockStyle.Fill
        Me.Controls.Add(Me.Webbrowser1)
        Me.Webbrowser1.GoHome()
    End Sub

    Private Sub Webbrowser1_DocumentCompleted(ByVal sender As Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles Webbrowser1.DocumentCompleted
        Dim Body As HtmlElement = Me.Webbrowser1.Document.Body
        Dim Images As HtmlElementCollection = Body.GetElementsByTagName("img")
        For Each Img As HtmlElement In Images
            Debug.Print(Img.GetAttribute("src"))
        Next
    End Sub

End Class
投稿者 山元山田威厳●  (社会人) 投稿日時 2011/1/23 09:59:40
soruceじゃなくてsourceだよね^^;
投稿者 パル36  (中学生) 投稿日時 2011/1/23 17:35:32
YASさん、山元山田威厳●さん、お返事ありがとうございます。

>正規表現ではなく,DOMを検索する方がよいと思います。
正規表現ではなくてもできるんですか。ありがとうございます。

>soruceじゃなくてsourceだよね^^; 
訂正しておきます。ありがとうございますw

YASさんが提示してくれたコードをやってみたらうまくいきました。
ありがとうございます。

もうひとつですが、CheckListをクリアするには、Clearを使うのですができません。
なぜでしょうか。
ソフトとしては、URLを取得しCheckListにAddしています。
lstFile.Items.Clear()
上をメソッド前に使用しても削除されません。

宜しくお願いします。
投稿者 YAS  (社会人) 投稿日時 2011/1/23 18:01:19
CheckListがCheckedListBoxのことを指しているのなら,CheckedListBox.Items.Clear()でクリアされるはずです。
次のコードを試してみてください。


Public Class Form1

    Friend WithEvents Webbrowser1 As New WebBrowser
    Friend CheckedListBox1 As New CheckedListBox

    Private Sub Form1_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
        Me.Webbrowser1.Dock = DockStyle.Fill
        Me.CheckedListBox1.Size = New Size(400, 300)
        Me.CheckedListBox1.Location = New Point(0, 0)
        Me.Controls.AddRange({Me.Webbrowser1, Me.CheckedListBox1})
        Me.CheckedListBox1.BringToFront()
        Me.Webbrowser1.GoHome()
    End Sub

    Private Sub Webbrowser1_DocumentCompleted(ByVal sender As ObjectByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles Webbrowser1.DocumentCompleted
        Me.CheckedListBox1.Items.Clear()
        Dim Body As HtmlElement = Me.Webbrowser1.Document.Body
        Dim Images As HtmlElementCollection = Body.GetElementsByTagName("img")
        For Each Img As HtmlElement In Images
            Me.CheckedListBox1.Items.Add(Img.GetAttribute("src"))
        Next
    End Sub

End Class
投稿者 パル36  (中学生) 投稿日時 2011/1/23 21:20:01
YASさんありがとうございます。
できました。
(よく見てみたら、クリアを別のチェックリストボックスに命令していました。今思えば、なぜ別のが消えたのかわかりました。w)

何回もすみませんが、取得したURLを拡張子で分岐させたいのですが、どのようにすればできるでしょうか。
拡張子は、CheckListBoxのItemsで複数選択できるようになっています。(GIF,PNG,JPEG,BMP)
この場合は、たくさんネストをしないといけないのでしょうか。でも、そしたら5つも選択していた場合は相当なコードになります。
ほかに方法をお願いします。
投稿者 YAS  (社会人) 投稿日時 2011/1/23 21:33:19
申し訳ありませんが,「取得したURLを拡張子で分岐させたい」の意味がよくわかりません。
拡張子によって処理を分けるために,IF文の繰り返しになるのを避けるには,一般的にはSelect Caseを使うのがよいと思います。
投稿者 パル36  (中学生) 投稿日時 2011/1/23 23:08:43
>「取得したURLを拡張子で分岐させたい」の意味がよくわかりません。
すみません。書き直します。

Checklistboxで選択された拡張子のファイルだけをリストアップするということです。
例えば、gif.bmpの2つが選択されているとします。この場合に、選択されている拡張子のファイルだけをリストアップするということです。

でも、選択されている項目を取得できません。SelectItemsやCheckedItemsを試しましたが型が違って表示できません。

取得した後は、IO.Path.GetExtensionを使います。
したいことは、

If チェックされている項目=GIF Then
 Select Case IO.Path.GetExtension(File)
  Case ".gif"
   CheckListBox.Add(File)
  Case ".png"
'なにもしない 
  Case ".jpg"
'なにもしない 
  Case ".jepg"
'なにもしない 
  Case ".bmp"
'なにもしない 
 End Select
End If

これですが、たくさん選択されているとAndElseやネストをたくさんしないといけないでしょうか?

説明がわかりにくいかもしれませんが、宜しくお願いします。
投稿者 YAS  (社会人) 投稿日時 2011/1/24 00:29:45
選択した拡張子に対応したURLを表示する例です。
注意しなければならないのは,ItemCheckイベントはチェックが変化する前に発生するので,変化したItemについて考慮しなければなりません。
処理が重複していてあまりよい例とはいえませんが,参考にしてください。


Imports System.IO

Public Class Form1

    Friend WithEvents Webbrowser1 As New WebBrowser
    Friend CheckedListBox1 As New CheckedListBox
    Friend WithEvents CheckedListBox2 As New CheckedListBox

    Private Sub Form1_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
        Me.Webbrowser1.Dock = DockStyle.Fill
        Me.CheckedListBox1.Size = New Size(400, 300)
        Me.CheckedListBox1.Location = New Point(0, 0)
        Me.CheckedListBox2.Size = New Size(100, 100)
        Me.CheckedListBox2.Location = New Point(400, 0)
        Me.Controls.AddRange({Me.Webbrowser1, Me.CheckedListBox1, Me.CheckedListBox2})
        Me.CheckedListBox1.BringToFront()
        Me.CheckedListBox2.BringToFront()
        Me.Webbrowser1.GoHome()
    End Sub

    Private Sub Webbrowser1_DocumentCompleted(ByVal sender As ObjectByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles Webbrowser1.DocumentCompleted
        Me.CheckedListBox1.Items.Clear()
        Me.CheckedListBox2.Items.Clear()
        Dim Body As HtmlElement = Me.Webbrowser1.Document.Body
        Dim Images As HtmlElementCollection = Body.GetElementsByTagName("img")
        For Each Img As HtmlElement In Images
            Dim src As String = Img.GetAttribute("src")
            Dim ext As String = Path.GetExtension(src)
            Me.CheckedListBox1.Items.Add(src)
            If Not Me.CheckedListBox2.Items.Contains(ext) Then
                Me.CheckedListBox2.Items.Add(ext, True)
            End If
        Next
    End Sub

    Private Sub CheckedListBox2_ItemCheck(ByVal sender As ObjectByVal e As System.Windows.Forms.ItemCheckEventArgs) Handles CheckedListBox2.ItemCheck
        Me.CheckedListBox1.Items.Clear()
        Dim CheckedItems As New ArrayList
        CheckedItems.AddRange(Me.CheckedListBox2.CheckedItems)
        Dim CurrentItem As Object = Me.CheckedListBox2.Items(e.Index)
        If e.NewValue Then
            CheckedItems.Add(CurrentItem)
        Else
            CheckedItems.Remove(CurrentItem)
        End If
        Dim Body As HtmlElement = Me.Webbrowser1.Document.Body
        Dim Images As HtmlElementCollection = Body.GetElementsByTagName("img")
        For Each Img As HtmlElement In Images
            Dim src As String = Img.GetAttribute("src")
            Dim ext As String = Path.GetExtension(src)
            If CheckedItems.Contains(ext) Then
                Me.CheckedListBox1.Items.Add(src)
            End If
        Next
    End Sub

End Class
投稿者 パル36  (中学生) 投稿日時 2011/1/24 17:21:54
YASさん、たくさんの回答ありがとうございます。

>処理が重複していてあまりよい例とはいえませんが,参考にしてください。
いえいえ、参考どころか採用させていただきます。このような考え方が思い浮かびませんでした。

この質問に回答してくれました方に、とても感謝します。
ありがとうございました。

解決策は、YASさんの(自分では)すばらしいサンプルを使うことでした。
ありがとうございます。