1. 程式人生 > >基於python,scrapy,redis實現主從式(分散式的一種)master-slave爬蟲

基於python,scrapy,redis實現主從式(分散式的一種)master-slave爬蟲

前言

這是本人的第一篇部落格,感觸還是很多的,最近在幫朋友做一個分散式爬蟲的論文,遇到很多坑,不過已經一一填平,廢話不多說啦。

分類

(1)主從分散式爬蟲:
由一臺master伺服器, 來提供url的分發, 維護待抓取url的list。由多臺slave伺服器執行網頁抓取功能, slave所抽取的新url,一律由master來處理解析,而slave之間不需要做任何通訊。
(2)對等分散式爬蟲:
由多臺相同的伺服器整合,每臺伺服器可單獨運作,完成爬蟲工作,每臺伺服器之間的分工有一定的運算邏輯(ex: hash),由運算(配置)的結果,來決定由那臺伺服器做抓取網頁的工作。

本文講解第一種-主從式,只是簡單的闡明,所以master端只負責爬取url儲存到redis資料庫,slave端取出redis裡url佇列進行爬取網頁內容,解析並儲存到mongodb資料庫。


準備

python3(本人使用的是3.6版本)
scrapy
redis

mongodb

安裝教程自行百度,使用到的python模組(這裡是需要使用pip安裝,最好是pip新版本):

scrapy-redis
pymongo

python連結mongodb例子:

import pymongo as pm

host = 'localhost'
port = 27017

# 連結資料庫
client = pm.MongoClient(host,port)
# 選擇db
db = client.demo
# 選擇集合test
# 注意這裡的集合可以直接使用,如果沒有mongodb會自動建立
db.test.insert({"name":"hello"})

client.close()

實現

我們以58同城為例,爬取二手房,爬取中間有些錯誤但不影響,由於網站整改302重定向了。

1. master端

spider檔案

from scrapy.spider import CrawlSpider,Rule
from scrapy.linkextractors import LinkExtractor
from master.items import MasterItem

class myspider(CrawlSpider):

    name = 'master'
    allowed_domains = ['58.com']
    item = MasterItem()
    start_urls = ['http://cd.58.com/ershoufang/']
    rules = (
        Rule(LinkExtractor(allow=('http://cd.58.com/ershoufang/\d{14}x.shtml.*?',)), callback='parse_item',
             follow=True),
    )

    def parse_item(self,response):
        item = self.item
        item['url'] = response.url
        return item

繼承CrawlSpider可以遍歷整個網站,Rule和LinkExtractor限制遍歷那些網頁,allow為允許的網址(正則表示式),callback回撥函式,注意一定不能寫預設的parse函式。

item檔案

import scrapy

class MasterItem(scrapy.Item):
    # define the fields for your item here like:
    url = scrapy.Field()
    pass

只儲存url

middleware檔案

import random
from .useragent import agents

class UserAgentMiddleware(object):

    def process_request(self, request, spider):
        agent = random.choice(agents)
        referer = request.meta.get('referer', None)
        request.headers["User-Agent"] = agent
        request.headers["Referer"] = referer

這裡對預設的middleware檔案進行修改,useragent是自建的檔案,裡面agents=['內容略']陣列,欄位程式碼表示為每次請求隨機一個User-Agent(瀏覽器身份),一定程度避免認為是爬蟲。

pipeline檔案

import redis

class MasterPipeline(object):

    def __init__(self):
        self.redis_url = 'redis://123456:@localhost:6379/'
        self.r = redis.Redis.from_url(self.redis_url,decode_responses=True)

    def process_item(self, item, spider):
        self.r.lpush('myredis:start_urls', item['url'])
儲存url到redis資料庫,redis_url中123456為資料庫密碼,你的redis沒有密碼就不用寫,第二種連結方式:
redis.Redis(host="localhost",port=6379)

預設使用db0,一定要使用db0,否則slave端取不到資料(可能由於本人才疏學淺沒有找到連結其他db供slave端使用的方式)

