selenium のドライバを自動でダウンロードする 【Python】

Python

selenium のドライバをダウンロードする Python のスクリプトについてまとめておきます。

以下の環境で動作確認をしています。
環境:
・ Windows パソコン、Microsoft Edge ブラウザ
・ Python 3、requests、BeautifulSoup のインストール済み

背景 ~ ドライバをダウンロードする

日頃、Python を使って、ネットやパソコンの作業の自動化を進めています。

selenium とブラウザ用のドライバの2つを設定すると、Python を使って Webサイト上での文字入力や画面操作などを自動化できます。

ところが、Windows パソコンで selenium を使おうとすると、しばしば、スクリプトが動かなくなることがあります。
Microsoft Edge のブラウザは自動でアップデートしていきます。時間が経つとドライバのバージョンが合わなくなり、いつかは動かなくなってしまいます。
ドライバには自動更新の機能もあるようですが、バージョンや環境の制約(?)があるようで、私の環境では動きません。

手作業であれば、公式サイトから最新のドライバをダウンロードして動かすことは可能です。
であれば、Python のスクリプトを素朴に作ってしまったほうが話が早そうです。

ということで、ドライバをダウンロードする Python のスクリプトをまとめ、公開しておくことにします。

Python のスクリプトでは、まず、Microsoft のドライバのある URL にアクセスし、リンクを収集します。つぎに、ファイル名を指定して、Windows OS 用の Microsoft Edge 用のドライバを探します。ドライバは新旧のバージョンがアップされているので、スクリプトでは最新版をダウンロードすることにします。
ダウンロードしたファイルは zip で圧縮されています。そこで、続いて zip ファイルの解凍も Python で行うことにします。

該当ページの URL とファイル名を指定するとダウンロードができます。ファイル名を修正することで Linux 用のドライバや他の一般のファイルもダウンロードできるようにするなど、汎用性を持たせておくことにします。

設定手順

① 以下を参考に、ウェブドライバのダウンロード用のフォルダを作成してください。
例: c:\user\web_driver1
② ①のフォルダ内に download_web_driver1.py 等の名前でテキストファイルを作成し、下記のサンプルスクリプトをコピー&ペーストで貼りつけて保存してください。
例: c:\user\web_driver1\download_web_driver1.py
③ コマンドプロンプト(または、Anaconda Prompt)を起動し、②のスクリプトを実行してください。
例: python c:\user\web_driver1\download_web_driver1.py

→ ①のフォルダ内に “download1” フォルダが作成され、この中に zip ファイルと、Microsoft Edge 用のドライバ msedgedriver.exe が生成できたら成功です。
※ ダウンロードと解凍が完了すると、以下のファイル等が取得できます。
例:
c:\user\web_driver1\download1\edgedriver_win64.zip
c:\user\web_driver1\download1\msedgedriver.exe    ★1

うまく動いたら

うまく動いたら、Python の selenium のプログラムに、★1のリンクを貼りつけて、selenium を使ってみてください。
最新のドライバで Web サイトの自動操作などが可能になります。
上記のスクリプトをバッチファイルから実行することで、1アクションでドライバの更新が可能になります。
また、現状では、指定したサイト上で、最新バージョン(バージョンの値が最大のもの)をダウンロードするようにしています。スクリプトを修正することで、一番古いものを使う等、カスタマイズが可能です。

スクリプトの説明

・ 冒頭で、Web サイトからファイルを取得するための requests と、HTML を解析するための BeautifulSoup をインポートしています。
・ re は、バージョンの文字列を切り出すために使います。
・ zipfile は、zip を解凍するために使います。
・ create_folder1() 関数は、Python のスクリプトのあるフォルダ内で “download1” フォルダの有無を確認し、なければフォルダを生成します。ダウンロードしたファイルはすべてこのフォルダ内で解凍等の処理を行います。
・ get_html1() は、指定した URL から requests を使って HTML のデータを取得し、BeautifulSoup の形式に変換して結果を返す関数です。
・ get_url1() は、zip ファイルの URL を返す関数です。具体的には、取得した BeautifulSoup 形式のデータから、aタグのリンクを取得し、ファイル名のパターン pattern1 (zipファイルのファイル名)が一致している URL を返します。
実際は、ドライバのサイト上には、バージョンの異なるファイル名が同一の zip ファイルが多数あります。そこで、スクリプトでは、最新バージョンのファイルを返すようにしています。スクリプトをカスタマイズすることで、最も古いバージョンを返す、等も可能です。
・ get_version1() は、zip ファイルの URL から、バージョンの部分を抜き出して返す関数です。
実際は、zip ファイルの1つ上の階層のフォルダ名がバージョンとなっているので、このバージョンの部分を抜き出しています。
・ download_file1() は、指定した URL からファイルを取得し、指定したファイル名 file1 でローカルに保存する関数です。
・ extract_zip1() は、zip ファイルのフルパスを指定すると、そのファイルを解凍し、デフォルトでは同一フォルダ内に解凍する関数です。フォルダ folder1 が指定されていた場合は、そのフォルダ内に解凍します。
・ Python のスクリプトを実行すると、path1 = … 以降から実行されます。
path1 = … としたところで、Python のスクリプトが存在しているフォルダを取得します。
path2 = … としたところで、保存先のフォルダ “download1″ を作成しています。
つぎに、マイクロソフトのホームページで、Microsoft Edge 用のドライバのある URL (★2)を指定し、該当ページの HTML を取得します。
つぎに、この HTML の中から、リンクを抽出し、”edgedrive_win64.zip” の文字列のあるリンク url2 を取得します。
zip が見つかったら、バージョンを確認し、ダウンロード先のリンクを生成して zip ファイルを保存します。
続いて、その zip ファイルの解凍を行って、プログラムを終了します。

