簡介
在使用 scrapy 爬取 IT桔子公司資訊,用來進行分析,瞭解 IT 創業公司的一切情況,之前使用 scrapy 寫了一個預設執行緒是10的單個例項,為了防止被 ban IP 設定了下載的速度,3萬多個公司資訊爬了1天多才完成,現在想到使用分散式爬蟲來提高效率。
技術工具:Python3.5
scrapy
scrapy_redis
redis
docker1.12
docker-compose
Kitematic
mysql
SQLAlchemy
準備工作
- 安裝
Docker
點這裡去了解、安裝; pip install scrapy scrapy_redis
;
程式碼編寫
- 分析頁面資訊:
我需要獲取的是每一個「公司」的詳情頁面連結 和 分頁按鈕連結; - 統一儲存獲取到的連結,提供給多個
spider
爬取; - 多個
spider
共享一個redis
list
中的連結;
目錄結構圖
juzi_spider.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# 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 |
說明:
class
繼承了RedisCrawlSpider
而不是CrawlSpider
start_urls
改為一個自定義的itjuziCrawler:start_urls
,這裡的itjuziCrawler:start_urls
就是作為所有連結儲存到redis
中的key
,scrapy_redis
裡也是通過redis
的lpop
方法彈出並刪除連結的;
db_util.py
使用 SQLAlchemy
作為 ORM
工具,當表結構不存在時,自動建立表結構
middlewares.py
增加了很多 User-Agent
,每一個請求隨機使用一個,防止防止網站通過 User-Agent
遮蔽爬蟲
settings.py
配置middlewares.py
scrapy_redis
redis
連結相關資訊
部署
在上面的「目錄結構圖」中有,Dockerfile
和docker-compose.yml
Dockerfile
1 2 3 4 5 6 7 |
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
設定環境變數 - 對映
host
和container
的目錄 - 安裝
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
version: '2' services: spider: build: . volumes: - .:/code links: - redis depends_on: - redis redis: image: redis ports: - "6379:6379" |
說明:
- 使用第2版本的
compose
描述語言 - 定義了
spider
和redis
兩個service
spider
預設使用當前目錄的Dockerfile
來建立,redis
使用redis:latest
映象建立,並都對映6379埠
開始部署
啟動 container
1 2 |
docker-compose up #從 docker-compose.yml 中建立 `container` 們 docker-compose scale spider=4 #將 spider 這一個服務擴充套件到4個,還是同一個 redis |
可以在 Kitematic
GUI 工具中觀察建立和執行情況;
在沒有設定 start_urls
時,4個 container
中的爬蟲都處於飢渴的等待狀態
現在給 redis
中放入 start_urls
:
1 |
lpush itjuziCrawler:start_urls http://www.itjuzi.com/company |
4個爬蟲都動起來了,一直爬到start_urls
為空
以上!