2 minutes
[Selenium] 在 readonly 模式下的問題
這個問題 debug 了快三小時…終於在 gpt 的協助下找到問題
先來描述一下 context
- Container 要 Read-only
- python 3.12
- selenium 用 chormedriver
一直出現這個錯誤
selenium.common.exceptions.SessionNotCreatedException: Message: session not created: probably user data directory is already in use, please specify a unique value for --user-data-dir argument, or don't use --user-data-dir
程式碼
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from seleniumwire import webdriver
import os
chrome_options = Options()
chrome_options.add_argument("--incognito")
chrome_options.add_argument("--headless=new")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--disable-extensions')
chrome_options.add_argument('--disable-setuid-sandbox')
chrome_options.add_argument("--disable-application-cache")
chrome_options.add_argument("--enable-do-not-track")
chrome_options.add_argument("--disable-popup-blocking")
driver = webdriver.Chrome(options=chrome_options)
一開始的程式好好的沒問題,但因為客戶要求要只能 readonly,但是因為該 pod 還是需要寫 tempfile 所以跟客戶要求只使用 /tmp 做為寫檔的地方,改好了其他 funtion,結果這個重要的爬蟲 function 出了問題
首先直接問 gpt,得到的答案跟 log 字面解釋的一樣
–user-data-dir 的使用上有問題,建議我使用 unique 的資料夾
我最先開始認為,因為是 read-only 的環境,可能 selenium 嘗試寫檔的時候被 block 了
於是我嘗試設定 –user-data-dir 到 /tmp file,並實際執行,結果還是一樣
# Create a temporary directory for the Selenium cache in /tmp
with tempfile.TemporaryDirectory(dir="/tmp") as custom_cache_dir:
chrome_options.add_argument(f"--user-data-dir={custom_cache_dir}")
print(custom_cache_dir)
由於一開始是在 aws ecs fargate 上執行,build + deploy 的過程少說都要 5 分鐘以上,相當難測,前後在那邊測試 code 超級惱人時間又被拖很長( 我用 Mac arm 架構,客戶環境 x86, 所以有點難直接在本機端測 ),後來乾脆開了一台 vm 用 docker 直接模擬環境( read-only 建立參考最底下備註)
首先看 log 遇到的第一個錯誤
Cache folder (/root/.cache/selenium) cannot be created: Read-only file system (os error 30)
看來是想寫東西到不能寫的地方
大概與 gpt 對話後就知道該怎麼修正
設定了一個環境變數就解決了
SE_CACHE_PATH=/tmp/selenium_cache
ok 解決掉這個 error 但是標題的問題還是一直存在
在不斷問答測試後才終於發現有兩個關鍵的環境變數也得設定
XDG_CONFIG_HOME=/tmp/xdg_config # default 是 ~/.config
XDG_CACHE_HOME=/tmp/xdg_cache # default 是 ~/.cache
終於大功告成!!!
總結
在 dockerfile 或是 entrypoint 裡面設定環境變數
ENV SE_CACHE_PATH=/tmp/XXXX #指定可以寫資料的地方
ENV XDG_CONFIG_HOME=/tmp/XXXX
ENV XDG_CACHE_HOME=/tmp/XXXX
備註
local 測試 readonly 方式
docker run --rm --read-only -v tmp-vol:/tmp -it {image} bash
ChatGPT 節錄的筆記
🧠 什麼是 XDG?
📦 XDG 最有名的規範:XDG Base Directory Specification
- XDG 是一系列 Linux 桌面環境標準的集合
- 目標是讓不同桌面環境(如 GNOME、KDE、Xfce)之間的軟體能「有一致的資料儲存位置與行為規範」
這是你在使用XDG_CONFIG_HOME
和XDG_CACHE_HOME
所依據的標準。
它定義了使用者應用程式該把以下這些資料存在哪裡:
資料類型 | 環境變數 | 預設值 | 用途 |
---|---|---|---|
設定檔 (Config) | XDG_CONFIG_HOME |
~/.config |
應用程式偏好設定等 |
快取檔 (Cache) | XDG_CACHE_HOME |
~/.cache |
可刪除的中間檔案 |
資料檔 (Data) | XDG_DATA_HOME |
~/.local/share |
長期資料,如使用者資料庫等 |
執行檔 (Runtime) | XDG_RUNTIME_DIR |
系統自動指定,如 /run/user/UID |
暫時檔案,如 IPC socket |
✅ 實際應用
許多知名應用程式都遵守這個標準,包括:
- Chromium / Google Chrome
- Firefox
- Visual Studio Code
- GNOME / KDE 工具
- Docker CLI / Podman
- Git credential helpers
🔧 舉個例子
如果沒設 XDG_CONFIG_HOME
,VS Code 的設定會寫在:
~/.config/Code/User/settings.json
但如果你這樣設定:
export XDG_CONFIG_HOME=/tmp/vscode
它就會改寫到:
/tmp/vscode/Code/User/settings.json
🎯 為什麼開發者常常會接觸 XDG?
- 在 Docker、Lambda、CI/CD 環境中,無法寫入
~/.config
或~/.cache
- 所以會把這些變數改指向
/tmp
或其他可寫目錄,避免程式出錯