2026/1/12 1:14:10
网站建设
项目流程
网站logo怎么做透明,python编程快速上手,百度站长电脑版,微信优惠券网站怎么做Scrapy 框架的核心价值在于四大组件#xff08;Spider/Item/Pipeline/Downloader#xff09;的协同工作#xff0c;优秀的案例必然是组件职责清晰、配置优化合理、可复用性强的。
案例总览#xff08;梯度进阶#xff0c;覆盖核心组件#xff09;
案例序号案例名称核心…Scrapy 框架的核心价值在于四大组件Spider/Item/Pipeline/Downloader的协同工作优秀的案例必然是组件职责清晰、配置优化合理、可复用性强的。案例总览梯度进阶覆盖核心组件案例序号案例名称核心目标覆盖核心组件难度适用场景1博客园文章静态爬取双格式存储掌握组件基础协同、数据结构化与持久化Spider/Item/Pipeline/Downloader基础配置入门静态网页、小批量数据爬取2豆瓣电影Top250 分页爬取掌握Spider分页跟进、数据去重Spider核心进阶/Item/Pipeline/Downloader进阶静态分页网页、批量数据爬取3知乎专栏文章 MySQL 存储掌握Pipeline数据库持久化、配置解耦Pipeline核心进阶/其余组件全覆盖进阶数据长期存储、批量结构化数据4京东商品列表 动态网页爬取掌握Downloader拓展处理AJAX渲染Downloader进阶拓展/其余组件全覆盖高阶动态渲染网页、反爬较弱场景案例1博客园文章静态爬取双格式存储案例场景爬取博客园首页推荐文章的标题、作者、发布时间、文章链接将数据结构化后同时保存为JSON文件和Excel文件核心是验证四大组件的基础协同工作流程。核心准备创建Scrapy项目scrapy startproject cnblog_static_spider安装依赖Excel存储需额外安装pip install pandas openpyxl步骤1Item 组件数据结构化规范字段与清洗编辑项目中的items.py定义字段并添加基础数据清洗逻辑避免脏数据传递到Pipeline。importscrapyfromscrapy.loader.processorsimportMapCompose,TakeFirst# 自定义清洗函数对应Item字段的前置处理defclean_string(value):去除字符串前后空格、换行符、制表符ifisinstance(value,str):returnvalue.strip().replace(\n,).replace(\t,)returnvaluedefclean_url(value):补全相对链接为绝对链接防止博客园内部相对路径ifvalueandnotvalue.startswith(http):returnfhttps://www.cnblogs.com{value}returnvalueor未知链接# 定义文章Item严格对应爬取字段职责结构化前置清洗classCnblogStaticArticleItem(scrapy.Item):titlescrapy.Field(input_processorMapCompose(clean_string),# 调用自定义清洗函数output_processorTakeFirst()# 提取单个结果避免返回列表)authorscrapy.Field(input_processorMapCompose(clean_string),output_processorTakeFirst())publish_timescrapy.Field(input_processorMapCompose(clean_string),output_processorTakeFirst(),default未知时间# 可选字段设置默认值避免KeyError)linkscrapy.Field(input_processorMapCompose(clean_url),output_processorTakeFirst())步骤2Spider 组件爬取与解析核心业务逻辑在spiders/目录下创建cnblog_article_spider.py定义爬取规则解析响应并生成Item对象职责是发起请求、提取数据、传递Item。importscrapyfromcnblog_static_spider.itemsimportCnblogStaticArticleItemclassCnblogArticleSpider(scrapy.Spider):# 爬虫唯一标识运行时需指定namecnblog_static_article# 允许爬取的域名限制Downloader的爬取范围避免资源浪费allowed_domains[cnblogs.com]# 初始请求URL传递给Downloader下载start_urls[https://www.cnblogs.com/]# 核心解析方法处理Downloader返回的Response提取数据defparse(self,response):# 1. 用XPath定位文章列表Scrapy内置XPath/CSS解析高效稳定article_listresponse.xpath(//div[classpost-item])# 2. 遍历解析单篇文章数据forarticleinarticle_list:# 初始化Item对象承接结构化数据itemCnblogStaticArticleItem()# 3. 提取字段数据赋值给Item自动触发清洗逻辑item[title]article.xpath(.//a[classpost-item-title]/text()).extract()item[author]article.xpath(.//a[classpost-item-author]/text()).extract()item[publish_time]article.xpath(.//span[classpost-date]/text()).extract()item[link]article.xpath(.//a[classpost-item-title]/href).extract()# 4. 传递Item给Pipeline通过yield返回给引擎再转发到Pipelineyielditem步骤3Downloader 组件配置优化提升下载稳定性无需编写代码仅在settings.py中配置Downloader的核心参数职责是高效、安全地下载网页响应。# 1. 配置下载延迟避免高频请求被反爬单位秒DOWNLOAD_DELAY2# 2. 配置并发请求数全局/单域名平衡速度与反爬CONCURRENT_REQUESTS16# 全局最大并发CONCURRENT_REQUESTS_PER_DOMAIN8# 单域名最大并发# 3. 配置请求头模拟浏览器避免被识别为爬虫USER_AGENTMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36# 4. 配置超时时间请求超时后放弃避免阻塞DOWNLOAD_TIMEOUT30# 5. 禁用Cookie静态网页无需保持会话减少反爬风险COOKIES_ENABLEDFalse步骤4Pipeline 组件双格式持久化解耦数据处理编辑pipelines.py实现两个PipelineJSON存储Excel存储按优先级执行职责是数据后处理、去重、持久化。importjsonimportpandasaspdfromopenpyxlimportload_workbook# Pipeline 1JSON文件存储优先级300先执行classCnblogJsonPipeline:将Item数据保存到cnblog_articles.json追加模式避免覆盖defopen_spider(self,spider):爬虫启动时执行打开JSON文件初始化列表self.fileopen(cnblog_articles.json,a,encodingutf-8)self.item_list[]defprocess_item(self,item,spider):核心处理方法接收Item添加到列表self.item_list.append(dict(item))returnitem# 返回Item传递给下一个Pipelinedefclose_spider(self,spider):爬虫关闭时执行将列表数据写入JSON文件# 格式化写入保证可读性json.dump(self.item_list,self.file,ensure_asciiFalse,indent4)self.file.close()spider.logger.info(fJSON数据已保存cnblog_articles.json共{len(self.item_list)}条)# Pipeline 2Excel文件存储优先级400后执行classCnblogExcelPipeline:将Item数据保存到cnblog_articles.xlsx追加模式支持重复爬取def__init__(self):self.excel_pathcnblog_articles.xlsxself.item_list[]defprocess_item(self,item,spider):self.item_list.append(dict(item))returnitemdefclose_spider(self,spider):爬虫关闭时执行将数据写入Excel支持追加dfpd.DataFrame(self.item_list)try:# 若文件已存在追加写入不覆盖原有数据bookload_workbook(self.excel_path)withpd.ExcelWriter(self.excel_path,engineopenpyxl,modea,if_sheet_existsoverlay)aswriter:writer.bookbook startrowwriter.sheets[Sheet1].max_row# 从下一行开始写入df.to_excel(writer,sheet_nameSheet1,startrowstartrow,indexFalse,headerFalse)exceptFileNotFoundError:# 若文件不存在创建新文件并写入df.to_excel(self.excel_path,sheet_nameSheet1,indexFalse)spider.logger.info(fExcel数据已保存{self.excel_path}共{len(self.item_list)}条)步骤5启用Pipeline运行爬虫在settings.py中启用Pipeline配置优先级数字越小优先级越高ITEM_PIPELINES{cnblog_static_spider.pipelines.CnblogJsonPipeline:300,cnblog_static_spider.pipelines.CnblogExcelPipeline:400,}终端运行爬虫进入项目根目录scrapy crawl cnblog_static_article案例验证与核心亮点验证结果项目根目录生成cnblog_articles.json和cnblog_articles.xlsx数据无空值、格式统一核心亮点四大组件职责清晰Item实现前置清洗Pipeline实现解耦存储Downloader配置兼顾速度与反爬符合Scrapy架构设计思想。案例2豆瓣电影Top250 分页爬取带数据去重案例场景爬取豆瓣电影Top250的电影名称、评分、简介、详情链接自动跟进分页共10页通过Pipeline去重避免重复爬取同一部电影最终保存为Excel文件核心是掌握Spider的分页跟进能力和Pipeline的去重逻辑。核心难点与解决思路分页跟进豆瓣Top250分页URL规律为https://movie.douban.com/top250?start0filterstart从0开始每次25通过循环生成分页URL或解析下一页链接跟进数据去重以电影名称评分为唯一标识通过Pipeline中的集合存储已爬取数据实现去重。关键组件实现仅展示核心差异部分其余组件类似案例11. Spider 组件分页跟进核心进阶在spiders/目录下创建douban_top250_spider.pyimportscrapyfromcnblog_static_spider.itemsimportDoubanTop250Item# 需提前在items.py定义对应字段classDoubanTop250Spider(scrapy.Spider):namedouban_top250allowed_domains[movie.douban.com]# 初始URL第一页start_urls[https://movie.douban.com/top250]defparse(self,response):# 1. 解析当前页电影数据movie_listresponse.xpath(//div[classitem])formovieinmovie_list:itemDoubanTop250Item()item[movie_name]movie.xpath(.//span[classtitle][1]/text()).extract()item[score]movie.xpath(.//span[classrating_num]/text()).extract()item[intro]movie.xpath(.//span[classinq]/text()).extract()item[detail_link]movie.xpath(.//div[classhd]/a/href).extract()yielditem# 2. 分页跟进解析下一页链接递归爬取next_pageresponse.xpath(//span[classnext]/a/href).extract_first()ifnext_page:# 补全绝对URL发起新请求传递给Downloader下载next_page_urlfhttps://movie.douban.com/top250{next_page}yieldscrapy.Request(urlnext_page_url,callbackself.parse# 回调自身继续解析下一页)2. Pipeline 组件数据去重核心进阶在pipelines.py中添加去重Pipeline优先级高于存储PipelineclassDoubanDuplicatePipeline:电影数据去重Pipeline基于电影名称评分去重def__init__(self):# 初始化集合存储已爬取的名称评分唯一标识self.movie_identifiersset()defprocess_item(self,item,spider):# 构建唯一标识避免单一字段重复movie_nameitem.get(movie_name,)movie_scoreitem.get(score,)identifierf{movie_name}_{movie_score}ifidentifierinself.movie_identifiers:# 重复数据丢弃并记录日志raisescrapy.exceptions.DropItem(f重复电影数据{movie_name}评分{movie_score})else:# 非重复数据添加到集合并传递给下一个Pipelineself.movie_identifiers.add(identifier)returnitem3. 运行与验证启用Pipeline在settings.py中配置去重Pipeline优先级最高运行爬虫scrapy crawl douban_top250验证结果Excel文件中无重复电影共250条数据分页跟进正常。案例3知乎专栏文章 MySQL 存储进阶持久化案例场景爬取知乎指定专栏的文章标题、作者、发布时间、阅读量、文章链接将结构化数据存入MySQL数据库核心是掌握Pipeline的数据库持久化逻辑实现数据的长期存储和后续分析。核心准备安装MySQL驱动pip install pymysqlMySQL中创建数据库和表-- 创建数据库CREATEDATABASEIFNOTEXISTSzhihu_spiderDEFAULTCHARACTERSETutf8mb4COLLATEutf8mb4_unicode_ci;-- 切换数据库USEzhihu_spider;-- 创建文章表CREATETABLEIFNOTEXISTSzhihu_column_article(idINTAUTO_INCREMENTPRIMARYKEYCOMMENT自增ID,titleVARCHAR(255)NOTNULLCOMMENT文章标题,authorVARCHAR(100)NOTNULLCOMMENT文章作者,publish_timeVARCHAR(50)COMMENT发布时间,read_countINTDEFAULT0COMMENT阅读量,linkVARCHAR(255)UNIQUECOMMENT文章详情链接唯一约束,create_timeDATETIMEDEFAULTCURRENT_TIMESTAMPCOMMENT入库时间)ENGINEInnoDBDEFAULTCHARSETutf8mb4COMMENT知乎专栏文章表;关键组件实现Pipeline 数据库持久化在pipelines.py中实现MySQL存储Pipeline核心是数据库连接池管理、数据插入、异常处理importpymysqlfromtwisted.enterpriseimportadbapi# Scrapy内置异步数据库连接库classZhihuMysqlPipeline:知乎专栏文章MySQL存储Pipeline异步插入提升效率def__init__(self,db_pool):self.db_pooldb_poolclassmethoddeffrom_settings(cls,settings):从settings.py中读取数据库配置初始化连接池db_params{host:settings.get(MYSQL_HOST),port:settings.get(MYSQL_PORT),user:settings.get(MYSQL_USER),password:settings.get(MYSQL_PASSWORD),db:settings.get(MYSQL_DB),charset:utf8mb4,cursorclass:pymysql.cursors.DictCursor# 游标类型}# 创建异步数据库连接池db_pooladbapi.ConnectionPool(pymysql,**db_params)returncls(db_pool)defprocess_item(self,item,spider):异步插入数据避免阻塞爬虫进程queryself.db_pool.runInteraction(self.insert_item,item)# 处理插入异常query.addErrback(self.handle_error,item,spider)returnitemdefinsert_item(self,cursor,item):执行数据插入SQL避免SQL注入使用参数化查询insert_sql INSERT INTO zhihu_column_article (title, author, publish_time, read_count, link) VALUES (%s, %s, %s, %s, %s) ON DUPLICATE KEY UPDATE # 唯一约束冲突时更新阅读量避免重复插入 read_count VALUES(read_count), publish_time VALUES(publish_time) # 提取Item数据转换格式data(item.get(title,),item.get(author,),item.get(publish_time,),int(item.get(read_count,0)),item.get(link,))# 执行SQLcursor.execute(insert_sql,data)defhandle_error(self,failure,item,spider):处理数据库插入异常记录日志spider.logger.error(f数据库插入失败{failure}数据{item})配置与运行在settings.py中添加MySQL配置解耦方便修改# MySQL 数据库配置MYSQL_HOST127.0.0.1MYSQL_PORT3306MYSQL_USERroot# 你的MySQL用户名MYSQL_PASSWORD123456# 你的MySQL密码MYSQL_DBzhihu_spider启用MySQL Pipeline运行爬虫验证结果MySQL中zhihu_column_article表已存入数据无重复字段格式统一。案例4京东商品列表 动态网页爬取Downloader 拓展案例场景爬取京东某商品分类列表的商品名称、价格、销量、商品链接由于京东商品列表是AJAX动态渲染静态HTML中无完整数据需通过Scrapy-Splash拓展Downloader实现动态网页的下载和解析核心是掌握Downloader的进阶拓展能力。核心准备安装Scrapy-Splashpip install scrapy-splash启动Splash服务需安装Docker拉取镜像并运行# 拉取Splash镜像dockerpull scrapinghub/splash# 运行Splash服务端口8050dockerrun -p8050:8050 scrapinghub/splash关键配置与实现Downloader 拓展在settings.py中配置Splash中间件拓展Downloader处理动态渲染# 启用Splash下载中间件DOWNLOADER_MIDDLEWARES{scrapy_splash.SplashCookiesMiddleware:723,scrapy_splash.SplashMiddleware:725,scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware:810,}# Splash服务地址SPLASH_URLhttp://127.0.0.1:8050# 配置Splash去重过滤器DUPEFILTER_CLASSscrapy_splash.SplashAwareDupeFilter# 配置缓存策略HTTPCACHE_STORAGEscrapy_splash.SplashAwareFSCacheStorageSpider 组件发起Splash请求解析动态数据importscrapyfromscrapy_splashimportSplashRequestfromcnblog_static_spider.itemsimportJdProductItemclassJdProductSpider(scrapy.Spider):namejd_productallowed_domains[jd.com]# 定义Splash Lua脚本实现动态页面渲染等待数据加载splash_lua_script function main(splash, args) splash:go(args.url) # 访问目标URL splash:wait(3) # 等待3秒让页面动态渲染完成 splash:scroll_position({y1000}) # 滚动页面加载更多商品 splash:wait(2) # 再等待2秒确保数据加载完整 return splash:html() # 返回渲染后的完整HTML end defstart_requests(self):发起Splash请求替代普通scrapy.Request实现动态渲染start_urlhttps://list.jd.com/list.html?cat652,12345,12346# 京东商品分类URLyieldSplashRequest(urlstart_url,callbackself.parse,endpointexecute,# 执行Lua脚本args{lua_source:self.splash_lua_script,url:start_url})defparse(self,response):解析Splash返回的动态渲染HTML与静态解析逻辑一致product_listresponse.xpath(//div[classgl-item])forproductinproduct_list:itemJdProductItem()item[product_name]product.xpath(.//div[classp-name]/a/em/text()).extract()item[price]product.xpath(.//div[classp-price]/strong/i/text()).extract()item[sales]product.xpath(.//div[classp-commit]/strong/a/text()).extract()item[link]product.xpath(.//div[classp-name]/a/href).extract()yielditem运行与验证确保Splash服务正常运行http://127.0.0.1:8050可访问运行爬虫scrapy crawl jd_product验证结果成功提取商品数据无空值说明Downloader拓展成功动态页面渲染完成。