多线程Selenium+Tkinter启动Chrome实例异常求助
Let's tackle your problems head-on—you're hitting two critical issues here: threads all targeting the last driver instance, and WebDriver exceptions from conflicting Chrome user data directories. Plus, we need to keep initialization fast and the GUI responsive while retaining that Chrome taskbar icon merging feature. Here's how to fix everything:
1. Stop Threads from Sharing the Same Driver (The "Last Instance" Problem)
This almost always happens because you're reusing a single ChromeOptions object or referencing loop variables that get overwritten (Python's loop variable late binding strikes again!). The fix is simple: give each thread its own isolated ChromeOptions and Browser instance.
Instead of creating options once outside your loop, build them inside the function each thread runs. Pass the URL directly to the thread so each Browser binds to its own driver and target URL:
import threading from selenium import webdriver import uuid # For unique profile IDs class Browser: def __init__(self, driver, target_url): self.driver = driver self.target_url = target_url self.running = True def start_refresh_loop(self): self.driver.get(self.target_url) while self.running: # Refresh every 4 seconds self.driver.refresh() threading.Event().wait(4) def launch_browser_instance(url): # Create a unique, isolated user data directory for this instance unique_profile_dir = f"./chrome_profiles/{uuid.uuid4().hex[:8]}" # Build options from scratch for this thread options = webdriver.ChromeOptions() options.add_argument(f"--user-data-dir={unique_profile_dir}") # Add your other desired options here (e.g., --start-minimized) options.add_argument("--start-minimized") # Initialize driver and bind to Browser driver = webdriver.Chrome(options=options) browser = Browser(driver, url) try: browser.start_refresh_loop() except Exception as e: print(f"Error with URL {url}: {str(e)}") driver.quit() # Your Tkinter button click handler def on_start_button_click(): urls = [ "https://url1.com", "https://url2.com", # Add your 4 other URLs here ] for url in urls: # Start a daemon thread so it exits when the Tkinter window closes thread = threading.Thread(target=launch_browser_instance, args=(url,), daemon=True) thread.start()
2. Fix the WebDriverException from --user-data-dir
The "unable to parse internal JSON template" error is a side effect of multiple Chrome instances trying to share the same user data directory. Chrome locks this directory to prevent corruption, so subsequent instances can't initialize properly.
By using a unique --user-data-dir for each instance (as shown above), you eliminate this conflict entirely. And don't worry about losing the taskbar icon merging—Windows (or your OS) will still group all Chrome windows under a single icon, since they're all instances of the same executable.
3. Keep Initialization Fast (Ditch the Global Lock)
You only needed locks because you were sharing resources across threads. Now that each thread manages its own options, driver, and profile, you don't need any locks. Threads can initialize Chrome instances in parallel, keeping your startup speed snappy.
4. Prevent GUI Freezing with ThreadPoolExecutor
If ThreadPoolExecutor was freezing your GUI, you were probably blocking the Tkinter main loop by waiting for thread results. Instead, submit tasks asynchronously without waiting for them to finish:
from concurrent.futures import ThreadPoolExecutor # Initialize the executor once (outside your button handler) executor = ThreadPoolExecutor(max_workers=6) # Match your 6 instances def on_start_button_click(): urls = ["url1", "url2", ..., "url6"] for url in urls: executor.submit(launch_browser_instance, url)
This lets the Tkinter main loop keep running while threads handle Chrome initialization and refreshing.
5. Bonus: Clean Up Temporary Profiles
To avoid cluttering your filesystem with hundreds of Chrome profiles, use temporary directories that auto-delete when the thread exits:
import tempfile def launch_browser_instance(url): # Create a temporary directory that gets deleted automatically with tempfile.TemporaryDirectory() as temp_profile_dir: options = webdriver.ChromeOptions() options.add_argument(f"--user-data-dir={temp_profile_dir}") # Rest of your driver/Browser setup here...
This ensures no leftover profile folders after your program closes.
Final Checks
- Make sure your
Browserclass uses instance variables (e.g.,self.driver) instead of class variables (e.g.,Browser.driver). Class variables are shared across all instances, which would bring back the "last driver" problem. - Always call
driver.quit()in exception handlers to avoid orphaned Chrome processes.
内容的提问来源于stack exchange,提问作者Theodore




