问题描述

默认RedisSpider在启动时,首先会读取redis中的spidername:start_urls,如果有值则根据url构建request对象。

现在的要求是,根据特定关键词采集。

例如:目标站点有一个接口,根据post请求参数来返回结果。

那么,在这种情况下,构建request主要的变换就是请求体(body),API接口是不变的。

对于原来通过url构建request的策略就不再适用了。

所以,此时我们需要对相应的方法进行重写。

重写方法

爬虫类需要继承至scrapy_redis.spiders.RedisSpider

start_requests

我需要从数据库拿到关键词数据,然后用关键词构建请求。

此时,我们将关键词看作start_url,将关键词pushredis

首先,写一个将单个关键词pushredis的方法

push_data_to_redis

def push_data_to_redis(self, data):
"""将数据push到redis"""
# 序列化,data可能是字典
data = pickle.dumps(data)
use_set = self.settings.getbool('REDIS_START_URLS_AS_SET', defaults.START_URLS_AS_SET)
self.server.spush(self.redis_key, data) if use_set else self.server.lpush(self.redis_key, data)

self.redis_key如果没有做任何声明,则默认为 spidername:start_urls

接着重写start_request

def start_requests(self):
if self.isproducer():
# get_keywords 从数据库读关键词的方法
items = self.get_keywords()
for item in items:
self.push_data_to_redis(item)
return super(DoubanBookMetaSpider, self).start_requests()

上述代码中有一个self.isproducer,此方法用于检测当前程序是不是生产者,即向redis提供关键词

isproducer

# (...)

def __init__(self, *args, **kwargs):
self.is_producer = kwargs.pop('producer', None)
super(DoubanBookMetaSpider, self).__init__() def isproducer(self):
return self.is_producer is not None # (...)

此方法需要配合scrapy命令行使用,例如:

// 启动一个生产者,producer的参数任意,只要填写了就是True
scrapy crawl myspider -a producer=1
// 启动一个消费者
scrapy crawl myspider

关于scrapy命令行的更多参数,参考文档:https://scrapy-chs.readthedocs.io/zh_CN/0.24/topics/shell.html

make_request_from_data

查看RedisMixin中的make_request_from_data

方法注释信息:

Returns a Request instance from data coming from Redis.

根据来源于redis的数据返回一个Request对象

By default, data is an encoded URL. You can override this method to

provide your own message decoding.

默认情况下,data是已编码的URL链接。您可以将此方法重写为提供您自己的消息解码。

def make_request_from_data(self, data):
url = bytes_to_str(data, self.redis_encoding)
return self.make_requests_from_url(url)

data转为字符串(网站链接字符串),接着调用了 make_requests_from_url,通过url构建request对象

data从哪里来?

查看RedisMixinnext_request方法

由此得知,data是从redispop出来的,在之前我们将data序列化后push进去,现在pop出来,我们将其反序列化并依靠它构建request对象

重写make_request_from_data

def make_request_from_data(self, data):
data = pickle.loads(data, encoding=self.redis_encoding)
return self.make_request_from_book_info(data)

在本例中构建request对象的方法是self.make_request_from_book_info,在实际开发中,根据目标站请求规则编写构建request的方法即可。

最终效果

启动一个生成者

scrapy crawl myspider -a producer=1

生成者将所有的关键词push完之后,会转为消费者开始消费

在多个节点上启动消费者

scrapy crawl myspider

一个爬虫的开始,总是根据现有数据采集新的数据,例如,根据列表页中的详情页链接采集详情页数据,根据关键词采集搜索结果等等。根据现有数据的不同,开始的方法也不同,大体仍是大同小异的。

