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

Flask+Selenium部署Heroku遇TypeError及代码不可达问题求助

Flask+Selenium+Heroku部署问题排查与解决

问题背景

基于Python Flask开发的Web应用,使用Selenium ChromeDriver实现网页爬取,部署在Heroku平台,遇到以下核心问题:

  • VSCode中driver = webdriver.Chrome(executable_path=os.environ.get("CHROMEDRIVER_PATH"), chrome_options=chrome_options)这行代码导致后续代码被标记为不可达
  • 运行时抛出TypeError: expected str, bytes or os.PathLike object, not NoneType错误
  • 尝试升级/降级Python版本(3.8→3.11→3.10→3.9)无效;将Chrome配置拆分到独立类后解决了代码不可达问题,但出现自定义类模块未找到错误

原代码

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os
import time


class Letsgo:
    def scrape(self):
        chrome_options = Options()
        chrome_options.binary_location = os.environ.get("GOOGLE_CHROME_BIN")
        chrome_options.headless = True
        chrome_options.add_argument("--disable-dev-shm-usage")
        chrome_options.add_argument("--no-sandbox")
        driver = webdriver.Chrome(executable_path=os.environ.get("CHROMEDRIVER_PATH"), chrome_options=chrome_options)

        driver.get("https://letsgo-bot.herokuapp.com/login?next=%2Fdashboard")
        time.sleep(2)
        wait = WebDriverWait(driver,10)
        original_window = driver.current_window_handle
        assert len(driver.window_handles) == 1  

拆分后的代码

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os
import time

class WebChrome:
    def chrome_func():
        chrome_options = Options()
        chrome_options.binary_location = os.environ.get("GOOGLE_CHROME_BIN")
        chrome_options.headless = True 
        chrome_options.add_argument("--disable-dev-shm-usage")
        chrome_options.add_argument("--no-sandbox")
        return chrome_options
    
    driver = webdriver.Chrome(executable_path=os.environ.get("CHROMEDRIVER_PATH"), chrome_options=chrome_func())

报错栈

Traceback (most recent call last):
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 2091, in _call_
    return self.wsgi_app(environ, start_response)
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 2076, in wsgi_app
    response = self.handle_exception(e)
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 2073, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 1518, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 1516, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 1502, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "C:\Users\User\Documents\lamla hub\damp-beach-65563\user.py", line 12, in wrap
    return f(*args, **kwargs)
  File "C:\Users\User\Documents\lamla hub\damp-beach-65563\run.py", line 218, in apply_results
    instance.wsu_apply()
  File "C:\Users\User\Documents\lamla hub\damp-beach-65563\uni\wsu.py", line 18, in wsu_apply
    driver = webdriver.Chrome(executable_path=os.environ.get("CHROMEDRIVER_PATH"), options=chrome_options)
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\site-packages\selenium\webdriver\chrome\webdriver.py", line 69, in _init_
    super()._init_(DesiredCapabilities.CHROME['browserName'], "goog",
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\site-packages\selenium\webdriver\chromium\webdriver.py", line 89, in _init_
    self.service.start()
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\site-packages\selenium\webdriver\common\service.py", line 71, in start
    self.process = subprocess.Popen(cmd, env=self.env,
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\subprocess.py", line 951, in _init_
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\subprocess.py", line 1360, in _execute_child
    args = list2cmdline(args)
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\subprocess.py", line 565, in list2cmdline
    for arg in map(os.fsdecode, seq):
  File "C:\Users\User\AppData\Local\Programs\Python\Python39\Lib\os.py", line 822, in fsdecode
    filename = fspath(filename)  # Does type-checking of `filename`.
TypeError: expected str, bytes or os.PathLike object, not NoneType

解决方案

1. 解决TypeError核心问题

报错根源是os.environ.get("CHROMEDRIVER_PATH")或os.environ.get("GOOGLE_CHROME_BIN")返回None,导致Selenium无法找到Chrome或ChromeDriver的路径:

  • 本地开发:手动设置这两个环境变量,指向本地Chrome安装路径和ChromeDriver的绝对路径
  • Heroku部署:
    1. 添加必要的buildpack:
      heroku buildpacks:add https://github.com/heroku/heroku-buildpack-google-chrome.git
      heroku buildpacks:add https://github.com/heroku/heroku-buildpack-chromedriver.git
      
    2. 确认Heroku环境变量中CHROMEDRIVER_PATH和GOOGLE_CHROME_BIN已自动配置(buildpack会自动生成)

2. 解决代码不可达问题

VSCode的标记是静态分析误判或代码可能抛出未捕获异常导致,修正方式:

  • 添加环境变量前置检查,提前抛出明确错误
  • 使用try/finally确保driver资源释放,避免异常导致后续代码无法执行

3. 修正拆分后的类代码问题

拆分后的类存在方法定义错误、类级别初始化driver的问题,修正示例:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os

class WebChrome:
    @staticmethod
    def get_chrome_options():
        chrome_bin = os.environ.get("GOOGLE_CHROME_BIN")
        if not chrome_bin:
            raise ValueError("环境变量GOOGLE_CHROME_BIN未设置")
        chrome_options = Options()
        chrome_options.binary_location = chrome_bin
        chrome_options.add_argument("--headless=new")  # 适配新版Chrome的无头模式
        chrome_options.add_argument("--disable-dev-shm-usage")
        chrome_options.add_argument("--no-sandbox")
        return chrome_options

    @staticmethod
    def get_driver():
        chromedriver_path = os.environ.get("CHROMEDRIVER_PATH")
        if not chromedriver_path:
            raise ValueError("环境变量CHROMEDRIVER_PATH未设置")
        options = WebChrome.get_chrome_options()
        # 新版Selenium推荐使用options参数,chrome_options已废弃
        return webdriver.Chrome(executable_path=chromedriver_path, options=options)

# 使用示例
driver = WebChrome.get_driver()
try:
    driver.get("https://letsgo-bot.herokuapp.com/login?next=%2Fdashboard")
    # 你的爬取逻辑
finally:
    driver.quit()  # 确保关闭driver释放资源

额外注意事项

  • 确保Selenium版本与Chrome、ChromeDriver版本兼容,推荐使用selenium==4.x
  • 原代码中漏导入WebDriverWait,需添加from selenium.webdriver.support.ui import WebDriverWait

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 22:01:28