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

从Laravel调用Python Selenium脚本无法打开浏览器的问题排查

问题:Laravel调用Python Selenium脚本无法打开浏览器

终端直接执行login_script.py能正常打开浏览器完成登录,但通过Laravel的PythonController.php调用时,浏览器无法打开,页面空白且无任何报错。

用户提供的代码

Python代码(login_script.py)

import subprocess
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time

# Install Selenium if not already installed
try:
    import selenium
except ImportError:
    print("Installing Selenium...")
    subprocess.run(['pip', 'install', 'selenium'])

# Define your credentials and login URL
username = 'myusername'
password = 'mypassword'
login_url = 'https://example.com/login'

# Create a WebDriver instance (assuming Chrome)
driver = webdriver.Chrome()

# Maximize the browser window
driver.maximize_window()

# Navigate to the login page
driver.get(login_url)

# Wait for the page to load (you might need to adjust the time depending on the page load time)
#time.sleep(1)

# Find the username and password input fields and fill them in
username_field = driver.find_element(By.NAME, "username")
password_field = driver.find_element(By.NAME, "password")

username_field.send_keys(username)
password_field.send_keys(password)

# Submit the form
password_field.send_keys(Keys.RETURN)

# Optionally, you might want to add some delay here to allow time for the page to load

# Wait for the login process to complete
time.sleep(999999999)  # Adjust as needed

# Close the browser session
#driver.quit()

Laravel代码(PythonController.php)

<?php

namespace Modules\SideMenuBuilder\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;
use Illuminate\Support\Facades\Artisan;


class PythonController extends Controller
{
    public function openBrowser(Request $request)
    {
        try {

        // Case 1:
            $basePath = base_path();
            $process = new Process(['python3', base_path() . '/open_browser.py']);
            $process->run();
            return $process->getOutput();

        // Case 2:
            // Activate virtual environment
            $activate_command = 'source pythonenv/bin/activate';
            // Run Python script within the activated virtual environment';
            $python_command = 'python3 open_browser.py';
            // Combine commands with && to execute sequentially
            $command = "$activate_command && $python_command 2>&1";
            // Execute the command and capture output
            $output = shell_exec($command);
            // Output the result
            return response()->json(['output' => $output]);
        } catch (Exception $e) {
            return response()->json(['output' => $e->getMessage()]);
        }
        //exit();
    }
}

核心原因排查

  • 无图形化环境:Laravel运行在Web服务器(Nginx/Apache)环境下,服务器通常没有桌面图形界面,而Selenium默认需要图形环境才能启动浏览器;终端执行时是在用户的桌面会话中,所以能正常运行。
  • 权限与环境变量差异:Web服务器进程(如www-data)的权限、环境变量和终端用户不同,可能找不到ChromeDriver、Python依赖,或者无法访问图形资源。
  • 脚本路径与虚拟环境问题:Laravel代码中脚本文件名不匹配(用户脚本是login_script.py,代码里写的是open_browser.py),且非交互式shell中source激活虚拟环境的方式无效。

解决方案

1. 配置Selenium为Headless模式(推荐)

修改Python脚本,使用Chrome的Headless模式,无需图形化环境即可运行:

# 修改WebDriver初始化部分
options = webdriver.ChromeOptions()
options.add_argument('--headless=new')  # 新版Headless模式,兼容性更好
options.add_argument('--no-sandbox')   # 解决服务器权限限制
options.add_argument('--disable-dev-shm-usage')  # 避免内存不足问题
driver = webdriver.Chrome(options=options)

2. 修复权限与路径问题

  • 确保ChromeDriver和Chrome浏览器能被Web服务器用户访问,或者在脚本中指定ChromeDriver绝对路径:
driver = webdriver.Chrome(executable_path='/usr/local/bin/chromedriver', options=options)
  • 给Python脚本添加服务器用户的执行权限:
chown www-data:www-data login_script.py
chmod +x login_script.py

3. 修正Laravel中的脚本调用

  • 修正脚本文件名:把代码中的open_browser.py改为实际的login_script.py,并使用绝对路径:
// Case1修改后
$process = new Process(['python3', base_path() . '/login_script.py']);
  • 虚拟环境直接调用:非交互式shell中source无效,直接使用虚拟环境的Python绝对路径:
// Case2修改后
$python_path = base_path() . '/pythonenv/bin/python3';
$script_path = base_path() . '/login_script.py';
$command = "$python_path $script_path 2>&1";
$output = shell_exec($command);
return response()->json(['output' => $output]);

4. 捕获详细错误信息

在Laravel中添加错误输出捕获,方便排查问题:

// Case1中补充错误捕获
$process->run();
if (!$process->isSuccessful()) {
    throw new ProcessFailedException($process);
}
return response()->json([
    'output' => $process->getOutput(),
    'error' => $process->getErrorOutput()
]);

修改后的完整Python脚本

import subprocess
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

# Install Selenium if not already installed
try:
    import selenium
except ImportError:
    print("Installing Selenium...")
    subprocess.run(['pip', 'install', 'selenium'])

# Define your credentials and login URL
username = 'myusername'
password = 'mypassword'
login_url = 'https://example.com/login'

# 配置Chrome Headless模式
options = webdriver.ChromeOptions()
options.add_argument('--headless=new')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--window-size=1920,1080')  # 设置窗口大小,保证元素能正常加载

# 初始化WebDriver
driver = webdriver.Chrome(options=options)

try:
    # 导航到登录页
    driver.get(login_url)

    # 显式等待元素加载,比time.sleep更可靠
    username_field = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.NAME, "username"))
    )
    password_field = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.NAME, "password"))
    )

    # 填写凭证并提交
    username_field.send_keys(username)
    password_field.send_keys(password)
    password_field.send_keys(Keys.RETURN)

    # 等待登录跳转完成
    WebDriverWait(driver, 10).until(
        EC.url_changes(login_url)
    )

    # 可选:截图验证登录结果
    # driver.save_screenshot(base_path() + '/login_success.png')

finally:
    # 关闭浏览器
    time.sleep(5)
    driver.quit()

内容的提问来源于stack exchange,提问作者Rajeev Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 20:16:13