使用PM2运行含Selenium与Chromedriver的Python应用频繁崩溃重启
Hey there! Let's work through this PM2 + Selenium issue you're facing—it's a super common hiccup when running browser-based scripts with process managers, so you’re definitely not alone. Let’s break down the fixes step by step:
When you run your script directly in the terminal, your system’s PATH knows where to find Chrome and chromedriver. But PM2 runs in a different environment, so it might not have access to those same paths. The quick fix is to hardcode absolute paths in your Python script:
from selenium import webdriver from selenium.webdriver.chrome.service import Service # Replace these with your actual system paths! # Linux example paths below—adjust for Windows/macOS chrome_binary_path = "/usr/bin/google-chrome" chromedriver_path = "/usr/local/bin/chromedriver" # Set up Chrome options with the explicit binary path chrome_options = webdriver.ChromeOptions() chrome_options.binary_location = chrome_binary_path # Initialize the driver with the specified paths service = Service(chromedriver_path) driver = webdriver.Chrome(service=service, options=chrome_options)
This way, your script doesn’t rely on PM2’s environment to find the browser or driver—you’re telling it exactly where to look.
PM2 only monitors the main Python process by default, but Chrome runs as a separate child process. If the two get disconnected, or if Chrome crashes without PM2 noticing, you’ll run into issues. Here’s how to fix that:
Use --attach for Real-Time Debugging
Start your script with the --attach flag to tie Chrome’s output to PM2’s logs. This makes it way easier to spot errors like browser startup failures:
pm2 start your_scraper.py --name "web-scraper" --attach
Check logs anytime with pm2 logs web-scraper to see what Chrome is doing.
Create an Ecosystem Config File (Recommended)
For better control, make an ecosystem.config.js file to define PM2’s behavior. This lets you set environment variables, restart rules, and log paths all in one place:
module.exports = { apps: [{ name: "web-scraper", script: "your_scraper.py", interpreter: "python3", env: { // Ensure PM2 has access to the right PATH PATH: "/usr/local/bin:/usr/bin:$PATH", // If running on a headless server, set DISPLAY (may vary by system) DISPLAY: ":0" }, autorestart: true, watch: false, max_memory_restart: "1G", // Auto-restart if memory gets too high merge_logs: true, output: "./logs/scraper-out.log", error: "./logs/scraper-error.log" }] };
Launch with this config using:
pm2 start ecosystem.config.js
Enable Headless Chrome (Critical for Servers)
If you’re running this on a server without a graphical interface, Chrome will fail to start unless you use headless mode. Add these arguments to your Chrome options in Python:
chrome_options.add_argument("--headless=new") # Newer, more stable headless mode chrome_options.add_argument("--no-sandbox") # Bypass security restrictions (common on servers) chrome_options.add_argument("--disable-dev-shm-usage") # Fixes "/dev/shm" memory limits chrome_options.add_argument("--disable-gpu") # Unnecessary for headless mode
If your script keeps losing connection to Chrome, it’s likely a lifecycle problem in your code. Make sure you’re properly managing the Chrome driver:
- Always use
driver.quit()instead ofdriver.close()when done—quit()terminates the entire Chrome process, not just a tab, preventing orphaned processes. - Wrap your code in a
try/finallyblock to ensure the driver gets closed even if an error occurs:
try: # Your scraping logic here driver.get("https://example.com") # ... rest of your code except Exception as e: print(f"Scraper error: {str(e)}") finally: # Ensure Chrome is closed no matter what if 'driver' in locals(): driver.quit()
If you want your scraper to run continuously, either add a loop in your script (with a time.sleep() to avoid spamming) or set PM2’s autorestart to true so it restarts the script when it finishes.
To rule out permission or path issues, run a quick test script with PM2 to check if it can access Chrome:
# test_chrome_access.py import subprocess chrome_path = "/usr/bin/google-chrome" # Use your actual path result = subprocess.run([chrome_path, "--version"], capture_output=True, text=True) print("Chrome Version Output:") print(result.stdout) print("\nErrors (if any):") print(result.stderr)
Launch it with PM2:
pm2 start test_chrome_access.py --attach
If it doesn’t print Chrome’s version, either your path is wrong, or the user running PM2 doesn’t have permission to access Chrome.
内容的提问来源于stack exchange,提问作者VagrantC

