menu Chancel's blog
rss_feed
Chancel's blog
有善始者实繁,能克终者盖寡。

Docker打包Selenium容器实践

作者:Chancel Yang, 创建:2022-12-27, 字数:2966, 已阅:165, 最后更新:2022-12-27

这篇文章更新于 484 天前,文中部分信息可能失效,请自行甄别无效内容。

Python的Selenium套件对于自动化一些常规网页操作非常好用,但部署是不太省心省力的,在不同的操作系统上安装Chrome与对应版本的driver后还需要进行测试运行,相较于传统的服务器项目部署来说,安装与排错都显得比较费事。

如果将Selenium+Chrome进行Docker部署,那可以大大降低部署难度,更加关注自动化的代码本身,于是有了下面打包Selenium项目(Chrome浏览器)的实践。

1. 前期准备

1.1. web项目

使用Python写一个简单的web项目,代码结构如下

Bash
❯ tree
.
├── requirements.txt
└── web
    └── __init__.py

引入fastapi作为web框架,__init__.py文件内容如下

Python
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello World"}

运行方法

Bash
uvicorn web:app --port=5000

此时访问http://127.0.0.1:5000/可以看到返回 Hello World,Web项目搭建结束

1.2. Selenium

Selenium支持许多浏览器,这里选择Chrome作为模拟的浏览器

Chrome历史版本下载:https://www.slimjet.com

Chromedriver历史版本下载:https://chromedriver.storage.googleapis.com

tips:Chrome版本与Chromedriver版本需对应

安装Chrome后,将chromedriver引入到项目中并修改__init__.py文件如下

Python
import os
from fastapi import FastAPI
from selenium.webdriver.chrome.options import Options
from selenium import webdriver

app = FastAPI()


@app.get("/")
async def root():
    chrome_options = Options()
    # headless 开启无显示模式,Docker容器中没有安装GUI桌面
    chrome_options.add_argument('--headless')
    chrome_options.add_argument("--disable-extensions")
    chrome_options.add_argument("--disable-dev-shm-usage")
    chrome_options.add_argument("--no-sandbox")
    c = webdriver.Chrome(executable_path=os.environ['chromedriver'],options=chrome_options)
    c.get('https://cn.bing.com/')
    return {"biying": c.page_source}

此时项目目录结构如下

Bash
❯ tree
.
├── chromedriver
├── requirements.txt
└── web
    └── __init__.py

再次运行

Bash
uvicorn web:app --port=5000

访问http://127.0.0.1:5000/可以获取到必应的HTML文档

到这里一个selenium的web项目搭建完成,保存当前引用的python包到requirements文件

Bash
pip freeze > requirements.txt

2. Docker

将上面的演示项目打包成Docker容器要考虑如何在容器中安装Python环境与Chrome,这里直接采用python:3.7.4-slim-stretch官网镜像,该镜像是以Debian为系统镜像,所以可以使用apt安装本地的Chrome.deb安装包

tips:这里不宜选版本过高的Chrome,否则在安装的时候可能会缺失一些.so文件,解决起来比较棘手

2.2. Dockerfile文件

从Chrome历史版本中挑选了81.6的Deb安装包与Chromedriver,引入到项目中,Dockerfile文件如下所示

Docker
FROM python:3.7.4-slim-stretch

ENV LANG en_US.UTF-8

WORKDIR /app

COPY ./ /app

RUN apt update && \
apt install -y /app/google-chrome.deb && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
pip install --upgrade pip && \
pip3 install -r /app/requirements.txt && \
chmod +x /app/chromedriver

ENV chromedriver=/app/chromedriver

CMD ["uvicorn", "web:app", "--host=0.0.0.0", "--port=5000"]

此时项目结构如下,新增了google-chrome.deb文件作为镜像安装的chrome浏览器

TEXT
❯ tree
.
├── Dockerfile
├── google-chrome.deb
├── requirements.txt
└── web
    └── __init__.py

打包Docker镜像

Bash
sudo docker build -t hello-world:v22.12.27 . --no-cache

运行Docker容器

Bash
sudo docker run --name hello-world -p 5000:5000 hello-world:v22.12.27

访问http://127.0.0.1:5000/看到必应的HTML文档表示运行成功


[[replyMessage== null?"发表评论":"发表评论 @ " + replyMessage.m_author]]

account_circle
email
web_asset
textsms

评论列表([[messageResponse.total]])

还没有可以显示的留言...
[[messageItem.m_author]] [[messageItem.m_author]]
[[messageItem.create_time]]
[[getEnviron(messageItem.m_environ)]]
[[subMessage.m_author]] [[subMessage.m_author]] @ [[subMessage.parent_message.m_author]] [[subMessage.parent_message.m_author]]
[[subMessage.create_time]]
[[getEnviron(messageItem.m_environ)]]