« 2015年1月 | トップページ | 2015年3月 »

2015年2月

2015年2月20日 (金)

VB WebBrowser HTML取得時間 IEバージョン差比較

半年以上前にVisualBasicでWebBrowserクラスを用いてWebページから情報を取得するプログラムをいくつか制作していました。同じページをInternetExplorer(以降IE)とVBフォーム内のWebBrowser両方で表示させ見比べながら,どこのボタンを押すのかなどを探りつつ作業を進めていくのですが,何故だが複数の特定ページでWebBrowser側の表示や挙動がおかしい。結局,原因が分からないままそのプログラムは後で検証しようと棚上げにしていました。

その後,偶然ネット徘徊の情報でWebBrowserは内部的にはIEが動作しており,しかもバージョンがかなり古い「IE7」であるとのことを知り,合点がいくと納得しました。該当のWebサイトは昨年4月のWindowsXPサポート終了に合わせてIEのサポートがIE8以降に変更されていました。WebBrowserのIEバージョンを変更して近々棚上げプログラムの制作再開を予定しています。

で,1つ疑問が湧きました。「IEのバージョンが新しい方が高速なはずだ!(根拠不明)」。ならばバージョンの違いでHTMLを読み込む速度がどの程度異なるのか是非知りたい,と。

と言うことで早速,前回の「VB HTML取得時間比較 WebClient,WebBrowser,IE」のプログラムコードをほぼそのまま使用し検証してみました。

前回は文字羅列のHTMLで100KByteと10MBteyのファイルを使用しました。半角の英文字(A~Z)を300桁×容量に合う行数としていました。今回は更に桁数が100桁,200桁のものも準備しました。
また,例えば10MBのファイルだと300桁×34997行とかになりますが現実的にそんなHTMLファイルは存在しないでしょうから,ごく普通の,HTMLが10KB程度に写真3枚100KB程度のファイルも準備し,計7種類のファイルを4種の方法でHTML取得し時間を比較してみました。

WebBrowseのIEバージョンは最新の「IE11」とサポート外となりつつある「IE7」を比較しています。

  VisualBasic HTMLファイル取得時間比較
項目 取得回数 平均時間[ms] WB IE7比
①HTML 100KB 半角英文字100桁×1004行
 IE11 22  789   
 WB IE11 22  221  1.1倍 
 WB IE7 28  202   
 WC 22  22   
②HTML 100KB 半角英文字200桁×506行
 IE11 22  717   
 WB IE11 22  199  1.1倍 
 WB IE7 28  184   
 WC 22  22   
③HTML 100KB 半角英文字300桁×338行
 IE11 20  727   
 WB IE11 20  191  1.1倍 
 WB IE7 24  181   
 WC 20  21   
④HTML 10MB 半角英文字100桁×102804行
 IE11 23  6058   
 WB IE11 21  11450  2.0倍 
 WB IE7 28  5644   
 WC 24  70   
⑤HTML 10MB 半角英文字200桁×47393行
 IE11 22  8505   
 WB IE11 21  8082  2.2倍 
 WB IE7 25  3630   
 WC 22  67   
⑥HTML 10MB 半角英文字300桁×34997行
 IE11 21  7504   
 WB IE11 21  7365  2.2倍 
 WB IE7 20  3317   
 WC 21  69   
⑦HTML 14.4KB + 画像3枚計141.3KB
 IE11 24  639   
 WB IE11 24  181  1.0倍 
 WB IE7 21  186   
 WC 24  22   
 WB = WebBrowser, WC = WebClient

結果として,
自分の見当とは逆にWebBrowserでは最新のIE11よりもIE7の方が高速でした。但し,一般的なHTML容量と言える100KB以下ではほとんど差がありませんでした。また,JavaScriptが付加されている場合などは結果が変わるかも知れません。

なお,WebBrowse(IE11)とIE11オブジェクトではHTMLのファイル容量や桁数,行数で結果が逆転しており優劣は判断出来ませんでした。

WebBrowseのIEバージョンの切り替えには下記サイトを参考にさせて頂きました。
C# WebBrowserのレンダリングモード
上記のC#のコードをVBに変換し活用しました。

WebBrowseのIEバージョン切り替え VisualBasicソースコード
※レジストリを操作しますので使用は自己責任でお願いします。
-----------------------------------------------------------
Imports System.Runtime.Serialization

Public Class Form1

Dim FEATURE_BROWSER_EMULATION As String = _
"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION"
Dim FEATURE_DOCUMENT_COMPATIBLE_MODE As String = _
"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_DOCUMENT_COMPATIBLE_MODE"

Dim userAgent As Integer = 11001 'IE11
Dim renderingMode As Integer = 110000 'IE11

Dim exeName As String = "WindowsApplication1.exe" 'デバッグ時は.vshost.exeにしておく
'Dim exeName As String = "WindowsApplication1.vshost.exe"


Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

