Linux下Django调用Selenium无法创建第二个会话问题
问题描述
Linux环境下,Django(WSGI模式)通过POST请求调用Selenium WebDriver,首次请求能正常打开浏览器,但第一个驱动仍运行时,第二次请求无法创建新的Selenium会话。需要同时启动两个独立的驱动实例,已排除线程问题。
代码片段
视图代码
class Test(generics.CreateAPIView): def create(self, request, *args, **kwargs): searchDict = dict(request.data) profile = searchDict['profile'] threading.Thread(target=self.runDriver, args=(profile,)).start() return Response(status=status.HTTP_200_OK) def runDriver(self, profile): br = Driver() useragent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0' profile_name = profile username = 'samsan' password = '##1234sAMIUL.' br.createUCDriver(useragent, profile_name) dr = br.ucDriver dr.get('https://www.google.com/') time.sleep(10) dr.get(dr.current_url)
Driver类代码
class Driver: def __init__(self): self.driver = None self.ucDriver = None self.waitTime = 10 self.executable = "seleniumDriver/chromedriver-mac-arm64/chromedriver" def createUCDriver(self, user_agent=None, profile_name='Profile 2'): options = webdriver.ChromeOptions() if user_agent: options.add_argument(f'--user-agent={user_agent}') print('sys', sys.platform) if sys.platform == 'darwin': options.add_argument('--user-data-dir=/Users/yourusername/Library/Application Support/Google/Chrome') elif sys.platform == 'linux' or sys.platform == 'linux2': options.add_argument(f'--user-data-dir={Path(__file__).parent.parent.parent / "application" / "local" / "nfs"}') elif sys.platform == 'win32' or sys.platform == 'win64': options.add_argument('--user-data-dir=C:\\Users\\User\\AppData\\Local\\Google\\Chrome\\User Data') options.add_argument(f'--profile-directory={profile_name}') options.add_argument('--hide-crash-restore-bubble') options.add_argument("--disable-popup-blocking") options.add_argument('--disable-features=InfiniteSessionRestore') options.add_argument('--disable-features=PrivacySandboxSettings4') if sys.platform == 'darwin': print('mac') driver = uc.Chrome(options=options, use_subprocess=True) elif sys.platform == 'linux' or sys.platform == 'linux2': service = Service(executable_path=str(Path(__file__).parent/ 'chromeDriver'/ 'chromedriver-linux64' / 'chromedriver')) print('linux') driver = uc.Chrome(options=options, use_subprocess=True, service=service) elif sys.platform == 'win32' or sys.platform == 'win64': print('windows') try: driver = uc.Chrome(options=options, use_subprocess=True, driver_executable_path=str(Path(__file__).parent/ 'chromeDriver'/ 'chromedriver-win32' / 'chromedriver.exe')) except Exception as e: print('Error in starting Chrome', e) self.ucDriver = driver self.ucDriver.set_page_load_timeout(1.5 * 60)
问题分析
核心原因是多个Chrome实例共享了同一个用户数据目录(user-data-dir)。Chrome会对用户数据目录加锁,不允许多个进程同时访问——哪怕指定了不同的profile-directory也不行,锁是在user-data-dir根目录级别生效的。第一个驱动启动后占用了该目录,第二个驱动尝试访问时会因为锁冲突而创建会话失败。
解决方案
1. 为每个驱动实例创建独立的用户数据目录
不要共用同一个user-data-dir,为每个实例生成唯一的目录路径。可以基于profile名称、UUID或者时间戳生成独立目录,示例修改如下:
修改Driver类的createUCDriver方法:
import tempfile import uuid def createUCDriver(self, user_agent=None, profile_name='Profile 2'): options = webdriver.ChromeOptions() if user_agent: options.add_argument(f'--user-agent={user_agent}') print('sys', sys.platform) # 为每个实例生成独立的用户数据目录 if sys.platform == 'darwin': temp_dir = tempfile.mkdtemp(prefix=f"chrome_{profile_name}_") options.add_argument(f'--user-data-dir={temp_dir}') elif sys.platform == 'linux' or sys.platform == 'linux2': base_dir = Path(__file__).parent.parent.parent / "application" / "local" / "nfs" unique_dir = base_dir / f"chrome_session_{uuid.uuid4().hex}" unique_dir.mkdir(parents=True, exist_ok=True) options.add_argument(f'--user-data-dir={unique_dir}') elif sys.platform == 'win32' or sys.platform == 'win64': temp_dir = tempfile.mkdtemp(prefix=f"chrome_{profile_name}_") options.add_argument(f'--user-data-dir={temp_dir}') # 以下原有参数保持不变...
2. 确保驱动退出时释放资源
在runDriver方法末尾添加dr.quit(),确保驱动进程完全退出,释放目录锁和系统资源:
def runDriver(self, profile): br = Driver() useragent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0' profile_name = profile username = 'samsan' password = '##1234sAMIUL.' try: br.createUCDriver(useragent, profile_name) dr = br.ucDriver dr.get('https://www.google.com/') time.sleep(10) dr.get(dr.current_url) finally: # 确保无论是否出错都关闭驱动 if hasattr(br, 'ucDriver') and br.ucDriver: br.ucDriver.quit()
3. 额外检查项
- 确认chromedriver版本与系统安装的Chrome版本完全匹配,版本不兼容也可能导致会话创建失败;
- Linux环境下DISPLAY变量设置正确,确保每个线程都能继承到该环境变量;
- 如果使用undetected-chromedriver(代码中的
uc),确保版本是最新的,避免已知的多实例冲突问题。
内容的提问来源于stack exchange,提问作者Samiul Ehsan
相关产品推荐
相关产品推荐