まとめ

Microsoft Edge の selenium 用のドライバについて、公式サイトからドライバをダウンロードする Python のスクリプトをまとめました。
これで、ウェブスクレイピングなどが動かなくなっても、ドライバのアップデートがすぐに終わるようになりました。

今回は、Microsoft のサイトから、必要な zip ファイルをダウンロードするスクリプトについてまとめました。
他にも、ネット上にアップされている CSV ファイルなどをダウンロードする汎用なスクリプトについてもまとめています。もし、興味のある方は、下記の関連リンクなども参照してみてください。

関連リンク
・ サイトを巡回してファイルをダウンロードする 【Python】
・ 
Webスクレイピングが動かなくなったとき 【Microsoft Edge & selenium】
・ ウェブ検索と結果の取得を自動化する【Python & selenium】
・ 指定した URL からリンクを抽出する 【Python】
・ 表示中のサイトの表やテキストを保存する 【Python & selenium】

外部リンク
・ https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/

サンプルスクリプト

ドライバのダウンロード用スクリプト download_web_driver1.py


import os
import re
import requests as rq1 
from bs4 import BeautifulSoup as bs1 
import zipfile as zf1 

def create_folder1(path1, folder1): 
    path2 = os.path.join(path1, folder1)                       # folder: download1 
    if not os.path.exists(path2):
        os.makedirs(path2)
        print(f"Created folder: {path2}")
    return path2 

def get_html1( url1 ):
    html1 = None 
    response1 = rq1.get( url1 )
    if response1.status_code == 200:
        html2 = response1.text 
        html1 = bs1(html2, "html.parser")
    return html1 

def get_url1( html1, pattern1 ): 
    url1 = None
    urls1 = [tag1["href"] for tag1 in html1.find_all("a", href=True)]    # url list 
    urls2 = [] 
    for url3 in urls1: 
        if url3.startswith("http") and pattern1 in url3:                 # web driver 
            urls2.append( url3 ) 
    urls2 = list(set(urls2))                                             # unique list 
    urls2.sort() 
    urls2.reverse() 
#   print( urls2 )  
    if len(urls2) > 0: 
        url1 = urls2[0]                                                  #   0: latest version 
#       url1 = urls2[-1]                                                 #  -1: oldest version 
    return url1 

def get_version1( str1 ): 
    str2 = None 
    search1 = re.search(r"/(\d+\.\d+\.\d+\.\d+)/", str1)                # pattern      /xxx.xxx.xxx.xxx/ 
    if search1:
        str2 = search1.group(1)                                         # version info  xxx.xxx.xxx.xxx 
    return str2 

def download_file1( url1, file1 ): 
    ret1 = None 
    get1 = rq1.get(url1) 
    if get1.status_code == 200:
        with open( file1, 'wb' ) as f: 
            f.write(get1.content) 
        ret1 = url1 
    return ret1 

def extract_zip1( path1, folder1=None ):
    if folder1 is None:
        folder1 = os.path.dirname( path1 )
    with zf1.ZipFile( path1, 'r' ) as zip_ref:
        zip_ref.extractall( folder1 )
        print(f"extracted: {path1}") 
        print(f"folder: '{folder1}")

path1 = os.path.dirname(__file__) 

path2 = create_folder1( path1, "download1" )                   # "download1" folder 

url1  = "https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/"
print( url1 ) 

html1 = get_html1( url1 )

filename1 = "edgedriver_win64.zip" 

url2 = get_url1( html1, filename1 )                            # url 

if url2: 
    str1 = get_version1( url2 ) 
    print( str1 ) 
    file1 = os.path.join( path2, filename1 ) 
    ret1 = download_file1( url2, file1 ) 
    print( ret1 ) 
    if ret1: 
        extract_zip1( file1 ) 
    else: 
        print( "cannot download" ) 
else: 
    print( "cannot find url" ) 
タイトルとURLをコピーしました