13.12-Scrapy对接Docker

环境配置问题可能一直是我们头疼的,我们可能遇到过如下的情况:

  • 我们在本地写好了一个 Scrapy 爬虫项目,想要把它放到服务器上运行,但是服务器上没有安装 Python 环境。

  • 别人给了我们一个 Scrapy 爬虫项目,项目中使用包的版本和我们本地环境版本不一致,无法直接运行。

  • 我们需要同时管理不同版本的 Scrapy 项目,如早期的项目依赖于 Scrapy 0.25,现在的项目依赖于 Scrapy 1.4.0。

在这些情况下,我们需要解决的就是环境的安装配置、环境的版本冲突解决等问题。

对于 Python 来说,VirtualEnv 的确可以解决版本冲突的问题。但是,VirtualEnv 不太方便做项目部署,我们还是需要安装 Python 环境,

如何解决上述问题呢?答案是用 Docker。Docker 可以提供操作系统级别的虚拟环境,一个 Docker 镜像一般都包含一个完整的操作系统,而这些系统内也有已经配置好的开发环境,如 Python 3.6 环境等。

我们可以直接使用此 Docker 的 Python 3 镜像运行一个容器,将项目直接放到容器里运行,就不用再额外配置 Python 3 环境。这样就解决了环境配置的问题。

我们也可以进一步将 Scrapy 项目制作成一个新的 Docker 镜像,镜像里只包含适用于本项目的 Python 环境。如果要部署到其他平台,只需要下载该镜像并运行就好了,因为 Docker 运行时采用虚拟环境,和宿主机是完全隔离的,所以也不需要担心环境冲突问题。

如果我们能够把 Scrapy 项目制作成一个 Docker 镜像,只要其他主机安装了 Docker,那么只要将镜像下载并运行即可,而不必再担心环境配置问题或版本冲突问题。

接下来,我们尝试把一个 Scrapy 项目制作成一个 Docker 镜像。

1. 本节目标

我们要实现把前文 Scrapy 的入门项目打包成一个 Docker 镜像的过程。项目爬取的网址为:http://quotes.toscrape.com/,本章 Scrapy 入门一节已经实现了 Scrapy 对此站点的爬取过程,项目代码为:https://github.com/Python3WebSpider/ScrapyTutorial,如果本地不存在的话可以 Clone 下来。

2. 准备工作

请确保已经安装好 Docker 和 MongoDB 并可以正常运行,如果没有安装可以参考第 1 章的安装说明。

3. 创建 Dockerfile

首先在项目的根目录下新建一个 requirements.txt 文件,将整个项目依赖的 Python 环境包都列出来,如下所示:

scrapy
pymongo

如果库需要特定的版本,我们还可以指定版本号,如下所示:

scrapy>=1.4.0
pymongo>=3.4.0

在项目根目录下新建一个 Dockerfile 文件,文件不加任何后缀名,修改内容如下所示:

FROM python:3.6
ENV PATH /usr/local/bin:$PATH
ADD . /code
WORKDIR /code
RUN pip3 install -r requirements.txt
CMD scrapy crawl quotes

第一行的 FROM 代表使用的 Docker 基础镜像,在这里我们直接使用 python:3.6 的镜像,在此基础上运行 Scrapy 项目。

第二行 ENV 是环境变量设置,将 /usr/local/bin:$PATH 赋值给 PATH,即增加 /usr/local/bin 这个环境变量路径。

第三行 ADD 是将本地的代码放置到虚拟容器中。它有两个参数:第一个参数是.,代表本地当前路径;第二个参数是 /code,代表虚拟容器中的路径,也就是将本地项目所有内容放置到虚拟容器的 /code 目录下,以便于在虚拟容器中运行代码。

第四行 WORKDIR 是指定工作目录,这里将刚才添加的代码路径设成工作路径。这个路径下的目录结构和当前本地目录结构是相同的,所以我们可以直接执行库安装命令、爬虫运行命令等。

第五行 RUN 是执行某些命令来做一些环境准备工作。由于 Docker 虚拟容器内只有 Python 3 环境,而没有所需要的 Python 库,所以我们运行此命令来在虚拟容器中安装相应的 Python 库如 Scrapy,这样就可以在虚拟容器中执行 Scrapy 命令了。

