Scrapy-redis分布式爬蟲+Docker快速部署

Scrapy-redis分布式爬蟲+Docker快速部署

打算爬一個網(wǎng)站的數(shù)據(jù),量比較大,url鏈接從0開始達到2億,剛開始用request遞歸寫了個爬蟲,發(fā)現(xiàn)速度低的可憐,不算任何的錯誤,也只能達到.5秒一個請求,這速度實在不能忍,所以想著用分布式爬蟲,所以才有了這篇文章


開發(fā)環(huán)境+框架开呐、庫

開發(fā)環(huán)境:macOS High Sierra 10.13 Python3.5
開發(fā)工具:PyCharm
Python庫:pymysql豁跑、scrapy历极、scrapy-redis悄窃、requestsBeautifulSoup4花鹅、redis-py
運行環(huán)境:Centos7.4 Centos6.9 Docker


開始搭建環(huán)境

安裝Python3Windows請自行查找教程安裝、Mac用戶系統(tǒng)自帶了Py2.6,我建議升級到Python3,用HomeBrew安裝即可
Homebrew安裝命令

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

然后使用brew install python安裝Python3
安裝成功后再終端輸入python3查看是否安裝成功,如果輸入python默認使用本機的py2,當然也可以去配置文件設(shè)置個aliaspython設(shè)置成啟動py3

image

如圖安裝成功
然后用easy_install pip安裝Python的包管理工具pip

注意:有的人用的是Anaconda作為py環(huán)境,我剛開始也是用的Anaconda,但是在install scrapy-redis的時候發(fā)現(xiàn)無法導(dǎo)入,默認源都沒有這個庫,但我沒找到哪個源有,所以強制切換了本機環(huán)境為brewpython3,如果你能用conda install scrapy-redis那就不用切換

切換環(huán)境:
在終端輸入which python3

image

將下面的路徑復(fù)制出來
打開FinderCommand + Shift + G輸入~/找到.bash_profile文件
image

如果沒有這個文件的,先看一下是否開啟了顯示隱藏文件功能,沒開始可以使用Command + Shift + .開啟,如果你的系統(tǒng)不是macOS Sierra及之后的系統(tǒng),那么需要使用命令defaults write com.apple.finder AppleShowAllFiles -bool true來開啟隱藏文件功能(需要強制重啟Finder生效)

打開.bash_profile文件

image

Anaconda的環(huán)境變量注釋掉,將brew安裝的寫入進去,路徑就是上面which python3獲得的,最后bin后面換成${PATH}即可,然后輸入source ~/.bash_profile使之立即生效,然后終端查看一下,是否已經(jīng)切換成功(剛開始路徑是anaconda)
image

開始安裝第三方庫
pip install requests scrapy scrapy-redis redis BeautifulSoup4
至此環(huán)境方面的東西已經(jīng)處理完


簡單原理介紹

image

這是在網(wǎng)上找了一張圖,很好的解釋了scrapy-redis原理,我簡單的描述下主要原理
使用redis來維護一個url queue,然后scrapy爬蟲都連接這一個redis獲取url,且當爬蟲在redis處拿走了一個url后,redis會將這個urlqueue中清除,保證不會被2個爬蟲拿到同一個url,即使可能2個爬蟲同時請求拿到同一個url,在返回結(jié)果的時候redis還會再做一次去重處理,所以這樣就能達到分布式效果,我們拿一臺主機做redis queue,然后在其他主機上運行爬蟲.且scrapy-redis會一直保持與redis的連接,所以即使當redis queue中沒有了url,爬蟲會定時刷新請求,一旦當queue中有新的url后,爬蟲就立即開始繼續(xù)爬.

創(chuàng)建工程

打開終端隨便找個空目錄運行scrapy startproject projectname來初始化一個scrapy項目
目錄結(jié)構(gòu)如下

image

Pycharm打開(其他工具也可)
工程需要修改地方主要在于Spidersettings,其他的都和正常Scrapy項目一樣

首先是Spider,我們新建的一般都是繼承與scrapy.Spider,要使用Scrapy-redis需要繼承RedisCrawlSpider,引入from scrapy_redis.spiders import RedisCrawlSpider,且不再需要start_urls,用redis_key來取代

image

修改setting.py,添加以下選項

image

如果需要將item結(jié)果返回到redis需要使用scrapy_redis提供的pipelines,如下
image

其余都按Scrapy正常項目編寫


主服務(wù)器環(huán)境搭建

主要就安裝redis開啟外網(wǎng)訪問
我這里環(huán)境是Centos 6.9
1点骑、直接使用yum安裝
yum install redis
2、啟動redis
systemctl start redis.service
3谍夭、設(shè)置開機啟動(非必要)
systemctl enable redis.service
4黑滴、設(shè)置redis密碼(非必要)
打開文件/etc/redis.conf,找到其中的# requirepass foobared紧索,去掉前面的#袁辈,并把foobared改成你的密碼

如果是本地安裝了redis想測試的話,Mac上啟動redis是使用redis-server命令

image

然后新開個終端使用redis-cli連接
image

