分布式爬虫
-
什么分布式
分布式就是把一个系统拆分成若干个子系统, 每个子系统独立运行, 然后通过某种方式进行交互.
-
什么是分布式爬虫
狭义地讲, 需要将爬虫的多个组件拆分成子系统. 但是现在主流是只拆分出任务生产者, 建立一个生产消费者模型.由多台机器上的爬虫实例作为消费者去完成爬虫任务.
scrapy的痛点
- 爬虫实例中断后重启后, 内存保存的消息队列将会丢失, 实现爬虫重启功能比较复杂;
- 去重中间件无法持久化, 中断后无法正常过滤;
- 消息队列放在了内置类型
QUEUE
中, 无法简单地从外部查看; - 不共享消息队列, 可扩展性差;
scrapy-redis
https://github.com/rmax/scrapy-redis
-
安装
pip install scrapy-redis
-
SETTINGS设置
-
SCHEDULER
更换调度器
SCHEDULER = 'scrapy_redis.scheduler.Scheduler'
-
SCHEDULER_QUEUE_CLASS
更换消息队列
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'
-
DUPEFILTER_CLASS
更换过滤器, 将请求指纹保存在redis当中
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
-
SCHEDULER_PERSIST
消息队列持久化, 不会清空redis中的消息队列
SCHEDULER_PERSIST = True
-
REDIS配置
# Redis settings REDIS_HOST = 'localhost' REDIS_PORT = 6379 # Redis 参数配置 REDIS_PARAMS = {"db": 5}
-
-
SPIDER设置
-
修改继承的父类为
scrapy_redis.spiders.RedisSpider
from scrapy_redis.spiders import RedisSpider class JdSearch(RedisSpider):
-
添加redis_key配置
redis_key = f"{name}:start_urls"
-
-
将生产者从scrapy项目中拆分出去
import redis import time import json redis_con = redis.Redis(host='localhost', port=6379, db=5) def search_producer(): for keyword in ["鼠标", "键盘", "显卡", "耳机"]: for page_num in range(1, 11): url = f"https://search.jd.com/Search?keyword={keyword}&page={page_num}" meta = { "sta_date": time.strftime("%Y-%m-%d"), "keyword": keyword, "page_num": page_num } task = json.dumps({ "url": url, "body": '', "method": "GET", "meta": meta }) redis_con.lpush("jd_search:start_urls", task) if __name__ == "__main__": search_producer()
-
重写start_requests
def make_request_from_data(self, data): task = json.loads(data.decode("utf-8")) return scrapy.http.FormRequest(url=task['url'], formdata=json.loads(task['body']) if task['body'] else '', method=task['method'], meta=task['meta'], dont_filter=False, callback=self.parse_search, errback=self.process_error)