第六行 CMD 是容器启动命令。在容器运行时,此命令会被执行。在这里我们直接用 scrapy crawl quotes 来启动爬虫。

4. 修改 MongoDB 连接

接下来我们需要修改 MongoDB 的连接信息。如果我们继续用 localhost 是无法找到 MongoDB 的,因为在 Docker 虚拟容器里 localhost 实际指向容器本身的运行 IP,而容器内部并没有安装 MongoDB,所以爬虫无法连接 MongoDB。

这里的 MongoDB 地址可以有如下两种选择。

  • 如果只想在本机测试,我们可以将地址修改为宿主机的 IP,也就是容器外部的本机 IP,一般是一个局域网 IP,使用 ifconfig 命令即可查看。

  • 如果要部署到远程主机运行,一般 MongoDB 都是可公网访问的地址,修改为此地址即可。

在本节中,我们的目标是将项目打包成一个镜像,让其他远程主机也可运行这个项目。所以我们直接将此处 MongoDB 地址修改为某个公网可访问的远程数据库地址,修改 MONGO_URI 如下所示:

MONGO_URI = 'mongodb://admin:admin123@120.27.34.25:27017'

此处地址可以修改为自己的远程 MongoDB 数据库地址。

这样项目的配置就完成了。

5. 构建镜像

接下来我们便可以构建镜像了,执行如下命令:

docker build -t quotes:latest .

这样的输出就说明镜像构建成功。这时我们查看一下构建的镜像,如下所示:

Sending build context to Docker daemon 191.5 kB
Step 1/6 : FROM python:3.6
---> 968120d8cbe8
Step 2/6 : ENV PATH /usr/local/bin:$PATH
---> Using cache
---> 387abbba1189
Step 3/6 : ADD . /code
---> a844ee0db9c6
Removing intermediate container 4dc41779c573
Step 4/6 : WORKDIR /code
---> 619b2c064ae9
Removing intermediate container bcd7cd7f7337
Step 5/6 : RUN pip3 install -r requirements.txt
---> Running in 9452c83a12c5
...
Removing intermediate container 9452c83a12c5
Step 6/6 : CMD scrapy crawl quotes
---> Running in c092b5557ab8
---> c8101aca6e2a
Removing intermediate container c092b5557ab8
Successfully built c8101aca6e2a

出现类似输出就证明镜像构建成功了,这时执行如我们查看一下构建的镜像:

docker images

返回结果中其中有一行就是:

quotes latest 41c8499ce210 2 minutes ago 769 MB

这就是我们新构建的镜像。

6. 运行

我们可以先在本地测试运行,执行如下命令:

docker run quotes

这样我们就利用此镜像新建并运行了一个 Docker 容器,运行效果完全一致,如图 13-29 所示。

图 13-32 运行结果

如果出现类似图 13-29 的运行结果,这就证明构建的镜像没有问题。

7. 推送至 Docker Hub

构建完成之后,我们可以将镜像 Push 到 Docker 镜像托管平台,如 Docker Hub 或者私有的 Docker Registry 等,这样我们就可以从远程服务器下拉镜像并运行了。

以 Docker Hub 为例,如果项目包含一些私有的连接信息(如数据库),我们最好将 Repository 设为私有或者直接放到私有的 Docker Registry。

首先在 https://hub.docker.com 注册一个账号,新建一个 Repository,名为 quotes。比如,我的用户名为 germey,新建的 Repository 名为 quotes,那么此 Repository 的地址就可以用 germey/quotes 来表示。

为新建的镜像打一个标签,命令如下所示:

docker tag quotes:latest germey/quotes:latest

推送镜像到 Docker Hub 即可,命令如下所示:

docker push germey/quotes

Docker Hub 便会出现新推送的 Docker 镜像了,如图 13-30 所示。

图 13-30 推送结果

如果我们想在其他的主机上运行这个镜像,主机上装好 Docker 后,可以直接执行如下命令:

docker run germey/quotes

这样就会自动下载镜像,然后启动容器运行,不需要配置 Python 环境,不需要关心版本冲突问题。

运行效果如图 13-31 所示:

图 13-31 运行效果

整个项目爬取完成后,数据就可以存储到指定的数据库中。

8. 结语

我们讲解了将 Scrapy 项目制作成 Docker 镜像并部署到远程服务器运行的过程。使用此种方式,我们在本节开头所列出的问题都迎刃而解。