Excel VBAからIEを操作する

はじめに

何番煎じかわかりませんが,ExcelからIE操作をトライしました.

モチベーションは以下の通りです. * VBAの練習 * 自然言語処理の題材として,スクレイピングをやってみたい

自然言語処理のイメージとしては,SNSの情報を吸いだしてデマの検証をするとか,株価の予想をするとか,そういったものを想像しています.なお,私のAI系の知識はcourseraの機械学習のコースを修了した程度です.要するに,得た知識を使ってみたいというのがモチベーションですね.

IEの起動

IEを起動してそのインスタンスを取得するのは簡単で,以下の1行で出来ます.

Set ie = CreateObject("InternetExplorer.Application")

これを用いたIEの取得及び表示設定の初期化を行う以下の関数を作りました.

'IEオブジェクトを取得して初期化する
Private Function init_ie_obj() As Object
    Dim ie As Object
    Set ie = CreateObject("InternetExplorer.Application")
    With ie 'ieの表示設定
      .AddressBar = False'アドレスバー非表示
      .MenuBar = False'メニューバー非表示
      .StatusBar = False'ステータスバー非表示
      .Toolbar = False'ツールバー非表示[f:id:kshige00:20200811031514p:plain]
      .Visible = True'画面表示を有効にする
    End With
    Set init_ie_obj = ie'取得したieオブジェクトを戻り値として返す
End Function

IEオブジェクトからのデータの入出力方法

取得したIEオブジェクトからアクセス先のwebページにデータを入力する(ボタンクリック,テキスト入力など)もしくは読み出す(テキスト,画像など)ためには,アクセス先のwebページのデータ構造を把握する必要があります. これは,IE上で右クリック→ソースの表示をクリックすると見ることができます.

google翻訳でやってみると以下のような画面になり,画面下部にデータ構造が表示されます.

f:id:kshige00:20200811031514p:plain この画面上で,欲しい情報を持つ要素を右クリック→要素の検査をクリックすると,その要素に対応するコードがハイライトされます. 翻訳したい英文を入力するテキストボックスについて行うと,以下の画面となります.

f:id:kshige00:20200811031510p:plain

英文を入力するテキストボックスのクラス名は"orig tlid-source-text-input goog-textarea"で,idは"source"であることが分かりました.

取得したい要素のクラス名もしくはidが分かれば,以下のコードでその要素のオブジェクトを取得することができます.

idを使う場合:

Set ElementObj = ie.document.getElementById("id name")

クラス名を使う場合:

Set ElementObj = ie.document.getElementsByClassName("class name")(0)

クラス名を使う場合は文末に(0)が付きます.これは,getElementsByClassNameは"class name"をクラス名に含む要素を全て取得して配列風に返すメソッドだからです.目的の要素だけを取り出すためには,配列の1番目の要素を取得するという意味で(0)をつけてやる必要があります.なお,"class name"に該当する要素が複数個ある場合は,欲しい要素が該当する番号を設定すればよいです.

idを用いる場合はこのような番号指定の必要はありません.これは,idはdocumentオブジェクト内で固有であり,要素を一意に指定できるためです.idが分かる場合は,idを用いて要素にアクセスするのが便利だと言えます.

要素のオブジェクトを取得出来たら,VBAのエディター上のローカルウインドウでオブジェクト内のデータを見ることができます. オブジェクトのメンバである.innerTextや.textContentを読み書きすることで,テキストデータの入出力が可能です. また,.clickメソッドを使うことで,対象の要素(ボタンなど)をクリックすることができます.

参考サイト

google翻訳の自動化

以上の情報を使って,google翻訳の自動化ソフトを作ってみました. f:id:kshige00:20200811031506p:plain 1列目の英文を1つずつgoogle翻訳に投げて,2列目に結果を入れていくというものです.

全コードは以下になります.

