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


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

 

一、item文件,和之前項目一樣不需要改變

# -*- 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()

 

二、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

 

 

三、settings文件設置

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

執行命令:

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

啟動爬蟲程序

scrapy runspider sina.py

執行程序后終端窗口顯示如下:

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

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM