如何在单个user-data-dir下使用多进程运行Selenium Chrome实例?
如何在单个user-data-dir下使用多进程运行Selenium Chrome实例?
这个问题我之前折腾过好一阵子!核心原因是Chrome根本不允许多个实例同时共用同一个用户数据目录(user-data-dir)——它会对这个目录加排他锁,防止多个进程同时读写配置、cookie这类数据,所以就会出现你看到的「无法删除旧devtools端口文件」的冲突错误。
下面给你两个可行的解决方案,结合你的代码来改就行:
方案1:给每个进程分配独立的Profile子目录
Chrome的user-data-dir目录本身就支持多个独立的Profile子目录(比如默认的Default,或者你手动创建的Profile 1、Profile 2)。我们可以让所有进程共用同一个主user-data-dir,但给每个进程指定不同的--profile-directory参数,这样既共享了主目录的基础配置和cookie,又不会互相干扰。
具体修改步骤:
- 在调用多进程任务时,给每个任务传递一个唯一的Profile标识(比如用循环索引)
- 修改浏览器驱动的配置,添加
--profile-directory参数
比如修改你的delete_empty_albums函数里的循环部分:
for idx, album in enumerate(tqdm(albums.albums, desc = "Deleting empty albums", unit = "album", position = 0, leave = True)): if album.mediaItemsCount == 0: try: tqdm.write(f"{Fore.BLUE}🗑️ Remove the empty album: \"{album.title}\"{Fore.RESET}") tqdm.write(f"\tURL: {album.productUrl}{Fore.RESET}") # 给每个任务分配唯一的Profile子目录名称 profile_dir = f"Profile_{idx}" pool.apply_async(delete_album, args = (album.productUrl, location, profile, profile_dir), callback = lambda _: delete_album_success(album.title, album.id), error_callback = lambda e: delete_album_error(album.title, album.id, e) ) except Exception as e: # ... 原有错误处理代码不变
然后修改delete_album和browser_driver函数,新增profile_dir参数:
def delete_album(album_productUrl: str, location: pathlib.Path, profile: pathlib.Path, profile_dir: str) -> bool: driver = browser_driver(location, profile, profile_dir) # ... 原有逻辑完全不变 def browser_driver(location: pathlib.Path, profile: pathlib.Path, profile_dir: str) -> webdriver.Chrome: options = Options() if location: options.binary_location = str(location) options.headless = True # 保留原有的user-data-dir配置 options.add_argument(f"--user-data-dir={profile}") # 添加这一行,指定当前进程使用的独立Profile子目录 options.add_argument(f"--profile-directory={profile_dir}") # ... 原有其他配置不变 driver = webdriver.Chrome(options = options) driver.set_window_size(800, 600) return driver
这样每个进程会使用user-data-dir下的不同子目录,完全不会冲突,还能共享主目录的cookie数据。
方案2:给每个实例指定独立的调试端口
有时候即使Profile独立了,devtools的端口也可能出现冲突,我们可以给每个Chrome实例指定唯一的调试端口,进一步避免冲突:
在browser_driver函数里添加端口配置:
import os def browser_driver(location: pathlib.Path, profile: pathlib.Path, profile_dir: str) -> webdriver.Chrome: options = Options() # ... 原有配置 # 生成唯一的调试端口,比如基于进程ID或者索引 # 这里用进程ID取模,确保端口在9222-9322之间(可自行调整范围) port = 9222 + os.getpid() % 100 options.add_argument(f"--remote-debugging-port={port}") # ... 其他配置不变
额外注意事项
- 启动脚本前一定要关闭所有正在运行的Chrome/Chromium进程,否则主
user-data-dir会被占用,还是会报错 - 不要把进程数(threads参数)设得太大,每个Chrome实例占用的内存不低,太多进程会导致系统卡顿
- 如果某些Profile子目录不存在,Chrome会自动创建,不用手动提前创建
备注:内容来源于stack exchange,提问作者ILP
相关产品推荐
相关产品推荐

