はじめに
本記事のコードは以下の環境で検証しています。
※OSやバージョンが異なる場合、挙動が変わる可能性があります。
OS: Windows10
Python: 3.12.2
selenium: 4.17.2
ブラウザはChromeで記載していますが、Firefoxなど別ブラウザでも同様の対策ができるようです。
driverの生成の仕方でwebdriverが残存することがある
driverを生成する方法によってはdriverを閉じることが出来ず、プロセスが残ってしまうことがあります。
これによりメモリなどを無駄に使ってしまい、リソースを圧迫し他のプログラムに影響を与えてしまうことがあります。
こういったwebdriverの閉じ漏れ、対策方法についてまとめていきます。
driverが残存するおそれのある書き方
それではいきなり、driverが残存するおそれのある書き方を見てみましょう。
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("http://selenium.dev")
driver.quit()
このコード実はseleniumの公式サイトに記載された記述方法です...
どういう場合にdriverの閉じ漏れが発生するのか
まずはdriverを閉じる方法を確認します。
driverを閉じる方法としては
driver.quit()
このコードが実行されることによりdriverが閉じられます。
そのため
・driver.quit()
を記載しなかった場合
・driver.quit()
を記載していたが、driverの操作中にエラーが発生し実行されなかった場合
にdriverが残存してしまいます。
閉じ漏れの発生するコード例
実務でコードを書くときはエラーを検知できるよう、エラーハンドリングしていると思います。
driverが残存するおそれのある書き方のコードをtry
except
で囲ってエラーハンドリングしてみましょう。
driver.get
を存在しないURLに変更しエラーを起こすようにしています。
これにより
driver.quit()
が実行されずにexcept
へ行ってしまい、driverが閉じられません。
from selenium import webdriver
try:
driver = webdriver.Chrome()
# 存在しないURLを指定してエラーを起こす
driver.get("http://not-exists.selenium.dev") # ここでエラーになってexceptに行く
driver.quit() # ここを通らないため、driverが閉じない
except Exception as e:
# エラー通知代わりのプリント文
print(e)
いくらシンプルなコードでも、通信の問題などでエラーが発生してしまう可能性もあるため、こういったdriverの生成、エラーハンドリングは避けるべきです。
閉じ漏れを防ぐdriverの生成方法
driverの生成を以下のように変更することで防ぐことが出来ます。
他にもfinallyでdriverを閉じるという方法もありますが
これがdriver生成のベストプラクティス、これだけ覚えればいい気がします。
from selenium import webdriver
try:
with webdriver.Chrome() as driver:
driver.get("http://not-exists.selenium.dev")
except Exception as e:
print(e)
このようにwith文で書くことにより
エラーが有っても無くてもwithブロックを抜けたときに自動的にdriver.quit()
が呼び出されるようになります。
なのでdriver.quit()
を明示的に書く必要が無くなります。
正確に言うと、withブロックを抜けるとクラスの__exit__
メソッドが呼び出されます。
そのためseleniumライブラリ selenium/webdriver/remote/webdriver.py内
WebDriverクラスの__exit__
メソッドのself.quit()
が実行されています。
(おまけ)
finallyでdriverを閉じる
with文での書き方だけ覚えればいい気がしますが
finallyでエラーが有っても無くてもdriver.quit()する方法です。
from selenium import webdriver
try:
driver = webdriver.Chrome()
# 存在しないURLを指定してエラーを起こす
driver.get("http://not-exists.selenium.dev") # ここでエラーになってexceptに行く
except Exception as e:
# エラー通知代わりのプリント文
print(e)
finally: # finallyはエラーが有っても無くても実行される
driver.quit()
Pythonのコード上で chromedriver.exe の残存を確認
プロセスに"chromedriver.exe"が存在するかはタスクマネージャーを見れば分かりますが
以下のようなコードで、Pythonのコード上で確認することが出来ます。
※psutilというライブラリを使用しているのでpip install psutil
でインストールが必要です。
import psutil
exists_chromedriver = False
for proc in psutil.process_iter():
if proc.name() == "chromedriver.exe":
exists_chromedriver = True
break
if exists_chromedriver:
print("chromedriver.exe プロセスが存在します。")
else:
print("chromedriver.exe プロセスが存在しません。")
実際に動作させてみると
import psutil
from selenium import webdriver
try:
driver = webdriver.Chrome()
driver.get("http://not-exists.selenium.dev")
driver.quit()
except Exception as e:
print(e)
exists_chromedriver = False
for proc in psutil.process_iter():
if proc.name() == "chromedriver.exe":
exists_chromedriver = True
break
if exists_chromedriver:
print("chromedriver.exe プロセスが存在します。")
else:
print("chromedriver.exe プロセスが存在しません。")
# >>> chromedriver.exe プロセスが存在します。
with文で書いていない方は、driverが残存し
import psutil
from selenium import webdriver
try:
with webdriver.Chrome() as driver: # withブロックを抜けるとquit()が呼び出される
driver.get("http://not-exists.selenium.dev")
except Exception as e:
print(e)
exists_chromedriver = False
for proc in psutil.process_iter():
if proc.name() == "chromedriver.exe":
exists_chromedriver = True
break
if exists_chromedriver:
print("chromedriver.exe プロセスが存在します。")
else:
print("chromedriver.exe プロセスが存在しません。")
# >>> chromedriver.exe プロセスが存在しません。
with文で書いた方は、きちんとdriverが閉じられていることが確認できます。