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個容器,以下圖。
###4. 子節點部署咱們經過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
複製代碼