diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/5\347\217\255/5\347\217\255_\344\272\221/week_12/\345\210\206\345\270\203\345\274\217\347\210\254\350\231\253\343\200\201scrapy\344\270\216redis-12-1noteyun.md" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/5\347\217\255/5\347\217\255_\344\272\221/week_12/\345\210\206\345\270\203\345\274\217\347\210\254\350\231\253\343\200\201scrapy\344\270\216redis-12-1noteyun.md" new file mode 100644 index 0000000000000000000000000000000000000000..15891827e2969d49cf729bcb3810b06b6495c3f4 --- /dev/null +++ "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/5\347\217\255/5\347\217\255_\344\272\221/week_12/\345\210\206\345\270\203\345\274\217\347\210\254\350\231\253\343\200\201scrapy\344\270\216redis-12-1noteyun.md" @@ -0,0 +1,159 @@ +11-1noteyun-分布式爬虫、scrapy与redis + +# 分布式爬虫 + +- 什么分布式 + + 分布式就是把一个系统拆分成若干个子系统, 每个子系统独立运行, 然后通过某种方式进行交互. + +- 什么是分布式爬虫 + + 狭义地讲, 需要将爬虫的多个组件拆分成子系统. 但是现在主流是只拆分出**任务生产者**, 建立一个生产消费者模型.由多台机器上的爬虫实例作为消费者去完成爬虫任务. + +# scrapy的痛点 + +- 爬虫实例中断后重启后, 内存保存的消息队列将会丢失, 实现爬虫重启功能比较复杂; +- 去重中间件无法持久化, 中断后无法正常过滤; +- 消息队列放在了内置类型`QUEUE`中, 无法简单地从外部查看; +- 不共享消息队列, 可扩展性差; + +# scrapy-redis + +```python +https://github.com/rmax/scrapy-redis +``` + +- 安装 + + ```python + pip install scrapy-redis + ``` + +- SETTINGS设置 --settings设置 + + - SCHEDULER + + 更换调度器 + + ```python + SCHEDULER = 'scrapy_redis.scheduler.Scheduler' + ``` + + - SCHEDULER_QUEUE_CLASS + + 更换消息队列 + + ```python + SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue' + ``` + + - DUPEFILTER_CLASS + + 更换过滤器, 将请求指纹保存在redis当中 + + ```python + DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" + ``` + + - SCHEDULER_PERSIST + + 消息队列持久化, 不会清空redis中的消息队列 + + ```python + SCHEDULER_PERSIST = True + ``` + + - REDIS配置 + + ```python + # Redis settings + REDIS_HOST = 'localhost' + REDIS_PORT = 6379 + # Redis 参数配置 + REDIS_PARAMS = {"db": 5} + ``` + +- SPIDER设置 + + - 修改继承的父类为`scrapy_redis.spiders.RedisSpider` + + ```python + from scrapy_redis.spiders import RedisSpider + + class JdSearch(RedisSpider): + ``` + + - 添加redis_key配置 + + ```python + redis_key = f"{name}:start_urls" + ``` + +- 将生产者从scrapy项目中拆分出去 + + ```python + 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 + + ```python + 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) + ``` + +![image-20210318173303033](C:\Users\yunqin\AppData\Roaming\Typora\typora-user-images\image-20210318173303033.png) + + + + + +![image-20210318181312572](C:\Users\yunqin\AppData\Roaming\Typora\typora-user-images\image-20210318181312572.png) + +# 课后作业 + +- 将scrapy项目重构为scrapy-redis项目 +- 了解scrapy的痛点和我们为什么要使用scrapy-redis + + + + + + + + +