Python爬蟲scrapy-redis分佈式實例(一)

目標任務:將以前新浪網的Scrapy爬蟲項目,修改成基於RedisSpider類的scrapy-redis分佈式爬蟲項目,將數據存入redis數據庫。html

 

1、item文件,和以前項目同樣不須要改變redis

複製代碼
# -*- coding: utf-8 -*-

import scrapy
import sys
reload(sys)
sys.setdefaultencoding("utf-8")


class SinanewsItem(scrapy.Item):
    # 大類的標題和url
    parentTitle = scrapy.Field()
    parentUrls = scrapy.Field()

    # 小類的標題和子url
    subTitle = scrapy.Field()
    subUrls = scrapy.Field()

    # 小類目錄存儲路徑
    subFilename = scrapy.Field()

    # 小類下的子連接
    sonUrls = scrapy.Field()

    # 文章標題和內容
    head = scrapy.Field()
    content = scrapy.Field()
複製代碼

 

2、spiders爬蟲文件,使用RedisSpider類替換以前的Spider類,其他地方作些許改動便可,具體代碼以下:數據庫

 

複製代碼
# -*- coding: utf-8 -*-

import scrapy
import os
from sinaNews.items import SinanewsItem
from scrapy_redis.spiders import RedisSpider
import sys
reload(sys)
sys.setdefaultencoding("utf-8")


class SinaSpider(RedisSpider):
    name = "sina"
# 啓動爬蟲的命令
redis_key = "sinaspider:strat_urls"   # 動態定義爬蟲爬取域範圍 def __init__(self, *args, **kwargs): domain = kwargs.pop('domain', '') self.allowed_domains = filter(None, domain.split(',')) super(SinaSpider, self).__init__(*args, **kwargs) def parse(self, response): items= [] # 全部大類的url 和 標題 parentUrls = response.xpath('//div[@id="tab01"]/div/h3/a/@href').extract() parentTitle = response.xpath('//div[@id="tab01"]/div/h3/a/text()').extract() # 全部小類的ur 和 標題 subUrls = response.xpath('//div[@id="tab01"]/div/ul/li/a/@href').extract() subTitle = response.xpath('//div[@id="tab01"]/div/ul/li/a/text()').extract() #爬取全部大類 for i in range(0, len(parentTitle)): # 爬取全部小類 for j in range(0, len(subUrls)): item = SinanewsItem() # 保存大類的title和urls item['parentTitle'] = parentTitle[i] item['parentUrls'] = parentUrls[i] # 檢查小類的url是否以同類別大類url開頭,若是是返回True (sports.sina.com.cn 和 sports.sina.com.cn/nba) if_belong = subUrls[j].startswith(item['parentUrls']) # 若是屬於本大類,將存儲目錄放在本大類目錄下 if(if_belong): # 存儲 小類url、title和filename字段數據 item['subUrls'] = subUrls[j] item['subTitle'] =subTitle[j] items.append(item) #發送每一個小類url的Request請求,獲得Response連同包含meta數據 一同交給回調函數 second_parse 方法處理 for item in items: yield scrapy.Request( url = item['subUrls'], meta={'meta_1': item}, callback=self.second_parse) #對於返回的小類的url,再進行遞歸請求 def second_parse(self, response): # 提取每次Response的meta數據 meta_1= response.meta['meta_1'] # 取出小類裏全部子連接 sonUrls = response.xpath('//a/@href').extract() items= [] for i in range(0, len(sonUrls)): # 檢查每一個連接是否以大類url開頭、以.shtml結尾,若是是返回True if_belong = sonUrls[i].endswith('.shtml') and sonUrls[i].startswith(meta_1['parentUrls']) # 若是屬於本大類,獲取字段值放在同一個item下便於傳輸 if(if_belong): item = SinanewsItem() item['parentTitle'] =meta_1['parentTitle'] item['parentUrls'] =meta_1['parentUrls'] item['subUrls'] = meta_1['subUrls'] item['subTitle'] = meta_1['subTitle'] item['sonUrls'] = sonUrls[i] items.append(item) #發送每一個小類下子連接url的Request請求,獲得Response後連同包含meta數據 一同交給回調函數 detail_parse 方法處理 for item in items: yield scrapy.Request(url=item['sonUrls'], meta={'meta_2':item}, callback = self.detail_parse) # 數據解析方法,獲取文章標題和內容 def detail_parse(self, response): item = response.meta['meta_2'] content = "" head = response.xpath('//h1[@id="main_title"]/text()') content_list = response.xpath('//div[@id="artibody"]/p/text()').extract() # 將p標籤裏的文本內容合併到一塊兒 for content_one in content_list: content += content_one item['head']= head[0] if len(head) > 0 else "NULL" item['content']= content yield item
複製代碼

 

 

3、settings文件設置app

複製代碼
SPIDER_MODULES = ['sinaNews.spiders']
NEWSPIDER_MODULE = 'sinaNews.spiders'


# 使用scrapy-redis裏的去重組件,不使用scrapy默認的去重方式
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis裏的調度器組件,不使用默認的調度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 容許暫停,redis請求記錄不丟失
SCHEDULER_PERSIST = True
# 默認的scrapy-redis請求隊列形式(按優先級)
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"
# 隊列形式,請求先進先出
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue"
# 棧形式,請求先進後出
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack"

# 只是將數據放到redis數據庫,不須要寫pipelines文件
ITEM_PIPELINES = {
#    'Sina.pipelines.SinaPipeline': 300,
    'scrapy_redis.pipelines.RedisPipeline': 400,
}

# LOG_LEVEL = 'DEBUG'

# Introduce an artifical delay to make use of parallelism. to speed up the
# crawl.
DOWNLOAD_DELAY = 1
# 指定數據庫的主機IP
REDIS_HOST = "192.168.13.26"
# 指定數據庫的端口號
REDIS_PORT = 6379
複製代碼

執行命令: dom

本次直接使用本地的redis數據庫,將settings文件中的REDIS_HOST和REDIS_PORT註釋掉。scrapy

啓動爬蟲程序分佈式

scrapy runspider sina.py

執行程序後終端窗口顯示以下:ide

表示程序處於等待狀態,此時在redis數據庫端執行以下命令: 函數

redis-cli> lpush sinaspider:start_urls http://news.sina.com.cn/guide/

http://news.sina.com.cn/guide/爲起始url,此時程序開始執行。post

相關文章
相關標籤/搜索