setting檔案

ROBOTSTXT_OBEY = False
DOWNLOADER_MIDDLEWARES = {
   'master.middlewares.UserAgentMiddleware': 543,
}
ITEM_PIPELINES = {
   'master.pipelines.MasterPipeline': 300,
}

注意這裡只是部分程式碼不要覆蓋上去,替換相同的地方即可。爬蟲一開始會取得網站的robot.txt檔案(也叫君子協議檔案),得知那些網址可爬,我們設定ROBOTSTXT_OBEY=False不遵循他的協議。

2. slave端

spider檔案

import re
from scrapy_redis.spiders import RedisSpider
from scrapy.http import Request
from slave.items import SlaveItem

class myspider(RedisSpider):
    name = 'slave'
    item = SlaveItem()
    redis_key = 'myredis:start_urls'

    def parse(self, response):
        item = self.item
        item['title'] = response.xpath('//div[@class="house-title"]/h1/text()').extract()[0]
        item['price'] = response.xpath('//div[@id="generalSituation"]//li[1]/span[2]/text()').extract()[0]
        item['type'] = response.xpath("//div[@id='generalSituation']//li[2]/span[2]/text()").extract()[0]
        item['area'] = response.xpath("//div[@id='generalSituation']//li[3]/span[2]/text()").extract()[0]
        item['direct'] = response.xpath("//div[@id='generalSituation']//li[4]/span[2]/text()").extract()[0]
        item['floor'] = response.xpath(
            "//div[@id='generalSituation']//ul[@class='general-item-right']/li[1]/span[2]/text()").extract()[0]
        item['decorat'] = response.xpath(
            "//div[@id='generalSituation']//ul[@class='general-item-right']/li[2]/span[2]/text()").extract()[0]
        item['start'] = response.xpath(
            "//div[@id='generalSituation']//ul[@class='general-item-right']/li[4]/span[2]/text()").extract()[0]
        item['village'] = response.xpath("string(/html/body/div[4]/div[2]/div[2]/ul/li[1]/span[2])").extract()[0]
        item['position'] = response.xpath("string(/html/body/div[4]/div[2]/div[2]/ul/li[2]/span[2])").extract()[0]
        item['phone'] = response.xpath("//div[@id='houseChatEntry']//p[@class='phone-num']/text()").extract()[0]
        txt = response.xpath("/html/head/script[1]/text()").extract()[0]
        pattern = re.compile(".*?____json4fe.brokerUrl = '(.*?)';.*?", re.S)
        result = re.findall(pattern, txt)
        yield Request("http://" + result[0], callback=self.get_user)

    def get_user(self, response):
        item = self.item
        item['user'] = response.xpath("/html/body/div[2]/div[2]/div[1]/div[1]/div/div[1]/text()").extract()[0]
        return item

這裡不在講解xpath的用法,告訴你們一個好方法,瀏覽器F12選中一個元素,右鍵->複製->xpath。用redis_key代替start_urls,‘myredis:start_urls’為redis資料庫db0的鍵,就是我們master端儲存的,直接使用預設回撥函式parse。

item檔案

import scrapy

class SlaveItem(scrapy.Item):
    title = scrapy.Field()
    price = scrapy.Field()
    type = scrapy.Field()
    area = scrapy.Field()
    direct = scrapy.Field()
    floor = scrapy.Field()
    decorat = scrapy.Field()
    start = scrapy.Field()
    village = scrapy.Field()
    position = scrapy.Field()
    user = scrapy.Field()
    phone = scrapy.Field()
    pass

middleware檔案(同master端)

pipeline檔案

import pymongo as pm

host = 'localhost'
port = 27017
client = pm.MongoClient(host,port)
db = client.demo.tongcheng

class SlavePipeline(object):
    def process_item(self, item, spider):
        db.insert(dict(item))

儲存到mongodb資料庫

