scrapy_redis 和 docker 實現簡單分佈式爬蟲

簡介

在使用 scrapy 爬取 IT桔子公司信息,用來進行分析,瞭解 IT 創業公司的一切狀況,以前使用 scrapy 寫了一個默認線程是10的單個實例,爲了防止被 ban IP 設置了下載的速度,3萬多個公司信息爬了1天多才完成,如今想到使用分佈式爬蟲來提升效率。python

源碼githupmysql

技術工具:Python3.5 scrapy scrapy_redis redis docker1.12 docker-compose Kitematic mysql SQLAlchemy

準備工做

  1. 安裝 Docker 點這裏去了解、安裝;git

  2. pip install scrapy scrapy_redis;github

代碼編寫

  1. 分析頁面信息:
    我須要獲取的是每個「公司」的詳情頁面連接 和 分頁按鈕連接;redis

  2. 統一存儲獲取到的連接,提供給多個 spider 爬取;sql

  3. 多個 spider 共享一個 redis list 中的連接;docker

目錄結構圖

圖片描述

juzi_spider.py

# coding:utf-8

from bs4 import BeautifulSoup
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule

from scrapy_redis.spiders import RedisCrawlSpider
from itjuzi_dis.items import CompanyItem


class ITjuziSpider(RedisCrawlSpider):
    name = 'itjuzi_dis'
    allowed_domains = ['itjuzi.com']
    # start_urls = ['http://www.itjuzi.com/company/157']
    redis_key = 'itjuziCrawler:start_urls'
    rules = [
        # 獲取每一頁的連接
        Rule(link_extractor=LinkExtractor(allow=('/company\?page=\d+'))),
        # 獲取每個公司的詳情
        Rule(link_extractor=LinkExtractor(allow=('/company/\d+')), callback='parse_item')
    ]

    def parse_item(self, response):
        soup = BeautifulSoup(response.body, 'lxml')

         .
         .省略一些處理代碼
         .
        return item

說明:dom

  1. class 繼承了RedisCrawlSpider 而不是CrawlSpiderscrapy

  2. start_urls 改成一個自定義的 itjuziCrawler:start_urls,這裏的itjuziCrawler:start_urls 就是做爲全部連接存儲到 redis 中的 key,scrapy_redis 裏也是經過redislpop方法彈出並刪除連接的;分佈式

db_util.py

使用 SQLAlchemy 做爲 ORM 工具,當表結構不存在時,自動建立表結構

middlewares.py

增長了不少 User-Agent,每個請求隨機使用一個,防止防止網站經過 User-Agent 屏蔽爬蟲

settings.py

配置middlewares.py scrapy_redis redis 連接相關信息

部署

在上面的「目錄結構圖」中有,Dockerfiledocker-compose.yml

Dockerfile

FROM python:3.5
ENV PATH /usr/local/bin:$PATH
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
COPY spiders.py /usr/local/lib/python3.5/site-packages/scrapy_redis
CMD /usr/local/bin/scrapy crawl itjuzi_dis

說明:

  • 使用 python3.5做爲基礎鏡像

  • /usr/local/bin設置環境變量

  • 映射 hostcontainer 的目錄

  • 安裝 requirements.txt

  • 特別要說明的是COPY spiders.py /usr/local/lib/python3.5/site-packages/scrapy_redis,將 host 中的 spiders.py 拷貝到container 中的 scrapy_redis 安裝目錄中,由於 lpop 獲取redis 的值在 python2中是 str 類型,而在 python3中是 bytes 類型,這個問題在 scrapy_reids 中須要修復,spiders.py 第84行須要修改;

  • 啓動後當即執行爬行命令 scrapy crawl itjuzi_dis

docker-compose.yml

version: '2'
services:
  spider:
    build: .
    volumes:
     - .:/code
    links:
     - redis
    depends_on:
     - redis
  redis:
    image: redis
    ports:
    - "6379:6379"

說明:

  • 使用第2版本的 compose 描述語言

  • 定義了 spiderredis 兩個 service

  • spider默認使用當前目錄的 Dockerfile 來建立,redis使用 redis:latest 鏡像建立,並都映射6379端口

開始部署

啓動 container

docker-compose up #從 docker-compose.yml 中建立 `container` 們
docker-compose scale spider=4 #將 spider 這一個服務擴展到4個,仍是同一個 redis

能夠在 Kitematic GUI 工具中觀察建立和運行狀況;

圖片描述

在沒有設置 start_urls 時,4個 container 中的爬蟲都處於飢渴的等待狀態

圖片描述

如今給 redis 中放入 start_urls:

lpush itjuziCrawler:start_urls http://www.itjuzi.com/company

4個爬蟲都動起來了,一直爬到start_urls爲空
圖片描述

以上です!ありがとうございました!

相關文章
相關標籤/搜索