一.部署前的准备

在开始部署之前,先梳理一下几个关键词:

1.Scrapy

Scrapy是一个基于Twisted的异步处理框架,是纯Python实现的爬虫框架。Scrapy由Spider、Middleware、Downloader、Pipeline等组成,各个模块之间耦合度低,扩展性强。Scrapy的整体结构如下:


Dockerfile中安装scrapy docker scrapy_scrapyd

图1:Scrapy架构

 

2.Scrapyd

Scrapyd是一个用于部署和运行scrapy项目的工具,通过Scrapyd可以将已经写好的Scrapy项目上传到云主机并通过scrapyd提供的Restful API来控制它们的运行。

3.Scrapyd-Client

在将Scrapy代码部署到远程Scrapyd的时候,第一步就是要将代码打包为EGG文件(EGG是二进制文件),其次需要将EGG文件上传到云主机。这个过程可以使用程序实现,也可以使用Scrapyd-Client来实现。


Dockerfile中安装scrapy docker scrapy_配置文件_02

图2:Scrapyd-Client和Scrapyd的通信

 以图2为例子,客户端做的有两个操作:

  1. 通过Scrapyd-Client打包Scrapy项目并发送到对应的已经在运行Scrapyd进程的服务器上;
  2. 客户端通过发送HTTP请求来获取或者控制爬虫的运行。

二.Scrapyd的Docker化

在把Scrapyd放入容器之前,首先要考虑需要什么。

1.scrapyd的运行依赖库

需要一个requirements.txt文件来安装scrapyd的依赖文件,解决办法是在本地开发scrapy的时候使用到python的虚拟环境,比如virtualenv,以便于版本控制和导出requirements.txt。

对于开发来说,环境配置一直就是个问题,最大的问题就是版本不一致。在Python中,可以使用virtualenv来解决上面的问题,但是virtualenv对于项目部署来说并不方便,而此时使用Docker则是更好的选择。

项目链接:https://github.com/sky94520/ScrapyTutorial

上面的项目为scrapy的一个简例,它的任务就是爬取http://quotes.toscrape.com/网站的名言,并把这些数据存储到mongodb中去。如果对mongodb不熟悉的可以改为存在csv文件或者json文件中,只需要添加一个对应的pipeline即可。 

上面的这个例子包含了两个标签(tag):mongodbjson。mongodb标签将会把数据保存到mongodb中;而json标签将会把数据保存到quotes.json文件中。

使用git clone https://github.com/sky94520/ScrapyTutorial.git 把项目从github中克隆下来;然后在控制台中切换到对应的标签,比如这里要切换到json标签,需要键入:

git checkout json


Dockerfile中安装scrapy docker scrapy_scrapyd_03

图3:ScrapyTutorial项目结构

这里使用的是windows环境下的cmd。在项目根目录下,使用下面的命令进入到虚拟环境下:

venv\Scripts\activate

如果执行成功的话会出现下面这样:


Dockerfile中安装scrapy docker scrapy_scrapyd_04

图4:虚拟环境

 此时无论是执行python文件、还是安装/卸载库都是只会影响这个虚拟环境。

接着就可以导出该环境下的依赖库文件:

pip freeze > requirements.txt

 requirements.txt文件显示如下:

asn1crypto==0.24.0
attrs==19.1.0
Automat==0.7.0
cffi==1.12.3
constantly==15.1.0
cryptography==2.6.1
cssselect==1.0.3
hyperlink==19.0.0
idna==2.8
incremental==17.5.0
lxml==4.3.3
parsel==1.5.1
pyasn1==0.4.5
pyasn1-modules==0.2.5
pycparser==2.19
PyDispatcher==2.0.5
PyHamcrest==1.9.0
pymongo==3.8.0
pyOpenSSL==19.0.0
pywin32==224
queuelib==1.5.0
Scrapy==1.6.0
service-identity==18.1.0
six==1.12.0
Twisted==18.9.0
w3lib==1.20.0
zope.interface==4.6.0

注:Twisted的版本为18.9.0,scrapy的版本为scrapy==1.6.0,否则scrapyd的网页访问将会出错。 另外,在虚拟环境下输入deactivate表示退出虚拟环境。


 2.外网可以访问Scrapyd