scrapy-redis非多网址采集的使用的更多相关文章

  1. Redis 非关系性数据库集群的搭建与常用方法

    redis 非关系型数据库,内存型数据库,现在大家都不陌生了,无论大中小型企业,都会将redis应用到自己的项目中,以此来减轻数据库的压力 安装步骤: 1.安装gcc 安装c语言的编译环境 yum i ...

  2. 基于Python,scrapy,redis的分布式爬虫实现框架

    原文  http://www.xgezhang.com/python_scrapy_redis_crawler.html 爬虫技术,无论是在学术领域,还是在工程领域,都扮演者非常重要的角色.相比于其他 ...

  3. Redis非关系型数据库

    1.简介 Redis是一个基于内存的Key-Value非关系型数据库,由C语言进行编写. Redis一般作为分布式缓存框架.分布式下的SESSION分离.分布式锁的实现等等. Redis速度快的原因: ...

  4. redis非关系型数据库的基本语法

    导入并连接数据库: import redis # 导入redis模块,通过python操作redis 也可以直接在redis主机的服务端操作缓存数据库 import time # host是redis ...

  5. 37.scrapy解决翻页及采集杭州造价网站材料数据

    1.目标采集地址: http://183.129.219.195:8081/bs/hzzjb/web/list 2.这里的翻页还是较为简单的,只要模拟post请求发送data包含关键参数就能获取下一页 ...

  6. Redis——非阻塞IO和队列

    Redis是个高并发的中间件,但是确实是单线程.而且,Nginx.Node.js等也是单线程的.Redis通过非阻塞IO(IO多路复用)处理那么多的并发客户端连接,并且,由于Redis所有的数据都在内 ...

  7. Scrapy+redis实现分布式爬虫

    概述 什么是分布式爬虫 需要搭建一个由n台电脑组成的机群,然后在每一台电脑中执行同一组程序,让其对同一网络资源进行联合且分布的数据爬取. 原生Scrapy无法实现分布式的原因 原生Scrapy中调度器 ...

  8. Redis非关系型缓存数据库集群部署、参数、命令工具

    <关系型数据库与非关系型数据库> 关系数据库:mysql.oracle.DB2.SQL Server非关系数据库:Redis(缓存数据库).MongodDB(处理海量数据).Memcach ...

  9. redis非特定类型命令

    1. key查询 keys my* #获取当前数据库中符合模式的所有key exists mykey #查看key是否还存在 2. 数据库操作 redis默认一个实例的数据库是16个[db0-db15 ...

随机推荐

  1. Apache Cassandra——可扩展微服务应用程序的持久数据存储

    通过使用微服务,团队可以更快地响应变化,而无需改动整个应用程序.利用微服务,开发团队可以构建出具有鲁棒性和可扩展性的系统,从而适应当今应用程序的需求.   然而,使用微服务也带来了一系列挑战.在本文中 ...

  2. 深入理解MySQL系列之锁

    按锁思想分类 悲观锁 优点:适合在写多读少的并发环境中使用,虽然无法维持非常高的性能,但是在乐观锁无法提更好的性能前提下,可以做到数据的安全性 缺点:加锁会增加系统开销,虽然能保证数据的安全,但数据处 ...

  3. 如何优雅排查现网服务器cpu飙高的问题

    1.排查现网服务器cpu飙高问题的思路 1.查看java进程id ps -ef|grep java 2.使用top -Hp 进程id 查看cpu比较高的线程 3.执行jstack 进程id > ...

  4. JS function 是函数也是对象, 浅谈原型链

    JS function 是函数也是对象, 浅谈原型链 JS 唯一支持的继承方式是通过原型链继承, 理解好原型链非常重要, 我记录下我的理解 1. 前言 new 出来的实例有 _proto_ 属性, 并 ...

  5. git分支的创建与分支之间合并的底层原理

    开发一个版本,采用的发布流程: (1).从master的最新代码拉取一个开发分支,在上面进行开发(这里假设开发分支为dev) (2).在开发分支上不断地进行提交版本,期间,master也会有因为其他版 ...

  6. 关于java方法重写

    1.子类的方法与父类中的方法有相同的返回类型,相同的方法名称.相同的参数列表 2.子类方法的访问级别不能低于父类方法的访问级别 3.子类方法抛出的异常范围不能大于父类中方法抛出的异常范围

  7. maven打包 依赖jar与不依赖jar

    ?xml version="1.0" encoding="UTF-8"?> <assembly xmlns="http://maven.a ...

  8. jdbc事务、连接池概念、c3p0、Driud、JDBC Template、DBUtils

    JDBC 事务控制 什么是事务:一个包含多个步骤或者业务操作.如果这个业务或者多个步骤被事务管理,则这多个步骤要么同时成功,要么回滚(多个步骤同时执行失败),这多个步骤是一个整体,不可分割的. 操作: ...

  9. apply 和 call的用法、区别

    1.JavaScript中函数是对象的方法,如果一个函数不是js对象的方法那一定是全局对象的函数,每个函数的对象都有apply和call方法,即每个对象都有call and apply apply:调 ...

  10. 【小菜学网络】MAC地址详解

    上一小节介绍了以太网帧的结构,以及帧中各个字段的作用.参与以太网通讯的实体,由以太网地址唯一标识.以太网地址也叫做 MAC 地址,我们对它仍知之甚少. 以太网地址在不同场景,称谓也不一样,常用叫法包括 ...