服務(wù)器上也是一樣的使用redis-cli連接

注意:服務(wù)器上搭建的redis外網(wǎng)應(yīng)該是無法訪問,需要修改配置文件,如果是Mac運行的話,配置文件路徑在啟動redis的時候會寫,上圖中有,如果是Centos安裝的redis,默認是在/etc/redis/redis.conf下,如果沒有就在redis的安裝目錄下
將下圖標記處的bind 127.0.0.1加上#,然后重啟一下redis外網(wǎng)即可鏈接

image

測試連接
image


子服務(wù)器跑爬蟲

用其他服務(wù)器運行爬蟲(也可以用運行redis的服務(wù)器)
通過ftp、scp等方式將爬蟲上傳至服務(wù)器上
然后在子服務(wù)器上也安裝python3pip
命令依次是
yum install python34
yum install python34-setuptools
easy_install-3.4 pip
yum install -y python34-pip.noarch python34-devel.x86_64
最后一條不安裝的話用pip會出現(xiàn)報錯
然后安裝一下第三方庫
pip install requests scrapy scrapy-redis redis BeautifulSoup4
最后運行爬蟲
scrapy runspider vmSpider.py
最后的參數(shù)是你的Spider名字
如下圖,爬蟲啟動成功,等待url待爬

image


測試

連接主服務(wù)器,往redis中push一條url

image

返回子服務(wù)器可以看到,爬蟲已經(jīng)將我剛剛添加的那條url給請求了
image

且根據(jù)我的提取規(guī)則把我要的數(shù)據(jù)也提取了出來并且也幫我把數(shù)據(jù)返回到了redis
redis里的urls就又是空的了
image

為了對比一下珠漂,我把爬蟲關(guān)掉晚缩,又添加了一條url
可以看到現(xiàn)在url就在redis里了
image

綜上,我們的效果已經(jīng)達到了,可以在多臺服務(wù)器上跑爬蟲了,然后在主服務(wù)器上的redis里會把爬回的數(shù)據(jù)匯總


處理返回的數(shù)據(jù)

scapy-redis把數(shù)據(jù)全部返回到了redis里,我們不可能等它留在那,得想辦法提取出去,我這里是提取到MySQL中,這個我的思路就是,直接在主服務(wù)器上跑個腳本去redis里提取就行了
直接上代碼

import redis
import json
import pymysql
import logging
import time

# mysql
connection = pymysql.connect('127.0.0.1', 'vdata', 'root', 'vdata', 3306)
cursor = connection.cursor()

# redis
pool = redis.ConnectionPool(host='127.0.0.1', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)
r.pipeline()

# log
logging.basicConfig(level=logging.ERROR,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='myapp.log',
                    filemode='a')


while True:
    print('循環(huán)中')
    k,v = r.blpop(['vm:items'])
    result = json.loads(v)
    title = result['title']
    videoid = result['videoid']
    author = result['author']
    fav = result['favorite']
    sql = 'insert into vindex(title, videoid, author,favorite)(select "%s","%s","%s","%s" from dual where not exists(select * from vindex where videoid="%s"))' % (
    title, videoid, author, fav, videoid)
    try:
        n = cursor.execute(sql)
        connection.commit()
        if n == 0:
            print('數(shù)據(jù)已存在...')
    except Exception as err:
        connection.rollback()
        print('插入數(shù)據(jù)庫錯誤,數(shù)據(jù)庫回滾,錯誤信息:' + str(err))
        logging.error(str(title) + '------insert Error:' + str(err))

代碼中關(guān)鍵部分是k,v = r.blpop(['vm:items']),這句會去redis里獲取items list中第一行的值,獲取到了就將redis里的這個值刪除,然后我們存到數(shù)據(jù)庫里,當然我在數(shù)據(jù)庫sql里也做了下重復(fù)數(shù)據(jù)不允許插入,然后我們在服務(wù)器上跑這個腳本就行了

流程就成了爬蟲從redis獲取url,然后返回請求的數(shù)據(jù)到redis,腳本從redis獲取數(shù)據(jù)到mysql存儲.挺完美的,缺點也有,目前沒有做錯誤處理,如果url拿走了沒請求成功就不知道了,下次添加個中間件,把失敗的url也返回到redis,然后根據(jù)狀態(tài)碼重新添加回queue讓爬蟲繼續(xù)爬.


Docker

雖然看上去挺不錯了,但是發(fā)現(xiàn)個問題媳危,我到一臺服務(wù)器上部署的時候荞彼,就得走一遍安裝python``pip第三方庫這樣的流程,雖然也不麻煩,但是感覺還是不夠省事,然后就發(fā)現(xiàn)了Docker
注意:Docker要求Centos內(nèi)核版本要高于3.1,而Centos6.9默認是2.6,查看內(nèi)核命令uname -r

image

