Playwright-Python+FastAPI应用Docker运行失败,Headless模式异常求助
问题背景
我开发了一个基于FastAPI和Playwright的数据抓取应用,本地运行完全正常,但部署为Docker镜像时遇到两个问题:
- 初始报错提示未运行XServer,需开启Headless模式;
- 设置
Headless=True后,出现net::ERR_EMPTY_RESPONSE错误,且本地使用Headless=True模式也会触发超时。
报错信息
报错1
Looks like you launched a headed browser without having a XServer running.
Set either 'headless: true' or use 'xvfb-run' before running Playwright.
报错2
net::ERR_EMPTY_RESPONSE at https://book.flygofirst.com/Flight/Select?inl=0&CHD=0&s=True&o1=BOM&d1=BLR&ADT=1&dd1=2022-12-10&gl=0&glo=0&cc=INR&mon=true
logs
navigating to "https://book.flygofirst.com/Flight/Select?inl=0&CHD=0&s=True&o1=BOM&d1=BLR&ADT=1&dd1=2022-12-10&gl=0&glo=0&cc=INR&mon=true",
waiting until "load"
核心代码
def extract_html(self): with sync_playwright() as p: browser = p.chromium.launch() page = browser.new_page() page.goto('https://book.flygofirst.com/Flight/Select?inl={}&CHD={}&s=True&o1={}&d1={}&ADT={}&dd1={}&gl=0&glo=0&cc=INR&mon=true'.format(self.infants, self.children , self.origin, self.destination, self.adults, self.date)) html = page.inner_html('#sectionBody') return html
Dockerfile
FROM python:3.9-slim COPY ../../requirements/dev.txt ./ RUN python3 -m ensurepip RUN pip install -r dev.txt RUN playwright install RUN playwright install-deps ENV PYTHONPATH "${PYTHONPATH}:/app/" WORKDIR /code/src COPY ./src /app CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
解决方案
1. 修复Headless模式启动问题
Docker环境无XServer,必须显式开启headless,同时添加Docker适配的启动参数:
修改核心代码中的浏览器启动部分:
browser = p.chromium.launch( headless=True, args=[ "--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage", "--disable-gpu", "--window-size=1920,1080" ] )
--no-sandbox/--disable-setuid-sandbox:Docker下必须关闭沙箱,否则Chromium无法启动--disable-dev-shm-usage:解决Docker中共享内存不足导致的浏览器崩溃--disable-gpu:无GPU环境下禁用GPU加速--window-size:模拟真实窗口尺寸,规避目标网站的小窗口反爬策略
2. 解决net::ERR_EMPTY_RESPONSE与超时问题
目标网站大概率检测到了headless浏览器,需模拟真实浏览器环境:
步骤1:添加浏览器上下文模拟参数
在创建page前,先创建上下文并配置用户代理等信息:
context = browser.new_context( user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', viewport={'width': 1920, 'height': 1080}, ignore_https_errors=True # 忽略HTTPS证书问题(可选) ) page = context.new_page()
步骤2:优化页面加载策略
将默认的wait_until="load"改为等待网络空闲,同时延长超时时间:
page.goto( url='https://book.flygofirst.com/Flight/Select?inl={}&CHD={}&s=True&o1={}&d1={}&ADT={}&dd1={}&gl=0&glo=0&cc=INR&mon=true'.format(self.infants, self.children, self.origin, self.destination, self.adults, self.date), wait_until="networkidle", # 等待500ms内无网络请求 timeout=60000 # 超时时间设为60秒 )
步骤3:添加模拟交互(可选)
若网站反爬严格,可在加载前添加小延迟或模拟鼠标移动:
page.wait_for_timeout(1000) # 等待1秒 page.mouse.move(100, 100) # 模拟鼠标移动
3. 优化Dockerfile配置
修正路径问题并精简配置:
FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 复制依赖文件(避免多层相对路径错误) COPY requirements/dev.txt . # 安装依赖与Playwright RUN python3 -m ensurepip && \ pip install --no-cache-dir -r dev.txt && \ playwright install chromium && \ playwright install-deps chromium # 设置PYTHONPATH ENV PYTHONPATH="${PYTHONPATH}:/app" # 复制源代码 COPY src/ . # 生产环境移除--reload,减少资源占用 CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
4. 验证步骤
- 本地测试修改后的headless模式代码,确认能正常抓取
- 重新构建Docker镜像并运行,检查报错是否消失
内容的提问来源于stack exchange,提问作者Daniel Avigdor