setting檔案

# 啟用Redis排程儲存請求佇列
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
#不清除Redis佇列、這樣可以暫停/恢復 爬取
# SCHEDULER_PERSIST = True
# 確保所有的爬蟲通過Redis去重
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

#指定用於連線redis的URL(可選)
#如果設定此項,則此項優先順序高於設定的REDIS_HOST 和 REDIS_PORT
REDIS_URL = 'redis://[email protected]:6379/'

BOT_NAME = 'slave'

SPIDER_MODULES = ['slave.spiders']
NEWSPIDER_MODULE = 'slave.spiders'

ROBOTSTXT_OBEY = False
DOWNLOADER_MIDDLEWARES = {
   'slave.middlewares.UserAgentMiddleware': 543,
}
ITEM_PIPELINES = {
   'slave.pipelines.SlavePipeline': 300,
}

加入和替換配置

結果

redis資料庫

mongodb資料庫

最後

本人也是小白,寫的粗糙,有不懂或見解的地方一起交流。


相關推薦

基於pythonscrapyredis實現主從分散式master-slave爬蟲

前言這是本人的第一篇部落格,感觸還是很多的,最近在幫朋友做一個分散式爬蟲的論文,遇到很多坑,不過已經一一填平,廢話不多說啦。分類(1)主從分散式爬蟲:由一臺master伺服器, 來提供url的分發, 維護待抓取url的list。由多臺slave伺服器執行網頁抓取功能, sla

Python基於皮爾遜系數實現股票預測多線程

author top def split pat init -s bubuko odi 1 # -*- coding: utf-8 -*- 2 """ 3 Created on Tue Dec 4 08:53:08 2018 4 5 @a

Redis實現主從複製Master&Slave

         由於前段時間公司專案比較趕,一直抽不出時間寫部落格,今天偷空寫一篇吧。前面給大家講解了單機版redis的基本操作,現在繼續給大家講解一下Redis的進階部分,主從複製和讀寫分離。 一、Master&Slave是什麼?          也就是我們所

(Flask Web開發:基於Python的Web應用開發實戰)------學習筆記第2章

第2章 程式的基本結構 本章將帶你瞭解 Flask 程式各部分的作用,編寫並執行第一個 Flask Web 程式。 2.1 初始化   所有 Flask 程式都必須建立一個程式例項,程式例項是 Flask 類的物件。   Web 伺服器使用一種名為 Web 伺服器閘

linux上鍵安裝redis以及主從配置指令碼自動安裝

一、環境配置 1:任何位置建立資料夾 mkdir redis;cd redis;mkdir conf;cd conf #下載安裝安裝包 wget http://www.redis.cn/download.html/redis-5.0.3.tar.g

python版:單機redis實現秒殺防止超限

測試環境 ubuntu 16.04 python 3.6.6 redis 3.0.6 簡單描述 搶購、秒殺是一個很常見的應用場景,主要需要解決的問題有兩個: 1 高併發 2 如何解決庫存的正確減少("超賣"問題) redis 命令說明 exists 返回key是否

Python識別圖形驗證碼實現自動登陸附視訊教程

驗證碼有圖形驗證碼、極驗滑動驗證碼、點觸驗證碼、宮格驗證碼。這回重點講講圖形驗證碼的識別。 雖說圖形驗證碼最簡單,但是對於我這等新手,還是要苦學一番。首先尋找測試網站,網站選的是如雲閣小說網,小網站不怕被封。他們的驗證碼一般如下:視訊教程:     &n

Nginx+Tomcat搭建叢集Spring Session+Redis實現Session共享

小夥伴們好久不見!最近略忙,部落格寫的有點少,嗯,要加把勁。OK,今天給大家帶來一個JavaWeb中常用的架構搭建,即Nginx+Tomcat搭建服務叢集,然後通過Spring Session+Redis實現Session共享。 閱讀本文需要有如下知識點:

15.7哨兵叢集 redis-sentinel主從複製高可用