Dim regkey1 As Microsoft.Win32.RegistryKey = _
Microsoft.Win32.Registry.CurrentUser.CreateSubKey(FEATURE_BROWSER_EMULATION)
Dim regkey2 As Microsoft.Win32.RegistryKey = _
Microsoft.Win32.Registry.CurrentUser.CreateSubKey(FEATURE_DOCUMENT_COMPATIBLE_MODE)

'userAgent = 7000 'IE7
'renderingMode = 70000 'IE7

regkey1.SetValue(exeName, userAgent, Microsoft.Win32.RegistryValueKind.DWord)
regkey2.SetValue(exeName, renderingMode, Microsoft.Win32.RegistryValueKind.DWord)

regkey1.Close()
regkey2.Close()

End Sub

End Class

| | コメント (0) | トラックバック (0)

2015年2月15日 (日)

VB HTML取得時間比較 WebClient,WebBrowser,IE

いまや企業のみならず
個人においてもビックデータな時代
ではないでしょうか?

その気さえあれば個人でもネットにあふれる情報を収集,分析することで実りあるアウトプットを期待出来ると思います。

例えば,「Yahoo!検索(リアルタイム)」ではTwitterなどの投稿をワード検索出来,時間ごとの件数を表示してくれますが特定ワードの検索結果を一定間隔で収集しデータベースに溜め込み時間帯などの独自の切り口で分析するなどアイディアは沢山あると思います。

その意味で「WebページからHTMLデータを取得する」ことが入り口の作業として重要になってきます。

HTMLのデータ収集はプログラミングで実現出来ますが,例えばVisualBasic(VB)の場合だと,いくつかの方法(プログラムコード)があります。

主に
1)WebClientクラス を使用
2)WebBrowserクラス を使用
3)InternetExplorer(IE)オブジェクト を使用

それぞれ長所短所があります。
WebClient → 簡単で高速,但しページ上のボタンが押せないなど
WebBrowser → ブラウザーの機能を有しほとんどのことが出来る
IEオブジェクト → 面倒で低速,但しVBAなどでポピュラー

VBの場合,WebClientかWebBrowserかどちらかの選択で,ボタンを押す必要がある,セッションを維持する必要などの場合はWebBrowserになります。

その前提で使い分けてプログラミングしている訳ですが,ふと「WebClientが高速」って思ってたけど本当に高速なの?高速だとしてどのくらい高速なの? と疑問が湧いてきます。そう思い始めると気になってしょうがありません。

と言うことで実験してみました。

実験前にWebBrowserで注意点があります。
WebBrowserも内部的にIEが動作しているそうですが,標準で「IE7」のバージョンに設定されます。IE7はWindowsXP以前のバージョンですのでWebサイトによっては対応していません。また,バージョンが上がるほど高速になるなどの利点もありますので予め適切なバージョンを強制設定しておく必要があります。今回は下記のサイトを参考に最新の「IE11」に設定してあります。
※多分,IE11そのものがインストールされている必要があります。
WebBrowser コントロールで使われている Internet Explorerを最新のバージョンに変更する
C# WebBrowserのレンダリングモード
WebBrowserコントロールのIEバージョン

実験方法
1)中身が単なる文字羅列の100KByteと10MByteの
 HTMLファイルをローカルフォルダー(例えばDドライブ)
 に用意します。
2)WebClient,WebBrowser,IEオブジェクトのそれぞれで
 HTMLを読み込みその時間を計測します。
 プログラムコードは下記参照。
3)計測値の10回の平均を算出します。

当初,連続してページを読み込みましたが100KByteファイルで確認中に段々時間が早くなっていく現象がありました。計測前にIEの一時ファイルは削除していますがどこかの経路でキャッシュが働いているかも知れません。そのため面倒でしたが1回1回プログラムを終了,起動させながらデータを取得しました。

なお,VisualStudioのデバックモードでプログラムを実行しました。
パソコンはCeleron B840+256GB SSDのノートパソコンです。

計測結果
クラス/obj    サイズ   結果   WC比  WB比
WebClient(WC)  100KB   25ms
WebClient(WC)   10MB   67ms
WebBrowser(WB) 100KB  156ms  6.4倍
WebBrowser(WB)  10MB 1169ms 17.4倍
IE             100KB  423ms 16.9倍 2.7倍
IE             100KB 6895ms  102倍 5.8倍

結果として,WebClientがダントツに高速でした。
ただ,ローカルドライブのファイルをアクセスしており,Webからの場合,TCP/IP通信時間などのゲタが足されて幾分相殺されると思います。
(実際の時間差は少ないかも知れない)

逆にローカルファイルだったことでそれぞれの方法の時間差を正確に把握出来たとも言えますのでWebClientとWebBrowserをきっちり使い分けてプログラミングしていく必要性を改めて認識出来ました。

検証に使用したVisualBasicのソースコード
-----------------------------------------------------------
Imports System.IO
Imports System.Timers