可以参考官方网站https://scrapyd.readthedocs.io/en/latest/config.html,要了解的主要包括配置文件和配置文件的路径;由于这里使用的是ubuntu,所以配置文件放在/etc/scrapyd/目录下,配置文件scrapyd.conf内容如下:

[scrapyd]
eggs_dir    = eggs
logs_dir    = logs
items_dir   =
jobs_to_keep = 5
dbs_dir     = dbs
max_proc    = 0
max_proc_per_cpu = 4
finished_to_keep = 100
poll_interval = 5.0
bind_address = 0.0.0.0
http_port   = 6800
debug       = off
runner      = scrapyd.runner
application = scrapyd.app.application
launcher    = scrapyd.launcher.Launcher
webroot     = scrapyd.website.Root

[services]
schedule.json     = scrapyd.webservice.Schedule
cancel.json       = scrapyd.webservice.Cancel
addversion.json   = scrapyd.webservice.AddVersion
listprojects.json = scrapyd.webservice.ListProjects
listversions.json = scrapyd.webservice.ListVersions
listspiders.json  = scrapyd.webservice.ListSpiders
delproject.json   = scrapyd.webservice.DeleteProject
delversion.json   = scrapyd.webservice.DeleteVersion
listjobs.json     = scrapyd.webservice.ListJobs
daemonstatus.json = scrapyd.webservice.DaemonStatus

 上面的是官方提供的一个配置文件,这里的修改仅仅是把bind_address由127.0.0.1修改为了0.0.0.0,以使得外网可以访问scrapyd。

3.Docker镜像

接下来则是Dockerfile的编写了。

首先可以在云服务器上/home/下创建一个scrapy_test来保存配置文件和Dockerfile。项目结构如下:


Dockerfile中安装scrapy docker scrapy_Dockerfile中安装scrapy_05

图5:目录结构

在图5中,Dockerfile为构建docker镜像的配置文件;requirements.txt为 scrapyd所依赖的环境;而scrapyd.conf则是scrapyd运行所需的配置文件。

Dockerfile文件内容如下:

FROM python:3.7
ENV REFRESHED_AT 2019-05-30
ENV PATH /usr/local/bin:$PATH

#add the scrapyd configure file
ADD ./scrapyd.conf /etc/scrapyd/scrapyd.conf

#add requirements.txt
ADD requirements.txt /opt/requirements.txt
WORKDIR /opt

#use other fast image
RUN pip3 install  -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt

CMD ["scrapyd"]

EXPOSE 6800

 首先,这个镜像是基于python3.7的,所以需要先拉取镜像:

docker pull python:3.7

 其次,在环境中设置了一个REFRESHED_AT变量,由于docker build运行Dockerfile是每一个指令创建一个镜像的,而指令内容的变化会使得从它开始的镜像全都重新生成,所以可以通过修改REFRESHED_AT来控制镜像的更新。

之后,把scrapyd.conf放到了/etc/scrapyd/目录下,而requirements.txt 放到了/opt/目录下(放在其他目录也可以),然后设置/opt为工作路径,之后使用pip来安装依赖环境。为了使得pip下载库更快一些而使用了清华的镜像;

最后的CMD则是可以在docker run不添加命令的时候直接启动scrapyd,最后则是暴露的6800端口。

然后就可以在本文件夹中使用docker build来构建镜像了:

docker build -t xiaoniu/scrapyd .

 构建成功后可以查看镜像:

docker images

 


Dockerfile中安装scrapy docker scrapy_Dockerfile中安装scrapy_06

图6:查看镜像

最后则是运行:

docker run -d -p 6800:6800 --name=scrapyd xiaoniu/scrapyd

 -p 6800:6800表示的是开放容器的6800端口(这里要确保主机的6800端口没有被占用),并把它和外部服务器的6800端口对应起来。

 之后输入:

docker ps -l

 显示:


Dockerfile中安装scrapy docker scrapy_配置文件_07

图7:查看容器运行状态

可以看到我们创建的镜像已经在运行了,并且开放了6800端口。 

三.测试环境

如果服务器的6800端口已经开放(阿里云需要手动开放端口),则可以直接在浏览器访问到scrapyd:


Dockerfile中安装scrapy docker scrapy_scrapyd_08

图8:查看scrapyd提供的网页

 注意:如果scrapy和Twisted的版本不正确的话,Job网页会出现错误.