redis-sentinel主從複製高可用   Redis-Sentinel Redis-Sentinel是redis官方推薦的高可用性解決方案,當用redis作master-slave的高可用時,如果master

容器雲環境下Nginx+tomcat+redis實現web專案叢集

環境:由於在Windows下Tomcat8與Nginx實驗不成功,錯誤的認為8不行,就有了下面的歷程,,,,經過請教師兄,發現自己的方法不對, #利用centos基礎映象以及jdk Tomcat 編輯新的映象Tomcat7 #刪掉jdk資料夾下多餘檔案, 降低build的

企業實戰-KeepAlived+Redis實現主從熱備、秒級切換

keepalived redis 楊文 最近公司生產環境需要做一個Redis+Keepalived的集群架構,分別用六個端口,實現多路復用,最終實現主從熱備、秒級切換。一、部署Redis集群首先用兩臺虛擬機模擬6個節點,一臺機器3個節點,創建出3 master、3 salve 環境。然後模擬成功,

Nginx+keepalived做雙機熱備實現負載均衡主主模式

nginx keepalive Keepalived: 簡介:Keepalived的作用是檢測服務器的狀態,如果有一臺web服務器宕機,或工作出現故障,Keepalived將檢測到,並將有故障的服務器從系統中剔除,同時使用其他服務器代替該服務器的工作,當服務器工作正常後Keepali

淺談基於PythonScrapy爬蟲入門

Python爬蟲教程 Python內容講解 (一)內容分析   接下來創建一個爬蟲項目,以圖蟲網為例抓取裏面的圖片。在頂部菜單“發現”“標簽”裏面是對各種圖片的分類,點擊一個標簽,比如“Python視頻課程”,網頁的鏈接為:http://www.codingke.com/Python視頻課程/,我們以

腳本鍵安裝redis實現主從復制

redis自動化安裝腳本安裝腳本及配置文件上傳至家目錄即可,sh執行腳本即可選擇主從#!/bin/bash#Description:atuo install redis#Date:2018.4.11 Download_redis=http://download.redis.io/releases/redis

Redis實現主從復制Master&Slave

現在 開啟 博客 ont water 備機 mil 一個數 投票 由於前段時間公司項目比較趕,一直抽不出時間寫博客,今天偷空寫一篇吧。前面給大家講解了單機版redis的基本操作,現在繼續給大家講解一下Redis的進階部分,主從復制和讀寫分離。 一、Ma

基於python+whoosh的全文檢索實現

whoosh的官方介紹:http://whoosh.readthedocs.io/en/latest/quickstart.html 因為做的是中文的全文檢索需要匯入jieba工具包以及whoosh工具包 直接上程式碼吧 from whoosh.qparser import QueryPa

實現客戶端寫入字串在服務端翻轉後返回多執行緒

實現客戶端寫入字串,在服務端翻轉後返回 服務端: package network.tcp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import

mysql5.7 yum安裝及主從配置從庫只讀不重啟主庫新增從庫配置

yum -y remove mysql wget http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm rpm -ivh mysql57-community-release-el7-8.noarch.rpm yum -y ins

使用思事標籤實現包含GTD模式的方法

GTD(Getting Things Done)工作法,很多軟體採用了這個模式。它具體做法可以分成收集、整理、組織、回顧與行動五個步驟。我使用思事的標籤,預設標籤很方便的實現了GTD模式,同時還設定了一些自己需要的、常用的標籤,請參考。 下圖為我的標籤截圖: 關

關於將aop功能封裝成jar包後被其他模組依賴後aop功能無法實現的問題包掃描

在開發中,將aop的功能寫到了公共模組後,然後將公共模組封裝成jar包,被其他專案所依賴。但是出現aop功能無法實現,是因為未掃描到該包下的類,需要在引用模組的啟動類中加入掃描的程式碼 @ComponentScan(basePackages = {"xxx.xxx.*"})