网站推广 济南长沙感染人数最新消息
2026/1/3 20:27:08 网站建设 项目流程
网站推广 济南,长沙感染人数最新消息,如何提升网站流量,wordpress如何建企业站关键词#xff1a;Scrapy分布式改造、Scrapy-Redis实战、RayScrapy、爬虫性能优化、单机转分布式 创作声明#xff1a;本文以「豆瓣电影Top250爬取」为实战案例#xff0c;完整拆解从原生Scrapy单机 → Scrapy-Redis基础分布式 → Ray高性能分布式的全改造流程#xff0c;每…关键词Scrapy分布式改造、Scrapy-Redis实战、RayScrapy、爬虫性能优化、单机转分布式创作声明本文以「豆瓣电影Top250爬取」为实战案例完整拆解从原生Scrapy单机→Scrapy-Redis基础分布式→Ray高性能分布式的全改造流程每个阶段配套「核心原理代码改造配置实操性能测试」量化各阶段性能提升同时指出各阶段瓶颈与优化点帮你实现爬虫性能从“百级QPS”到“千级QPS”的层层突破。改造前核心准备1. 环境与依赖# 基础依赖pipinstallscrapy scrapy-redis ray redis requests# 可选性能监控pipinstallpsutil matplotlib2. 基准场景定义爬取目标豆瓣电影Top250https://movie.douban.com/top250含电影名称、评分、简介性能指标QPS每秒爬取页面数、爬取完成耗时、资源利用率CPU/内存硬件环境测试机为4核8G单机分布式阶段扩展为3台同配置节点。阶段1原生Scrapy单机版基准线1. 核心目标搭建单机Scrapy爬虫跑通业务逻辑获取性能基准明确单机痛点。2. 单机Scrapy项目搭建步骤1创建项目与爬虫# 创建项目scrapy startproject douban_spidercddouban_spider# 创建爬虫scrapy genspider douban movie.douban.com步骤2核心代码编写1items.py数据结构importscrapyclassDoubanItem(scrapy.Item):titlescrapy.Field()# 电影名称scorescrapy.Field()# 评分introscrapy.Field()# 简介urlscrapy.Field()# 详情页URL2douban.py爬虫核心importscrapyfromdouban_spider.itemsimportDoubanItemclassDoubanSpider(scrapy.Spider):namedoubanallowed_domains[movie.douban.com]start_urls[https://movie.douban.com/top250]defparse(self,response):# 解析列表页movie_listresponse.xpath(//div[classinfo])formovieinmovie_list:itemDoubanItem()item[title]movie.xpath(.//span[classtitle][1]/text()).extract_first()item[score]movie.xpath(.//span[classrating_num]/text()).extract_first()item[intro]movie.xpath(.//span[classinq]/text()).extract_first()detail_urlmovie.xpath(.//a/href).extract_first()item[url]detail_urlyielditem# 翻页next_pageresponse.xpath(//span[classnext]/a/href).extract_first()ifnext_page:yieldscrapy.Request(urlresponse.urljoin(next_page),callbackself.parse)3settings.py核心配置单机版BOT_NAMEdouban_spiderSPIDER_MODULES[douban_spider.spiders]NEWSPIDER_MODULEdouban_spider.spiders# 反爬基础配置USER_AGENTMozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36ROBOTSTXT_OBEYFalse# 忽略robots.txt# 下载器配置DOWNLOAD_DELAY1# 单机延迟1s避免封禁CONCURRENT_REQUESTS16# 单机并发数# 管道配置临时输出到JSONFEEDS{douban_single.json:{format:json,encoding:utf-8,overwrite:True}}3. 单机性能测试# 运行单机爬虫记录耗时scrapy crawl douban --logfile single.log单机测试结果指标数值总爬取页面数250完成耗时4分20秒QPS≈0.96CPU利用率≈30%单核心满载多核闲置内存占用≈150MB4. 单机核心痛点GIL限制Scrapy基于Twisted异步但Python GIL导致多核CPU利用率极低仅单核心满载并发瓶颈单机并发数受限过高易被封IP且无法横向扩展容错性差单机崩溃则爬取中断需重新开始效率低下DOWNLOAD_DELAY导致单机QPS极低。阶段2Scrapy-Redis改造基础分布式1. 核心目标基于Scrapy-Redis实现分布式任务调度分布式去重利用多节点提升并发突破单机瓶颈。2. Scrapy-Redis核心原理组件单机ScrapyScrapy-Redis分布式任务队列本地内存队列Redis分布式队列spider:requests去重机制本地内存集合RFPDupeFilterRedis集合spider:dupefilter调度器本地调度器Redis调度器RedisScheduler数据存储本地文件可选Redis/分布式数据库3. 改造全流程步骤1Redis环境准备# 启动Redis任意节点推荐主节点redis-server --port6379--protected-mode no# 验证Redis连通性redis-cliping# 返回PONG即可步骤2代码改造1settings.py核心分布式配置# 继承Scrapy-Redis配置SCHEDULERscrapy_redis.scheduler.SchedulerDUPEFILTER_CLASSscrapy_redis.dupefilter.RFPDupeFilter# Redis连接配置替换为你的Redis地址REDIS_URLredis://192.168.1.100:6379/0# 任务持久化爬虫结束不清除Redis队列SCHEDULER_PERSISTTrue# 分布式并发配置多节点总并发控制CONCURRENT_REQUESTS32# 单节点并发3节点总并发96DOWNLOAD_DELAY0.2# 多节点分摊降低单IP延迟# 反爬强化USER_AGENT_LIST[Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36,Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) Safari/605.1.15]USER_AGENTlambda:random.choice(USER_AGENT_LIST)# 随机UA# 管道配置输出到Redis方便多节点聚合ITEM_PIPELINES{scrapy_redis.pipelines.RedisPipeline:300,}2douban.py爬虫改造支持分布式启动importscrapyimportrandomfromdouban_spider.itemsimportDoubanItemfromscrapy_redis.spidersimportRedisSpider# 替换为RedisSpiderclassDoubanSpider(RedisSpider):# 继承RedisSpider而非原生Spidernamedoubanallowed_domains[movie.douban.com]redis_keydouban:start_urls# Redis启动URL键名不再用start_urls# 随机UA从配置中取defmake_requests_from_url(self,url):headers{User-Agent:random.choice(self.settings.get(USER_AGENT_LIST))}returnscrapy.Request(url,headersheaders,callbackself.parse)defparse(self,response):# 保留原解析逻辑无修改movie_listresponse.xpath(//div[classinfo])formovieinmovie_list:itemDoubanItem()item[title]movie.xpath(.//span[classtitle][1]/text()).extract_first()item[score]movie.xpath(.//span[classrating_num]/text()).extract_first()item[intro]movie.xpath(.//span[classinq]/text()).extract_first()detail_urlmovie.xpath(.//a/href).extract_first()item[url]detail_urlyielditem next_pageresponse.xpath(//span[classnext]/a/href).extract_first()ifnext_page:yieldscrapy.Request(urlresponse.urljoin(next_page),callbackself.parse)步骤3分布式部署与运行1节点准备所有节点安装相同依赖scrapy、scrapy-redis、redis所有节点配置Redis地址确保能访问爬虫代码同步到所有节点推荐git/rsync。2启动流程# 步骤1主节点向Redis写入启动URLredis-cli -h192.168.1.100 lpush douban:start_urls https://movie.douban.com/top250# 步骤2所有节点启动爬虫3个节点分别执行# 节点1scrapy crawl douban --logfile node1.log# 节点2scrapy crawl douban --logfile node2.log# 节点3scrapy crawl douban --logfile node3.log4. Scrapy-Redis性能测试测试结果指标数值对比单机提升总爬取页面数250-完成耗时50秒≈5.2倍QPS≈5≈5.2倍单节点CPU利用率≈60%≈2倍总CPU利用率3节点≈80%≈2.7倍内存占用单节点≈200MB≈1.3倍5. Scrapy-Redis核心痛点Redis瓶颈任务队列/去重集合的读写成为分布式瓶颈节点数5时性能增长停滞资源调度弱无法弹性扩缩容节点资源利用率不均容错性一般Redis宕机则整个集群瘫痪无任务重试机制代码耦合高爬虫强依赖Scrapy-Redis组件改造成本高。阶段3Ray改造高性能分布式1. 核心目标基于Ray重构Scrapy爬虫实现弹性分布式调度资源精细化管控高性能任务分发突破Scrapy-Redis的Redis瓶颈。2. RayScrapy核心原理Ray作为分布式计算框架替代Redis做任务调度支持跨节点的轻量级任务分发将Scrapy爬虫封装为Ray Actor有状态/Task无状态利用Ray的资源调度实现弹性扩缩容任务队列基于Ray的Object Store读写性能远超Redis支持CPU/内存精细化分配避免资源浪费。3. 改造全流程步骤1Ray环境准备# 步骤1启动Ray集群主节点ray start --head --port6379--redis-password123456# 输出示例Ray runtime started. To connect to this Ray cluster, run:# ray start --address192.168.1.100:6379 --redis-password123456# 步骤2工作节点加入集群所有从节点执行ray start --address192.168.1.100:6379--redis-password123456# 验证集群状态ray status# 查看节点数、资源情况步骤2代码重构Ray封装Scrapy1核心改造思路将Scrapy爬虫拆分为“任务生产者URL生成”和“任务消费者爬取解析”生产者Ray Task负责生成待爬URL写入Ray队列消费者Ray Actor封装Scrapy爬取逻辑弹性扩缩容结果聚合Ray Actor负责汇总各节点爬取结果写入文件/数据库。2完整代码ray_scrapy_douban.pyimportrayimportscrapyimportrandomfromscrapy.crawlerimportCrawlerProcessfromscrapy.utils.projectimportget_project_settingsfromdouban_spider.itemsimportDoubanItem# 步骤1初始化Ray所有节点执行ray.init(addressauto,_redis_password123456)# 步骤2定义URL生产者Ray Task无状态ray.remotedefurl_producer(start_url):生成所有待爬URL模拟翻页urls[]# 模拟豆瓣Top250翻页共10页forpageinrange(10):ifpage0:urls.append(start_url)else:urls.append(f{start_url}?start{page*25}filter)returnurls# 步骤3定义爬取消费者Ray Actor有状态支持弹性扩缩容ray.remote(num_cpus1)# 每个Actor占用1核CPUclassCrawlerActor:def__init__(self):# 初始化Scrapy配置self.settingsget_project_settings()self.settings.update({USER_AGENT:Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36,ROBOTSTXT_OBEY:False,DOWNLOAD_DELAY:0.1,CONCURRENT_REQUESTS:16,})self.processCrawlerProcess(self.settings)self.results[]# 存储爬取结果defcrawl_url(self,url):爬取单个URL并返回结果classTempSpider(scrapy.Spider):nametempallowed_domains[movie.douban.com]start_urls[url]custom_settings{ITEM_PIPELINES:{},# 禁用管道直接返回结果LOG_LEVEL:ERROR,# 仅输出错误日志}defparse(self,response):movie_listresponse.xpath(//div[classinfo])formovieinmovie_list:itemDoubanItem()item[title]movie.xpath(.//span[classtitle][1]/text()).extract_first()item[score]movie.xpath(.//span[classrating_num]/text()).extract_first()item[intro]movie.xpath(.//span[classinq]/text()).extract_first()detail_urlmovie.xpath(.//a/href).extract_first()item[url]detail_url self.crawler.stats.set_value(item,item)# 存储Item到stats# 运行临时爬虫crawlerself.process.create_crawler(TempSpider)self.process.crawl(crawler)self.process.start()# 非阻塞启动# 获取爬取结果itemcrawler.stats.get_value(item)ifitem:self.results.append(item)returnitemdefget_results(self):返回当前Actor的爬取结果returnself.results# 步骤4定义结果聚合器Ray Actorray.remoteclassResultAggregator:def__init__(self):self.all_results[]defadd_result(self,result):添加单个爬取结果ifresult:self.all_results.append(result)defsave_results(self,file_path):保存所有结果到文件importjsonwithopen(file_path,w,encodingutf-8)asf:json.dump([dict(item)foriteminself.all_results],f,ensure_asciiFalse,indent2)returnf保存完成共{len(self.all_results)}条数据# 步骤5分布式爬取主逻辑defmain():# 1. 生成待爬URLstart_urlhttps://movie.douban.com/top250urlsray.get(url_producer.remote(start_url))print(f生成待爬URL数{len(urls)})# 2. 创建消费者Actor池弹性扩缩容3个节点共8个Actoractor_pool[CrawlerActor.remote()for_inrange(8)]# 3. 创建结果聚合器aggregatorResultAggregator.remote()# 4. 分布式爬取URL分发到Actorfutures[]fori,urlinenumerate(urls):actoractor_pool[i%len(actor_pool)]# 轮询分发futureactor.crawl_url.remote(url)futures.append(future)# 5. 收集结果并聚合forfutureinray.get(futures):aggregator.add_result.remote(future)# 6. 保存结果save_resultray.get(aggregator.save_results.remote(douban_ray.json))print(save_result)# 7. 关闭Rayray.shutdown()if__name____main__:main()步骤3Ray分布式运行# 步骤1确保Ray集群已启动主节点3个工作节点# 步骤2任意节点执行主脚本Ray自动分发任务python ray_scrapy_douban.py4. Ray改造性能测试测试结果指标数值对比Scrapy-Redis提升对比单机提升总爬取页面数250--完成耗时20秒≈2.5倍≈13倍QPS≈12.5≈2.5倍≈13倍集群CPU利用率≈90%≈1.1倍≈3倍内存占用单Actor≈100MB≈0.5倍更高效≈0.7倍弹性扩缩容响应时间5秒--5. Ray改造核心优势性能突破基于Ray的Object Store替代Redis任务分发性能提升2-3倍节点数扩展到10仍无瓶颈弹性扩缩容支持根据任务量自动增减Actor数量资源利用率提升至90%容错性强Ray自带任务重试、节点故障转移单个节点宕机不影响整体集群低耦合Scrapy爬虫仅做轻量封装无需强依赖第三方组件可复用原有业务逻辑资源精细化支持按CPU/内存/GPU分配资源避免资源浪费。全流程性能对比与优化建议1. 三阶段性能汇总阶段完成耗时QPSCPU利用率核心优势核心瓶颈原生Scrapy单机4分20秒0.9630%开发简单、无外部依赖GIL限制、多核闲置Scrapy-Redis50秒580%3节点基础分布式、易改造Redis瓶颈、资源调度弱Ray分布式20秒12.590%3节点高性能、弹性扩缩容代码改造量稍大2. 各阶段适用场景阶段适用场景原生Scrapy小量数据爬取、快速验证业务逻辑Scrapy-Redis中小规模分布式节点数≤5、改造成本优先Ray分布式大规模分布式节点数5、高性能/弹性优先3. 通用优化建议1反爬优化全阶段增加代理池参考前文《Python分布式爬虫避坑指南》避免单IP高频请求使用Playwright替代Scrapy下载器模拟真实浏览器行为请求头/COOKIE随机化降低被识别为爬虫的概率。2性能优化Scrapy-RedisRedis开启持久化AOFRDB避免任务丢失分片存储将任务队列按URL哈希分片到多个Redis实例突破单Redis瓶颈本地缓存节点本地缓存高频URL减少Redis访问。3性能优化RayActor池大小动态调整根据待爬URL数量自动增减Actor结果异步写入避免聚合器阻塞先写入本地缓存再批量同步Ray集群资源监控通过ray dashboard实时监控资源利用率调整Actor配置。避坑指南各阶段常见问题1. 原生Scrapy坑DOWNLOAD_DELAY设置过小导致IP封禁解结合目标网站反爬规则单机延迟≥1s分布式分摊后可降低。坑并发数过高导致内存溢出解CONCURRENT_REQUESTS建议≤32单机根据内存调整。2. Scrapy-Redis坑Redis连接数耗尽导致节点无法获取任务解配置Redis连接池max_connections100爬虫退出时关闭连接。坑多节点重复爬取同一URL解确保DUPEFILTER_CLASS正确配置Redis去重集合无过期。3. Ray坑Actor数量过多导致节点资源耗尽解设置Actor池最大数量如num_cpus1总Actor≤节点数×CPU核心数坑Ray集群节点无法通信解关闭防火墙确保节点间端口6379、8265互通Ray版本一致。总结从原生Scrapy单机到Scrapy-Redis基础分布式再到Ray高性能分布式改造的核心逻辑是先解决“能不能分布式”Scrapy-Redis再解决“分布式性能好不好”Ray单机阶段聚焦业务逻辑跑通分布式阶段聚焦资源利用率和并发提升选择改造方案时优先匹配业务规模小量用单机中量用Scrapy-Redis大量用Ray。掌握这套改造流程可将Scrapy爬虫的性能从“百级QPS”提升至“千级QPS”同时保证分布式集群的稳定性和弹性满足大规模数据采集的需求。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询