四.Scrapyd-Client的安装与操作

在终端环境下输入下面的指令来安装scrapyd-client:

pip install scrapyd-client

 scrapyd-client的安装最好是在非虚拟环境下,从图2中可以看出,我们使用这个库仅仅是为了打包scrapy项目并发送给服务器,所以没必要在虚拟环境下安装。

安装成功后会有一个可用的命令,叫做scrapyd-deploy,不过在windows下这个命令是无法直接用的。

首先,需要确定python的安装位置,我这里的安装路径为:

C:\Users\lbb\AppData\Local\Programs\Python\Python37\Scripts

在这里应该可以看到dcrapyd-deploy这个文件:


Dockerfile中安装scrapy docker scrapy_scrapyd_09

图9:目录

 通过ubuntu的file命令(win10的应用商店中可以安装ubuntu),可以稍微了解到这个文件的类型:


Dockerfile中安装scrapy docker scrapy_json_10

图10:查看scrapyd-deploy文件类型

 如果想执行的话,那么还需要一个批处理文件scrapy-deploy.bat来执行这个python脚本:

@echo off

"C:\Users\lbb\AppData\Local\Programs\Python\Python37\python.exe" "C:\Users\lbb\AppData\Local\Programs\Python\Python37\Scripts\scrapyd-deploy" %1 %2 %3 %4 %5 %6 %7 %8 %9

注意:请根据自己的安装路径然后修改scrapy-deploy.bat脚本的路径。 

 接着就可以打包并发送scrapy文件了。回到ScrapyTutorial的项目根目录下,打开scrapy.cfg文件:

[settings]
default = tutorial.settings

[deploy:demo]
url = http://localhost:6800/
project = tutorial

把url的值改为自己的服务器的IP地址。然后在项目根目录下打开控制台,输入:

scrapyd-deploy demo -p tutorial

 如果结果如下,则表示上传到服务器成功!


Dockerfile中安装scrapy docker scrapy_scrapyd_11

图11:上传到服务器

接着可以在IP:6800上查看:


Dockerfile中安装scrapy docker scrapy_docker_12

图12:显示可用工程

五.发起操作

从图12中可以看到,scrapyd通过HTTP来发送请求的,而curl也可以发送HTTP请求,所以示例中使用到了curl。这里同样以curl为例,注意把以下命令的localhost改为服务器的IP地址。

1.获取服务器状态

curl http://localhost:6800/daemonstatus.json

 


Dockerfile中安装scrapy docker scrapy_docker_13

图13:显示服务器状态

2.运行爬虫

curl http://localhost:6800/schedule.json -d project=tutorial -d spider=quotes

 


Dockerfile中安装scrapy docker scrapy_Dockerfile中安装scrapy_14

图14:运行爬虫

 此时再看scrapyd的Jobs:


Dockerfile中安装scrapy docker scrapy_Dockerfile中安装scrapy_15

图15:爬虫工作情况

能够发现开启的爬虫已经运行完毕,总共运行了8秒左右。 

更多的命令请参考:https://scrapyd.readthedocs.io/en/latest/api.html

六.反向代理+身份验证

配置完成后,Scrapyd和它的接口都是可以公开访问的。如果想配置访问认证的话,可以借助于Nginx做反向代理。

云服务器下docker部署scrapyd之二:使用Nginx对Scrapyd添加验证

七.总结

1.curl的作用可以简单的认为和浏览器的作用差不多。

2.可以专门创建一个容器来对爬虫进行管理,比如定时定点开启爬虫,这对于scrapyd是可以做到的。比如周一的凌晨2点到3点开始爬取数据,那么我可以把这些数据写入到容器的一个配置文件里,然后在这个容器里开启一个进程,让它一直检测这个配置文件,来判断是否需要开启或者关闭爬虫。

3.创建的scrapyd容器的requirements.txt仅仅包含了必要的库,它并不能满足所有的情况,如果一个其他的scrapy项目需要用到第三方库,那么在上传的时候没有问题,但是在运行的时候则会因为找不到这个库而出错。解决办法就是需要进入到scrapyd容器中手动加入某些库。

 

参考链接:

Scrapyd使用教程

scrapyd 问题 builtins.AttributeError: 'int' object has no attribute 'splitlines'

解决python各类库安装包下载太慢速度问题