You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 10:29:52