如何在Heroku上用ChromeDriver将截图保存到Django的CloudinaryField?
解决Heroku上Django+ChromeDriver截图保存到CloudinaryField的问题
1. 先解决截图未生成的问题
Heroku采用临时文件系统,/app目录虽存在,但直接写入固定文件名可能因权限或临时存储机制导致文件无法保留。建议使用Heroku官方推荐的可写临时目录/tmp,该目录是每个dyno的专属临时存储,读写权限更可靠:
# 替换原截图路径为/tmp目录 driver.save_screenshot('/tmp/a.png')
2. 正确将截图上传到CloudinaryField
你当前直接传递本地文件路径给CloudinaryField的写法错误——Cloudinary无法访问Heroku本地临时路径,必须传递文件对象才能完成上传。修改代码如下:
screenshot_path = '/tmp/a.png' # 确认截图成功生成后再处理 if driver.save_screenshot(screenshot_path): # 以二进制模式打开截图文件 with open(screenshot_path, 'rb') as img_file: # 将文件对象传入CloudinaryField UploadedImage.objects.create(image=img_file) else: return HttpResponse("截图生成失败", status=500)
3. 其他关键优化
- ChromeDriver路径管理:在Heroku上建议通过
heroku-buildpack-chromedriver构建包管理ChromeDriver,可通过环境变量自动获取路径,避免手动指定出错:import os driver_path = os.environ.get('CHROMEDRIVER_PATH', '/app/.chromedriver/bin/chromedriver') driver = webdriver.Chrome(executable_path=driver_path, options=options) - 资源清理:使用完ChromeDriver后必须调用
quit()关闭,避免内存泄漏:driver.quit() - Cloudinary配置检查:确保Django的
settings.py已通过环境变量配置好Cloudinary参数(如CLOUDINARY_URL),这是Heroku上Cloudinary正常工作的前提。
完整修正后的视图片段
from selenium import webdriver from selenium.webdriver.chrome.options import Options from django.http import HttpResponse from .models import UploadedImage import os def capture_weather_screenshot(request): options = Options() options.add_argument('--disable-gpu') options.add_argument('--disable-extensions') options.add_argument('--proxy-server="direct://"') options.add_argument('--proxy-bypass-list=*') options.add_argument('--start-maximized') options.add_argument('--headless') options.add_argument('--no-sandbox') driver_path = os.environ.get('CHROMEDRIVER_PATH', '/app/.chromedriver/bin/chromedriver') driver = webdriver.Chrome(executable_path=driver_path, options=options) try: driver.get('https://weather.yahoo.co.jp/weather/') driver.set_window_size(1250, 1036) screenshot_path = '/tmp/a.png' if driver.save_screenshot(screenshot_path): with open(screenshot_path, 'rb') as img_file: UploadedImage.objects.create(image=img_file) return HttpResponse("Success") else: return HttpResponse("截图生成失败", status=500) finally: driver.quit()
内容的提问来源于stack exchange,提问作者Ko Rust
相关产品推荐
相关产品推荐

