【VBA】ログイン画面があるサイトをスクレイピングする

先日、FC2ブログからWordPressへの移行作業を行ったのですが、この時に画像を大量にダウンロードしなければいけなかったため、スクレイピングをする必要が出てきました。

しかし、厄介なことにログインをしなければ目的のページまでたどり着けないようになっているため、単純にURL直打ちでダウンロードすることができませんでした。

認証のためのリクエストを送る方法とかを調べるのが面倒だったので、Chromeをseleniumで動かして、画面のボタン押下で認証を突破していく感じにしました。

その時に実施した内容を備忘録として記載したいと思います。

実現したかったこと

今回やりたかったことは以下になります。

  1. ログイン画面を開く
  2. ログイン画面にユーザー名とパスワードを入力してログインボタンを押す
  3. ログイン後の画面から画像一覧の画面を開く
  4. 画像一覧の画面にある全ての画像をダウンロードする

上記を実現するために

  1. seleniumをインストールする
  2. VBAからseleniumを操作する

ということを実施いたしました。詳細な手順を記載していきたいと思います。

seleniumをインストールする

VBAからはIEはデフォルトで操作することが出来るのですが、もはやIEはサポートも終了しており使う気になりません

今後のことを考えると、VBAでChromeは操作出来るようにしておいたほうが良いのでseleniumをインストールすることにしました。

seleniumをダウンロードする

以下のページにアクセスし、インストーラーを入手します。

https://github.com/florentbr/SeleniumBasic/releases

seleniumをダウンロードする

このブログの執筆時点では最新バージョンは「v2.0.9.0」になっているので、このバージョンをダウンロードしました。

古いバージョンだと、最新のChromeに対応できないこともあるので、とりあえず一番新しいのを入手しておくのが無難だと思います。

ダウンロードが完了したら、exeファイルを起動してseleniumをインストールします。

自分のChromeバージョンにあったChromeDriverを入手する

Chromeのバージョンを確認する方法

Chromeのメニュー(ケバブボタン)から「ヘルプ→GoogleChrome」についてを選択します。

するとChromeのバージョンが表示されます。

次に、そのバージョンに対応したChromeDriverを以下のサイトからダウンロードします。

http://chromedriver.chromium.org/downloads

↓win32という表記が気になったんですが、64bit版でもwin32でOKみたいです

ChromeDriverをダウンロードする

ダウンロードしたChromeDriverをseleniumをインストールしたフォルダに配置します。

デフォルト設定でインストールした場合、C:\Program Files\SeleniumBasicになるかなと思います。

これでseleniumの準備は完了です。

参考にしたサイト

※seleniumのインストールについては、以下のサイトを参考にさせてもらいました。

https://excel-ubara.com/excelvba4/EXCEL_VBA_401.html


VBAでログインと画像ダウンロードを行う

次にVBAのプロジェクト(VBE)を開き、参照設定にSelenium Type Libraryを追加します。

Selenium Type Library

まずはChromeを立ち上げて、ログインを実施するところを実装します。

下調べとして、ログイン画面のHTMLから入力欄やログイン画面のIDを調べます。

今回自分が対象としているサイトでは、ユーザ名を入れる欄が「ID」、パスワードを入れる欄が「pass」というIDになっていました。

そこに値を入れるコードが以下のようになります。

Sub sample()
    Dim Driver As New Selenium.WebDriver
    Dim myBy As New By
    'ログインページを開く
    Driver.Start "chrome", "https://admin.blog.fc2.com/control.php?mode=control&process=backup"
    Driver.Get "/"
    
    With Driver
        'ユーザ名とパスワードを入れてログインボタンを押す
        .FindElementById("id").SendKeys "xxxxxxxx@yahoo.co.jp"
        .FindElementById("pass").SendKeys "password"
        .FindElementByName("image").Click
    End With
    
    Driver.Close
    Set Driver = Nothing
End Sub

Driver.Start “chrome”の行でサイトのルートを指定し、Driver.Get “/”でそのサイトを開いています。

.FindElementById(“id”)、FindElementById(“pass”)の行でユーザ名とパスワードを入力しています。

今回ログインボタンにIDがふられておらず、代わりにimageという名前がついていたので、FindElementByName(“image”)で要素を取得してクリックしています。

これでログインをすることができました。

次に画像一覧があるページを開いて、画像をダウンロードします。

Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As Long)

Public Declare PtrSafe Function URLDownloadToFile Lib "urlmon" _
    Alias "URLDownloadToFileA" (ByVal pCaller As Long, _
    ByVal szURL As String, ByVal szFileName As String, _
    ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long

Sub sample()
    Dim Driver As New Selenium.WebDriver
    Dim myBy As New By
    Driver.Start "chrome", "https://admin.blog.fc2.com/control.php?mode=control&process=backup"
    Driver.Get "/"
    
    With Driver
        .FindElementById("id").SendKeys "xxxxxxxx@yahoo.co.jp"
        .FindElementById("pass").SendKeys "password"
        .FindElementByName("image").Click
        .Get "/control.php?mode=control&process=backup"
        
        '画像一覧のページを開く
        .Get "/control.php?mode=control&process=backup&type=file&ext=pict&page=1"
        'タグがimgの要素を全て取得する
        Set images = .FindElements(myBy.Tag("img"))
        For Each Image In images
            '画像のURLを取得
            src = Image.Attribute("src")
            'URLからファイル名を取得   
            pos = InStrRev(src, "/")
            Filename = Mid(src, pos + 1)
            '画像ファイルを保存する
            Call GetImageFile(CStr(src), "C:\image\" & Filename)
        Next
    End With
    
    Sleep 10000
    Driver.Close
    Set Driver = Nothing
End Sub

Sub GetImageFile(ImgName As String, SaveName As String)
    Dim SaveFileName As String, DownloadFile As String, Ret As Long
    If ImgName = "" Then Exit Sub
    SaveFileName = SaveName
    DownloadFile = ImgName
    Ret = URLDownloadToFile(0, DownloadFile, SaveFileName, 0, 0)
    If Ret <> 0 Then
        MsgBox "エラーが発生しました"
    End If
End Sub

FindElementsメソッドを使用すると、そのページに有る全ての要素を配列で取得できるので、これをforEachで回して全ファイルを取得しました。

画像のダウンロードには、URLDownloadToFileを使用します。

これで無事に画像を全てダウンロードすることができました。

今回の方法ですと、「ログイン画面に値を入力してログイン→ページを開く」という人間が実施する動作と同じことをやっているため、認証やセッションの維持をブラウザにおまかせできるというメリットがあります。

画像認証などがある場合以外であれば、ほぼすべての画面をこの方法でスクレイピングすることができそうです。

(VBAだとバッチ化が難しいので、定期的に取得だと面倒ですが)


コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)