如果不是3.1的內(nèi)核裝不上Docker,辦法可以升級內(nèi)核或者升級Centos7,如果只是升級內(nèi)核的話,Docker是無法安裝到最新版本的,但我由于服務(wù)器里數(shù)據(jù)較多,就只選擇升級了內(nèi)核
1、安裝elrepo yum 源(提供內(nèi)核更新待笑、硬件驅(qū)動等軟件源支持)
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-6-8.el6.elrepo.noarch.rpm
2卿泽、內(nèi)核升級
yum --enablerepo=elrepo-kernel -y install kernel-lt
3、修改引導(dǎo)文件
vi /etc/grub.conf
default設(shè)置成0``default=0表示使用第一個內(nèi)核啟動
4滋觉、重啟服務(wù)器
reboot
5签夭、查看內(nèi)核
uname -r看看是否已經(jīng)是3.1以上了

安裝Docker

#安裝 Docker
yum -y install docker

#啟動 Docker 后臺服務(wù)
service docker start

#測試運行 hello-world
docker run hello-world
image

然后我們來讓Docker幫我們自動化,需要使用到Docker Compose做編排服務(wù)
首先安裝一下Docker Compose,這里可以用pip安裝,但使用pip安裝就違背我們的初衷了,還得先裝python,所以我們用官方推薦的方式curl

sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose version 1.22.0, build 1719ceb

先在我們的項目目錄下建立3個文件docker-compose.yml``Dockerfile``requirements.txt
第一個文件docker-compose.yml

version: '3'
services:
  spider:
    build: .
    volumes:
     - .:/code
  • 代表使用V3版本的寫法
  • services(v1版本沒services)
  • 建立一個名為spider的services
  • 用當前目錄下的Dockerfile構(gòu)建服務(wù)
  • 裝載路徑,將當前目錄下的文件裝載到容器的/code目錄下(會自動建立文件夾)

第二個文件Dockerfile

#Python3作為基礎(chǔ)映像
FROM python:3.5
#設(shè)置環(huán)境變量,使用which Python可以查看
ENV PATH=/usr/local/bin:$PATH
#添加當前目錄到容器里
ADD . /code
#設(shè)置容器工作路徑
WORKDIR /code
#安裝Python插件
RUN pip install -r requirements.txt
# #設(shè)置容器工作目錄
WORKDIR /code/vmoredis/vmoredis/spiders
# #運行命令
CMD /usr/local/bin/scrapy runspider vmSpider.py

這里要注意,先設(shè)置工作路徑為/code是為了能運行pip,運行完了再將路徑設(shè)置到Spider下,才能訪問到Spider文件,不然就提示找不到對應(yīng)的py文件

第三個文件requirements.txt

BeautifulSoup4
scrapy
scrapy_redis
redis
pymysql
requests

就是我們需要安裝的python庫


上傳服務(wù)器測試

上傳文件到服務(wù)器,目錄如下

image

cd到根目錄下,運行docker-compose up
注意:這里有個問題,就是我之前測試的時候運行了docker-compose up,后來我換了正式的文件,發(fā)現(xiàn)還是之前的報錯
image

這個test.py是我測試時運行的,現(xiàn)在居然還是這個錯誤,我以為是緩存,在網(wǎng)上搜索了,說要加參數(shù)--no-recreate啥的,最后去看了文檔才知道,改變了Dockerfile是需要用build命令重構(gòu)才行,意思先docker-compose builddocker-compose up就可以了
如圖啟動成功,只需要安裝docker,然后這些依賴啥的自動就好了,省事,雖然要安裝docker,但是docker可以開多個服務(wù)例如docker-compose scale spider=4,也可以自己搭建倉庫注冊鏡像,就更省事了
image

全文完,文中不對的請在評論區(qū)指出,未經(jīng)允許禁止轉(zhuǎn)載!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市椎侠,隨后出現(xiàn)的幾起案子第租,更是在濱河造成了極大的恐慌,老刑警劉巖我纪,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慎宾,死亡現(xiàn)場離奇詭異,居然都是意外死亡浅悉,警方通過查閱死者的電腦和手機趟据,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來术健,“玉大人汹碱,你說我怎么就攤上這事≤窆溃” “怎么了咳促?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵稚新,是天一觀的道長。 經(jīng)常有香客問我跪腹,道長褂删,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任冲茸,我火速辦了婚禮屯阀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘轴术。我一直安慰自己难衰,他們只是感情好,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布膳音。 她就那樣靜靜地躺著,像睡著了一般铃诬。 火紅的嫁衣襯著肌膚如雪祭陷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天趣席,我揣著相機與錄音兵志,去河邊找鬼。 笑死宣肚,一個胖子當著我的面吹牛想罕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播霉涨,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼按价,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了笙瑟?” 一聲冷哼從身側(cè)響起楼镐,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎往枷,沒想到半個月后框产,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡错洁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年秉宿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屯碴。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡描睦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出导而,到底是詐尸還是另有隱情酌摇,我是刑警寧澤膝舅,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站窑多,受9級特大地震影響仍稀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜埂息,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一技潘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧千康,春花似錦享幽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至豪椿,卻和暖如春奔坟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搭盾。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工咳秉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鸯隅。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓澜建,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蝌以。 傳聞我的和親對象是個殘疾皇子炕舵,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容