'IEオブジェクトを取得して初期化する
Private Function init_ie_obj() As Object
    Dim ie As Object
    Set ie = CreateObject("InternetExplorer.Application")
    With ie 'ieの表示設定
      .AddressBar = False 'アドレスバー非表示
      .MenuBar = False 'メニューバー非表示
      .StatusBar = False 'ステータスバー非表示
      .Toolbar = False 'ツールバー非表示
      .Visible = True '画面表示を有効にする
    End With
    Set init_ie_obj = ie '取得したieオブジェクトを戻り値として返す
End Function

'ieがビジー状態じゃなくなるまで待つ
Private Sub wait_ie_ready(ByRef ie As Object)
    Const READYSTATE_COMPLETE = 4
    Do While ie.Busy = True Or ie.ReadyState <> READYSTATE_COMPLETE
    DoEvents
    Loop
End Sub

'引数のテキストをgoogle翻訳する
Private Function GoogleTranslate(ByVal text As String, ByRef ie As Object)
    Dim url As String
    Dim ElemObj As Object
    Dim try_cnt
    Dim try_cnt_max
    try_cnt_max = 10

    'ieがgoogle翻訳を開いていない場合,google翻訳にアクセスする
    url = "https://translate.google.co.jp/?hl=ja"
    If InStr(ie.LocationURL, url) = 0 Then
        ie.Navigate url
    End If
    
    wait_ie_ready ie 'ieがビジー状態の間待機

    '翻訳する文章を入力欄に入力
    Set ElemObj = ie.document.getElementById("source")
    ElemObj.innerText = text
    
    wait_ie_ready ie 'ieがビジー状態の間待機
    
    GoogleTranslate = "error"
    try_cnt = 0
    Do While try_cnt < try_cnt_max
        Application.Wait Now() + TimeValue("00:00:01")
        On Error Resume Next
        Set ElemObj = ie.document.getElementsByClassName("result-shield-container tlid-copy-target")(0)
        '翻訳結果を取得
        GoogleTranslate = ElemObj.innerText
        On Error GoTo 0
        If GoogleTranslate = "error" Then
            try_cnt = try_cnt + 1
        Else
            Exit Do
        End If
    Loop
End Function

Sub sample()
    Dim wb
    Dim ws
    Dim str_en As String
    Dim str_jp As String
    Set wb = ThisWorkbook
    Set ws = wb.Worksheets("Sheet1")
    Dim ie As Object
    Dim cnt
    
    'IEを起動
    Set ie = init_ie_obj()
    
    '1列目を走査して,データがある限り翻訳を行う.結果は2列目に書き込む.
    cnt = 0
    While (ws.Cells(cnt + 6, 1)) <> ""
        empty_cnt = 0
        Application.Goto Cells(cnt + 5, 1), True
        If ws.Cells(cnt + 6, 2).text = "" Or ws.Cells(cnt + 6, 2).text = "error" Then
            str_en = ws.Cells(cnt + 6, 1).text
            str_jp = GoogleTranslate(str_en, ie)
            ws.Cells(cnt + 6, 2) = str_jp
        End If
        cnt = cnt + 1
    Wend
    
    'IEを終了
    ie.Quit
End Sub

Twitterスクレイピング

いよいよスクレイピング!ということで,同様のやり方でTwitterスクレイピングツールを作りました.作った直後は動いていたのですが(5月),その後IEでのTwitter閲覧のサポートが打ち切られてしまったらしく,IEからTwitterを見ることは出来なくなってしまいました...(2020/8/11現在)

chromeなどを使ったやり方に切り替えていく必要があるようです. これはSeleniumなるものを使えばできるようです.そのうちトライしようと思います.

まとめ

VBAからのIE操作にトライし,その基本的な方法をまとめました.IEの起動や更新方法などについては解説しているサイトが多く,すんなり出来たのですが,抽出したい要素のオブジェクトを取得したり,その内部のデータを読み書きする方法については結構嵌まりました(私のweb関係の知識不足のせい).苦労した点について多少詳しく解説したつもりです.何かの役に立ちましたら幸いです.