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部署:
- 添加必要的buildpack:
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-google-chrome.git heroku buildpacks:add https://github.com/heroku/heroku-buildpack-chromedriver.git - 确认Heroku环境变量中
CHROMEDRIVER_PATH和GOOGLE_CHROME_BIN已自动配置(buildpack会自动生成)
- 添加必要的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
相关产品推荐
相关产品推荐

