scrapy集成scrapy-redis
背景情况
爬虫由于需要网络请求,一般生产数据都比较慢,如果增加部分浏览器的处理,会更慢,
所以需要增加分布式的处理方案,
比较常见的,是把队列扔到redis中,比较常用的是 scrapy-redis
说明,怎么去搭建一个spider,请查看 https://blog.csdn.net/mingover/article/details/80717974
怎么加入scrapy-redis
官网
https://github.com/rmax/scrapy-redis
1,先把代码copy过来,
scrapy-redis不是 用pip安装 的,而是直接把代码copy过来
从githup中下载下来,路径中这个目录copy到我们的目录 中scrapy-redis-master\src\scrapy_redis, 我是 和 scrapy.cfg 平级.
2, settings.py中加上
下面两个是必要的内容,覆盖原来的scheduler
# Enables scheduling storing requests queue in redis.
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# Ensure all spiders share same duplicates filter through redis.
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
3,redis的设定.
依赖了redis,要先pip install redis
scrapy_redis\defaults.py
分析源码的配置,和redis相关的内容
defaults.py:
# Sane connection defaults.
REDIS_PARAMS = {
'socket_timeout': 30,
'socket_connect_timeout': 30,
'retry_on_timeout': True,
'encoding': REDIS_ENCODING
}
connection.py:
SETTINGS_PARAMS_MAP = {
'REDIS_URL': 'url',
'REDIS_HOST': 'host',
'REDIS_PORT': 'port',
'REDIS_ENCODING': 'encoding',
}
上面是scrapy-redis的源码内容,
配置redis,我们在setting中设定:
REDIS_HOST = "xxx.xxx.xxx.xx"
REDIS_PORT = "xxxx"
REDIS_URL='redis://:密码@XXX:XXX'
如果redis没有密码,REDIS_URL可以不设定.
4 ,业务代码的改动
class ASpider(scrapy.Spider):
改成:
from scrapy_redis.spiders import RedisSpider
class ASpider(RedisSpider):
启动服务&运行
1,第一次启动
启动和之前一样,直接main即可.
不过启动完后,是不会直接运行的,
要在redis中
lpush [spider的名称,如myspider]:start_urls http://xxxx
这里说明了url并不是从代码或配置中拿,是从redis中拿!!
一些关键的 redis key的设定,是在 defaults.py中设定的!
2,关掉后启动,
在运行时,服务会把队列和指纹放在redis中,如果服务关掉了,再启动,服务会从redis拿队列接着跑!!!
在运行时的redis情况:
如果不想接着上一次的任务继续,可以设定 SCHEDULER_FLUSH_ON_START 这个值 为True. 或者,直接把redis中的内容清空.
kwargs = {
'persist': settings.getbool('SCHEDULER_PERSIST'),
'flush_on_start': settings.getbool('SCHEDULER_FLUSH_ON_START'),
'idle_before_close': settings.getint('SCHEDULER_IDLE_BEFORE_CLOSE'),
}
启动服务发生了什么?
在main启动的时候,scrapy会触发,
如图,
在 L57行是初始化spider,如设定start_url等
L58是开始,这个时候,会从spider队列中拿数据,如果没有则死循环进行监听redis的内容
那监听的时候是先找request队列,还是先找start_url?
去在拿request和拿start_url中各打了断点,进行排查.
request的断点:
next_request, scheduler.py:164
_next_request_from_scheduler, engine.py:149
_next_request, engine.py:122
__call__, reactor.py:41
runUntilCurrent, base.py:896
mainLoop, base.py:1270
run, base.py:1261
start, crawler.py:291
run, crawl.py:58
_run_command, cmdline.py:157
_run_print_help, cmdline.py:90
execute, cmdline.py:150
<module>, main_page.py:10
execfile, _pydev_execfile.py:18
run, pydevd.py:1068
main, pydevd.py:1658
<module>, pydevd.py:1664
start_url的断点:
next_requests, spiders.py:82
schedule_next_requests, spiders.py:115
spider_idle, spiders.py:121
robustApply, robustapply.py:55
send_catch_log, signal.py:30
send_catch_log, signalmanager.py:45
_spider_idle, engine.py:278
_next_request, engine.py:138
__call__, reactor.py:41
runUntilCurrent, base.py:896
mainLoop, base.py:1270
run, base.py:1261
start, crawler.py:291
run, crawl.py:58
_run_command, cmdline.py:157
_run_print_help, cmdline.py:90
execute, cmdline.py:150
<module>, main_page.py:10
execfile, _pydev_execfile.py:18
run, pydevd.py:1068
main, pydevd.py:1658
<module>, pydevd.py:1664
在上面 _next_request, engine.py:122的逻辑可以看出前后 ,就先request,后start_url 的,
关于指纹
关于request生成的指纹用于确认是否已经处理过了.具体的逻辑如下
也是通过redis存储
其它的情况
如果发现把start_url扔到redis后没反应,则debug进去看看,有可能 是redis的dbindex 设置错了,
在defaults.py中配置
REDIS_PARAMS = {
....
'db': 4
}
参考
上一篇: 关于看板娘的那些事