'参照
'Microsoft.msHtml
'Microsoft Internet Controls

Public Class Form1
Private myUrl As String
'ストップウオッチ
Private sw As New System.Diagnostics.Stopwatch()
'IE
Private WithEvents IE As SHDocVw.InternetExplorer

Private Sub Form1_Load(sender As Object, e As EventArgs) _
                                        Handles Me.Load
myUrl = "D:\Work\check_100KB.html"
'myUrl = "D:\Work\check_10MB.html"
End Sub

'IEオブジェクトでページを開く
Private Sub Button1_Click(sender As Object, e As EventArgs) _
                                     Handles Button1.Click
delIeCache()
If Not (IE Is Nothing) Then
IE.Quit()
IE = Nothing
End If
sw.Start()
IE = New SHDocVw.InternetExplorer
IE.Visible = False
sw.Start()
IE.Navigate2(myUrl)
End Sub

'IEオブジェクトのドキュメントコンパレート
Private Sub IE_DocComplete(pDisp As Object, ByRef URL As Object) _
              Handles IE.DocumentComplete
If Not TypeName(pDisp) = "IWebBrowser2" Or _
        URL.ToString myUrl Then Return
Invoke(New SHDocVw.DWebBrowserEvents2_DocumentCompleteEventHandler(AddressOf myDocComplete), pDisp, URL)
End Sub

'IEオブジェクトのドキュメントコンパレート
Private Sub myDocComplete(ByVal pDisp As Object, ByRef URL As Object)
Dim ieDoc As mshtml.HTMLDocument = _
CType(IE.Document, mshtml.HTMLDocument)
Dim html As String = ieDoc.body.innerHTML
MRComObject(ieDoc)
sw.Stop()
System.Diagnostics.Debug.WriteLine("IE " & sw.ElapsedMilliseconds)
sw.Reset()
End Sub

'COMオブジェクトの開放
Public Shared Sub MRComObject(Of T As Class) _
(ByRef objCom As T, Optional ByVal force As Boolean = False)
If objCom Is Nothing Then
Return
End If
Try
If System.Runtime.InteropServices.Marshal.IsComObject(objCom) Then
If force Then
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(objCom)
Else
Dim count As Integer = _
System.Runtime.InteropServices.Marshal.ReleaseComObject(objCom)
If count 0 Then
Debug.Print(count.ToString())
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(objCom)
End If
End If
End If
Finally
objCom = Nothing
End Try
End Sub

'WebBrowserでページを開く
Private Sub Button2_Click(sender As Object, e As EventArgs) _
                                     Handles Button2.Click
delIeCache()
sw.Start()
WebBrowser1.ScriptErrorsSuppressed = True
WebBrowser1.Visible = False
WebBrowser1.Navigate(myUrl)
End Sub

'WebBrowserのドキュメントコンパレート
Private Sub WebBrowser1_DocumentCompleted(ByVal sender As System.Object,
ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) _
                         Handles WebBrowser1.DocumentCompleted
If Not TypeName(sender) = "WebBrowser" Then Exit Sub
If e.Url DirectCast(sender, WebBrowser).Url Then Exit Sub
Dim html As String = WebBrowser1.Document.Body.InnerHtml
sw.Stop()
System.Diagnostics.Debug.WriteLine("WB " & sw.ElapsedMilliseconds)
sw.Reset()
End Sub

'WebClient.DownloadStringでHTML取得
Private Sub Button3_Click(sender As Object, e As EventArgs) _
                                        Handles Button3.Click
delIeCache()
sw.Start()
Dim wc As New System.Net.WebClient()
wc.Encoding = System.Text.Encoding.UTF8
Dim HTML As String = wc.DownloadString(myUrl)
wc.Dispose()
sw.Stop()
System.Diagnostics.Debug.WriteLine("WC " & sw.ElapsedMilliseconds)
sw.Reset()
End Sub

'IEの一時ファイル削除 本当に削除されているかは未確認…
Sub delIeCache()
Dim D As String
D = System.Environment.GetFolderPath(Environment.SpecialFolder.InternetCache)
Dim F() As String
Try
F = Directory.GetFiles(D, "*", SearchOption.AllDirectories)
For I As Integer = 0 To (F.Length - 1)
File.Delete(F(I))
Next
Catch ex As Exception
End Try
End Sub

'フォームを閉じる時の処理
Private Sub Form1_FormClosed(sender As Object, _
                           e As FormClosedEventArgs) _
                                Handles Me.FormClosed
If Not (IE Is Nothing) Then
IE.Quit()
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(IE)
IE = Nothing
End If
End Sub

Private Sub Button4_Click(sender As Object, e As EventArgs) _
                                          Handles Button4.Click
Application.Exit()
End Sub
End Class

| | コメント (0) | トラックバック (0)

« 2015年1月 | トップページ | 2015年3月 »