需要搭建一个分布式的机群,在机群的每一台电脑中执行同一组程序,让其对某一个网站的数据进行联合分布爬取。
原生的scrapy不能实现分布式的原因
如何实现分布式
scrapy_redis组件作用
分布式的实现流程
UA伪装
Robots
管道的指定:ITEM_PIPELINES = {‘scrpay_redis.pipelines.RedisPipeline’: 400}
指定调度器:
指定redis数据库
redis的配置文件进行配置redis.windows.conf:
启动redis服务端和客户端
启动程序
向调度器的队列中扔入一个起始的url
用于检测网站数据更新的情况。核心机制:去重。redis的set实现去重
爬取4567电影名称和电影详情——深度爬取
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from redis import Redis
from movie_zls.items import MovieZlsItem
class MovieSpider(CrawlSpider):
conn = Redis(host='127.0.0.1', port=6379)
name = 'movie'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://www.4567kan.com/frim/index6.html']
rules = (
Rule(LinkExtractor(allow=r'frim/index6-\d.html'), callback='parse_item', follow=True),
)
def parse_item(self, response):
li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li')
for li in li_list:
name = li.xpath('./div/a/@title').extract_first()
item = MovieZlsItem()
item['name'] = name
detail_url = 'https://www.4567kan.com' + li.xpath('./div/a/@href').extract_first()
# 记录爬过的电影详情页的url。ex=0插入失败,ex=1插入成功
ex = self.conn.sadd('movie_detail_urls', detail_url)
if ex == 1:
print('捕获到新数据')
yield scrapy.Request(detail_url, callback=self.parse_detail, meta={'item': item})
else:
print('无数据更新')
def parse_detail(self, response):
desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
item = response['item']
item['desc'] = desc
yield desc
class MovieZlsPipeline:
def process_item(self, item, spider):
conn = spider.conn
conn.lpush('movieData', item)
return item
糗事百科爬取文章内容和标题——不用深度爬取
爬取标题和文章,都在同一个页面中就可爬取到,添加数据指纹
#将解析到的数据值生成一个唯一的标识进行redis存储
source = item['author']+item['content']
source_id = hashlib.sha256(source.encode()).hexdigest()
#将解析内容的唯一表示存储到redis的data_id中
ex = self.conn.sadd('data_id',source_id)
if ex == 1:
print('该条数据没有爬取过,可以爬取......')
yield item
else:
print('该条数据已经爬取过了,不需要再次爬取了!!!')