pyspider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI。采用Python语言编写,分布式架构,支持多种数据库后端,强大的WebUI支持脚本编辑器,任务监视器,项目管理器以及结果查看器。python
最近有项目须要爬虫支撑,须要抓取的站点繁多,但数据量较小,决定使用pyspider来作数据抓取。考虑到单机性能和可用性问题,最后使用Docker分布式部署了pyspider,到目前为止的半年时间里运行良好。本文主要介绍一下我搭建流程,以及遇到的问题以及解决办法。linux
pyspider
的框架设计在官方文档中已经介绍的很清楚了,"以去重调度,队列,抓取,异常处理,监控等功能做为框架,提供给抓取脚本,并保证灵活性。最后加上webUI的编辑调试环境,以及web任务监控,即成为了这套框架。 git
pyspider
中由
scheduler
负责任务调度,
fetcher
和
processor
负责数据抓取和解析输出。除了
scheduler
是单点部署,
fetcher
、
processor
和
webui
均可以多实例分布式部署。所以咱们能够将
scheduler
部署在一台机器上,负责全部爬虫任务的调度,
fetcher
和
processor
部署到其余机器进行数据抓取和解析输出。
事实上做者在DockerHub上提供了基于python2的镜像,由于有项目须要我就从新构建了基于python3的镜像,并引入一些本身的类库。DockerFile以下:github
FROM python:3.6
MAINTAINER LieFeng "buqx@foxmail.com"
# copy本身的一些代码到环境中
#$COPY . /spider
#WORKDIR /spider
# install phantomjs
RUN mkdir -p /opt/phantomjs \ && cd /opt/phantomjs \
&& wget -O phantomjs.tar.bz2 https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 \
&& tar xavf phantomjs.tar.bz2 --strip-components 1 \
&& ln -s /opt/phantomjs/bin/phantomjs /usr/local/bin/phantomjs \
&& rm phantomjs.tar.bz2
RUN ["pip","install","wsgidav==2.4.1"]
RUN ["pip","install","pyspider"]
RUN ["pip","install","sqlalchemy"]
RUN ["pip","install","redis"]
RUN ["pip","install","psycopg2"]
VOLUME ["/opt/pyspider"]
ENTRYPOINT ["pyspider"]
EXPOSE 5000 23333 24444 25555
复制代码
build镜像,我把镜像命名为buqx/pyspider
,后面的部署都是基于这个镜像来作的。web
在部署说明里咱们能够将scheduler
部署在一台机器上,负责全部爬虫任务的调度。这台机器我称为主节点,除了部署scheduler
以外,我还将pyspider
的project、task、result数据库和消息队列部署在这台机器上。redis
pyspider有三个数据库(projectdb\taskdb\resultdb)和一个消息队列,数据库我使用了PostgreSQL,消息队列使用Redis。咱们使用docker来部署它们。sql
为了使用统一的网络接口,咱们首先使用docker 建立pyspider network。docker
$ docker network create --driver bridge pyspider
复制代码
使用docker部署PostgreSQL,这里须要注意的是端口绑定的问题,postgres默认端口是5432,因此无论绑定到外部那个端口,docker容器内必定要使用5432端口,除非你手动修改了它shell
$ docker run --network=pyspider --name postgres \
-v ~/data/postgres/:/var/lib/postgresql/data \
-d -p $LOCAL_IP:5432:5432 -e POSTGRES_PASSWORD="" postgres
复制代码
进入postgres容器,新建数据库用户spider,新建数据库:projectdb、taskdb和resultdb数据库
使用docker部署Redis
$ docker run --network=pyspider --name redis -d -p 6379:6379 redis
复制代码
docker命令以下,其中buqx/pyspider
是我镜像名称,spider@192.168.34.203
是数据库用户名和机器的内网IP
$ docker run --network=pyspider --name scheduler -d -p 23333:23333 --restart=always buqx/pyspider --taskdb "sqlalchemy+postgresql+taskdb://spider@192.168.34.203:5431/taskdb" --resultdb "sqlalchemy+postgresql+resultdb://spider@192.168.34.203:5431/resultdb" --projectdb "sqlalchemy+postgresql+projectdb://spider@192.168.34.203:5431/projectdb" --message-queue "redis://192.168.34.203:6379/1" scheduler --inqueue-limit 5000 --delete-time 43200
复制代码
完成上面的操做后,能够在主节点上看到启动了9个容器,以下图。
咱们经过docker-compose来编排fetcher
、webui
、processor
容器,docker-compose.yml文件以下:
version: "2"
services:
phantomjs:
image: 'buqx/pyspider:latest'
command: phantomjs
cpu_shares: 256
environment:
- 'EXCLUDE_PORTS=5000,23333,24444'
expose:
- '25555'
mem_limit: 256m
restart: always
phantomjs-lb:
image: 'dockercloud/haproxy:latest'
links:
- phantomjs
volumes:
- ~/docker/volumes/docker.sock:/var/run/docker.sock
restart: always
fetcher:
image: 'buqx/pyspider:latest'
command: '--message-queue "redis://192.168.34.203:6379/1" --phantomjs-proxy "phantomjs:80" fetcher --xmlrpc'
cpu_shares: 256
environment:
- 'EXCLUDE_PORTS=5000,25555,23333'
links:
- 'phantomjs-lb:phantomjs'
mem_limit: 256m
restart: always
fetcher-lb:
image: 'dockercloud/haproxy:latest'
links:
- fetcher
volumes:
- ~/docker/volumes/docker.sock:/var/run/docker.sock
restart: always
processor:
image: 'buqx/pyspider:latest'
command: '--projectdb "sqlalchemy+postgresql+projectdb://spider:123@192.168.34.203:5431/projectdb" --message-queue "redis://192.168.34.203:6379/1" processor'
cpu_shares: 256
mem_limit: 256m
restart: always
result-worker:
image: 'buqx/pyspider:latest'
command: '--taskdb "sqlalchemy+postgresql+taskdb://spider:123@192.168.34.203:5431/taskdb" --projectdb "sqlalchemy+postgresql+projectdb://spider:123@192.168.34.203:5431/projectdb" --resultdb "sqlalchemy+postgresql+resultdb://spider:123@192.168.34.203:5431/resultdb" --message-queue "redis://192.168.34.203:6379/1" result-worker'
cpu_shares: 256
mem_limit: 256m
restart: always
webui:
image: 'buqx/pyspider:latest'
command: '--phantomjs-proxy "phantomjs:25555" --taskdb "sqlalchemy+postgresql+taskdb://spider:123@192.168.34.203:5431/taskdb" --projectdb "sqlalchemy+postgresql+projectdb://spider:123@192.168.34.203:5431/projectdb" --resultdb "sqlalchemy+postgresql+resultdb://spider:123@192.168.34.203:5431/resultdb" --message-queue "redis://192.168.34.203:6379/1" webui --scheduler-rpc "http://192.168.34.203:23333/" '
cpu_shares: 256
environment:
- 'EXCLUDE_PORTS=24444,25555,23333'
ports:
- '5288:5000'
links:
- 'fetcher-lb:fetcher'
mem_limit: 256m
restart: always
networks:
default:
external:
name: pyspider
复制代码
使用docker-compose up
启动全部容器,经过docker container ls
查看启动的容器,能够看到下图中的九容器正在运行(子节点机器上装了portainer
,图是从portainer截取的),访问http://子节点IP:5288/ 进入pyspider控制台。
self.crawl 添加 fetch_type=‘js’ 参数,出现
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/pyspider/libs/base_handler.py", line 188, in run_task
result = self._run_task(task, response)
File "/usr/local/lib/python2.7/dist-packages/pyspider/libs/base_handler.py", line 167, in _run_task
response.raise_for_status()
File "/usr/local/lib/python2.7/dist-packages/pyspider/libs/response.py", line 190, in raise_for_status
raise http_error
HTTPError: 501 Server Error
复制代码
解决:参考https://github.com/binux/pyspider/issues/432解决,修改compose file 在webui 的command 增长“--phantomjs-proxy "phantomjs:25555 ”
webui:
image: 'buqx/pyspider:latest'
command: '--phantomjs-proxy "phantomjs:25555" --taskdb "sqlalchemy+postgresql+taskdb://spider:123@192.168.34.203:5431/taskdb" --projectdb "sqlalchemy+postgresql+projectdb://spider:123@192.168.34.203:5431/projectdb" --resultdb "sqlalchemy+postgresql+resultdb://spider:123@192.168.34.203:5431/resultdb" --message-queue "redis://192.168.34.203:6379/1" webui --scheduler-rpc "http://192.168.34.203:23333/" '
cpu_shares: 256
environment:
- 'EXCLUDE_PORTS=24444,25555,23333'
ports:
- '5288:5000'
links:
- 'fetcher-lb:fetcher'
mem_limit: 256m
restart: always
复制代码