python爬虫环境spider_python爬虫中的Base Spider是什么?如何用?

当一个事物的个数很多的时候,我们会把它们归为一个群,比如人群之类的称呼。那对于python中的爬虫来说,我们想要获取数据,就需要大量的爬虫去支撑,不过这里我们肯定不能也给它们起一个群的称呼。同样我们会用类来表示,这就是我们今天要讲Base Spider,感兴趣的小伙伴也来看看这个爬虫中的类究竟是什么吧。

Base Spider

不在使用scrapy原有的Spider类,重写的RedisSpider继承了Spider和RedisMixin这两个类,RedisMixin是用来从redis读取url的类。

当我们生成一个Spider继承RedisSpider时,调用setup_redis函数,这个函数会去连接redis数据库,然后会设置signals(信号):

一个是当spider空闲时候的signal,会调用spider_idle函数,这个函数调用schedule_next_request函数,保证spider是一直活着的状态,并且抛出DontCloseSpider异常。

一个是当抓到一个item时的signal,会调用item_scraped函数,这个函数会调用schedule_next_request函数,获取下一个request。from scrapy import signals

from scrapy.exceptions import DontCloseSpider

from scrapy.spiders import Spider, CrawlSpider

from . import connection, defaults

from .utils import bytes_to_str

class RedisMixin(object):

"""Mixin class to implement reading urls from a redis queue."""

redis_key = None

redis_batch_size = None

redis_encoding = None

# Redis client placeholder.

server = None

def start_requests(self):

"""Returns a batch of start requests from redis."""

return self.next_requests()

def setup_redis(self, crawler=None):

"""Setup redis connection and idle signal.

This should be called after the spider has set its crawler object.

"""

if self.server is not None:

return

if crawler is None:

# We allow optional crawler argument to keep backwards

# compatibility.

# XXX: Raise a deprecation warning.

crawler = getattr(self, 'crawler', None)

if crawler is None:

raise ValueError("crawler is required")

settings = crawler.settings

if self.redis_key is None:

self.redis_key = settings.get(

'REDIS_START_URLS_KEY', defaults.START_URLS_KEY,

)

self.redis_key = self.redis_key % {'name': self.name}

if not self.redis_key.strip():

raise ValueError("redis_key must not be empty")

if self.redis_batch_size is None:

# TODO: Deprecate this setting (REDIS_START_URLS_BATCH_SIZE).

self.redis_batch_size = settings.getint(

'REDIS_START_URLS_BATCH_SIZE',

settings.getint('CONCURRENT_REQUESTS'),

)

try:

self.redis_batch_size = int(self.redis_batch_size)

except (TypeError, ValueError):

raise ValueError("redis_batch_size must be an integer")

if self.redis_encoding is None:

self.redis_encoding = settings.get('REDIS_ENCODING', defaults.REDIS_ENCODING)

self.logger.info("Reading start URLs from redis key '%(redis_key)s' "

"(batch size: %(redis_batch_size)s, encoding: %(redis_encoding)s",

self.__dict__)

self.server = connection.from_settings(crawler.settings)

# The idle signal is called when the spider has no requests left,

# that's when we will schedule new requests from redis queue

crawler.signals.connect(self.spider_idle, signal=signals.spider_idle)

def next_requests(self):

"""Returns a request to be scheduled or none."""

use_set = self.settings.getbool('REDIS_START_URLS_AS_SET', defaults.START_URLS_AS_SET)

fetch_one = self.server.spop if use_set else self.server.lpop

# XXX: Do we need to use a timeout here?

found = 0

# TODO: Use redis pipeline execution.

while found 

data = fetch_one(self.redis_key)

if not data:

# Queue empty.

break

req = self.make_request_from_data(data)

if req:

yield req

found += 1

else:

self.logger.debug("Request not made from data: %r", data)

if found:

self.logger.debug("Read %s requests from '%s'", found, self.redis_key)

def make_request_from_data(self, data):

"""Returns a Request instance from data coming from Redis.

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

provide your own message decoding.

Parameters

----------

data : bytes

Message from redis.

"""

url = bytes_to_str(data, self.redis_encoding)

return self.make_requests_from_url(url)

def schedule_next_requests(self):

"""Schedules a request if available"""

# TODO: While there is capacity, schedule a batch of redis requests.

for req in self.next_requests():

self.crawler.engine.crawl(req, spider=self)

def spider_idle(self):

"""Schedules a request if available, otherwise waits."""

# XXX: Handle a sentinel to close the spider.

self.schedule_next_requests()

raise DontCloseSpider

class RedisSpider(RedisMixin, Spider):

"""Spider that reads urls from redis queue when idle.

Attributes

----------

redis_key : str (default: REDIS_START_URLS_KEY)

Redis key where to fetch start URLs from..

redis_batch_size : int (default: CONCURRENT_REQUESTS)

Number of messages to fetch from redis on each attempt.

redis_encoding : str (default: REDIS_ENCODING)

Encoding to use when decoding messages from redis queue.

Settings

--------

REDIS_START_URLS_KEY : str (default: ":start_urls")

Default Redis key where to fetch start URLs from..

REDIS_START_URLS_BATCH_SIZE : int (deprecated by CONCURRENT_REQUESTS)

Default number of messages to fetch from redis on each attempt.

REDIS_START_URLS_AS_SET : bool (default: False)

Use SET operations to retrieve messages from the redis queue. If False,

the messages are retrieve using the LPOP command.

REDIS_ENCODING : str (default: "utf-8")

Default encoding to use when decoding messages from redis queue.

"""

@classmethod

def from_crawler(self, crawler, *args, **kwargs):

obj = super(RedisSpider, self).from_crawler(crawler, *args, **kwargs)

obj.setup_redis(crawler)

return obj

class RedisCrawlSpider(RedisMixin, CrawlSpider):

"""Spider that reads urls from redis queue when idle.

Attributes

----------

redis_key : str (default: REDIS_START_URLS_KEY)

Redis key where to fetch start URLs from..

redis_batch_size : int (default: CONCURRENT_REQUESTS)

Number of messages to fetch from redis on each attempt.

redis_encoding : str (default: REDIS_ENCODING)

Encoding to use when decoding messages from redis queue.

Settings

--------

REDIS_START_URLS_KEY : str (default: ":start_urls")

Default Redis key where to fetch start URLs from..

REDIS_START_URLS_BATCH_SIZE : int (deprecated by CONCURRENT_REQUESTS)

Default number of messages to fetch from redis on each attempt.

REDIS_START_URLS_AS_SET : bool (default: True)

Use SET operations to retrieve messages from the redis queue.

REDIS_ENCODING : str (default: "utf-8")

Default encoding to use when decoding messages from redis queue.

"""

@classmethod

def from_crawler(self, crawler, *args, **kwargs):

obj = super(RedisCrawlSpider, self).from_crawler(crawler, *args, **kwargs)

obj.setup_redis(crawler)

return obj

到这里我们关于Scrapy-redis的四种组件已经全部讲完了,对于之前其他组件还有不明白的可以再去翻一翻之前的文章,小编这里就不再重复啦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值