前言
利用本篇紀錄使用 Docker Selenium 的過程。
什麼是 Docker Selenium
Docker Selenium 是一個提供不同類型 driver 的 Docker image 的開源專案,目前掛在 Selenium 下面,看起來有常態性的維護。
為何需要 Docker Selenium
使用 Selenium 時進行資料蒐集工作時,需要指定 driver ,例如 Chrome 或是 Firefox,但如果跟 OS 上安裝的 browser 版本不同時,Selenium 就無法運作,Docker Selenium 解決了這項工作痛點。
專案提供了兩種常見的使用方式, standalone
和 Hub and Node
, standalone
只跑一個獨立的 driver, 而 Hub and Node
則有多個,方便不同瀏覽器間的自動化測試。
如何使用 Docker Selenium
如專案名稱所寫,要使用 Docker,沒碰過 Docker 的人可以看看這篇瞭解一下。
要單跑一個 driver,可以用專案提供的範例
docker run -d -p 4444:4444 --shm-size="2g" selenium/standalone-chrome:4.19.1-20240402
像 M1 Mac 用 arm 架構,雖然上面也指令也跑得起來,但看不到運行的 log,需要用不同 image,可以參考這邊的範例
docker run --rm -it -p 4444:4444 -p 5900:5900 -p 7900:7900 --shm-size 2g seleniarm/standalone-chromium:latest
跑起來後,可以去 http://localhost:4444/ui/
確認,應該會有類似後台的畫面就是成功囉。
Python 與 Selenium
一般情況下,在使用 selenium 時的 code 會像下方範例。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
url = 'https://google.com'
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
driver.get(url)
而如果是用 Docker Selenium 跑起來的 driver ,則需要稍微修改程式碼,將 Chrome
改為使用 Remote
。
參數 command_executor
就是指定剛用 Docker 跑起來的 driver。
...
driver = webdriver.Remote(
command_executor='http://localhost:4444/wd/hub',
options=options
)
...
實務上碰到的問題
當想在 server 上用 selenium 進行資料蒐集時,使用 docker selenium 的情況下,會需要從一個 container 去連到這個 driver,也就是 container 間的互連(driver 本身也是一個 container)。
此時需要用 Docker network 來完成,舉例如下
先建立一個
network
docker network create local-demo
此時,在跑 driver 的 docker 指令中指定
network
docker run --network=local-demo --name=selenium-chrome-driver --shm-size 2g seleniarm/standalone-chromium:latest
接著假設你的專案是只有一個簡單的檔案
main.py
,因為要連到另一個 container 的關係,要將command_executor
的 url 換成 driver 的 container 名稱,也就是selenium-chrome-driver
。# ./main.py from selenium import webdriver from selenium.webdriver.chrome.options import Options url = 'https://google.com' options = Options() options.add_argument('--headless') driver = webdriver.Remote( command_executor='http://selenium-chrome-driver:4444/wd/hub', options=options ) driver.get(url) print('success') driver.quit()
而整個專案是用
docker-compose.yaml
定義的,類似這樣,記得指定networks
,讓兩個 container 間可以互通。version: "3" services: worker: build: context: . dockerfile: Dockerfile container_name: demo-selenium command: "python main.py" networks: - local-demo # <-- add this networks: # <-- add this local-demo: external: true
此時把專案跑起來,可以成功使用 driver 完成工作。
docker-compose up -d --build