初步搭建并使用Scrapy框架
目录
目标
版本
实战
搭建框架
获取图片链接、书名、价格
通过管道下载数据
通过多条管道下载数据
下载多页数据
目标
掌握Scrapy框架的搭建及使用,本文以爬取当当网魔幻小说为案例做演示。
版本
Scrapy 2.12.0
实战
搭建框架
第一步:在D:\pytharm_workspace位置创建爬虫Scrapy项目。通过cmd在该目录执行Scrapy创建项目命令。dangdang是我的项目名称。
scrapy startproject dangdang
第二步:进入项目目录,并创建爬虫类。其中magic_novels是我自定义的爬虫程序名称,permit.mee.gov.cn表示要爬取的网站域名。
第三步:注释在settings文件中掉OBOTSTXT_OBEY协议。
#ROBOTSTXT_OBEY = True
第四步:打开Pycharm控制台,进入项目目录。设置start_urls为我们要爬取的首页。parse表示项目启动后会自动请求start_urls中的URL。所以我们在parse方法中调试输出,并运行项目。
import scrapyclass MagicNovelsSpider(scrapy.Spider):name = "magic_novels"allowed_domains = ["category.dangdang.com"]start_urls = ["https://category.dangdang.com/cp01.03.40.00.00.00.html"]def parse(self, response):print(response.url)print(response.text)
scrapy crawl magic_novels
第五步:此时会打印很多的无用信息,我们可以在settings.py文件中设置日志级别。再次启动项目后会发现页面干净了很多。
LOG_LEVEL = "WARNING"
scrapy crawl magic_novels
注意:如果多次请求导致可能会导致缓存出现,请使用以下命令:
scrapy crawl magic_novels --set HTTPCACHE_ENABLED=False
获取图片链接、书名、价格
第一步:通过xpath爬取价格、图片、书名,我们先来打印调试。此时发现图片的链接不对,思考是否是懒加载的一个反扒策略。
def parse(self, response):'''图片的链接:src=//ul[@id='component_59']/li//img/@src图片的名称:alt=//ul[@id='component_59']/li//img/@alt图书的价格:price=//ul[@id='component_59']/li//p[@class='price']/span考虑到所有的数据都来源于//ul[@id='component_59']/li,所以我们可以复用li对象。'''li_list = response.xpath("//ul[@id='component_59']/li")for li in li_list:print(f'图片的链接:src={li.xpath(".//img/@src").extract_first()}')print(f'图片的名称:alt={li.xpath(".//img/@alt").extract_first()}')print(f'图书的价格:price={li.xpath(".//p[@class='price']/span[1]/text()").extract_first()}')print("\n")
第二步: 刷新页面,在浏览器检查中查看第一个和最后一个,发现图片链接的初始接收属性并不是src,而是data-original,src是加载以后才代替data-original的。
第三步:修改src获取的方法,并再次运行项目。发现除了第一个图书的src为None,其他src都正常获取了。猜测:是不是第一个图书打开时没有使用懒加载。
第四步: 通过调试发现,确实如刚才的猜想一般,第一个图书的src没有使用懒加载。修改代码后再次调试,发现可以获取到第一个图书的链接。
def parse(self, response):'''图片的链接:src=//ul[@id='component_59']/li//img/@src图片的名称:alt=//ul[@id='component_59']/li//img/@alt图书的价格:price=//ul[@id='component_59']/li//p[@class='price']/span考虑到所有的数据都来源于//ul[@id='component_59']/li,所以我们可以复用li对象。'''li_list = response.xpath("//ul[@id='component_59']/li")for i , li in enumerate(li_list):print(f'第{i+1}本书。')src = li.xpath(".//img/@data-original").get()if src is None:src = li.xpath(".//img/@src").get()alt = li.xpath(".//img/@alt").get()price = li.xpath(".//p[@class='price']/span[1]/text()").get()print(f'图片的链接:src={src}')print(f'图片的名称:alt={alt}')print(f'图书的价格:price={price}')print("\n")
通过管道下载数据
第一步:打开items.py文件,配置字段。
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.htmlimport scrapyclass DangdangItem(scrapy.Item):# 图片src = scrapy.Field()# 书名name = scrapy.Field()# 价格price = scrapy.Field()
第二步:将item类导入到爬虫程序。
import scrapyfrom dangdang.items import DangdangItemclass MagicNovelsSpider(scrapy.Spider):name = "magic_novels"allowed_domains = ["category.dangdang.com"]start_urls = ["https://category.dangdang.com/cp01.03.40.00.00.00.html"]def parse(self, response):'''图片的链接:src=//ul[@id='component_59']/li//img/@src图书的名称:alt=//ul[@id='component_59']/li//img/@alt图书的价格:price=//ul[@id='component_59']/li//p[@class='price']/span考虑到所有的数据都来源于//ul[@id='component_59']/li,所以我们可以复用li对象。'''li_list = response.xpath("//ul[@id='component_59']/li")for i , li in enumerate(li_list):print(f'第{i+1}本书。')src = li.xpath(".//img/@data-original").get()if src is None:src = li.xpath(".//img/@src").get()alt = li.xpath(".//img/@alt").get()price = li.xpath(".//p[@class='price']/span[1]/text()").get()print(f'图片的链接:src={src}')print(f'图书的名称:alt={alt}')print(f'图书的价格:price={price}')print("\n")#该对象要通过管道去下载,通过yield可以在每次获得book后立刻返回book给管道。book=DangdangItem(src=src, alt=alt, price=price);yield book
第三步:在settings.py中开启管道配置。管道可以有很多个并且有优先级,值越大优先级越小。
ITEM_PIPELINES = {"dangdang.pipelines.DangdangPipeline": 300,
}
第四步:来到pipelines.py文件,其中process_item方法中的item就是我们刚才在爬虫程序配置的boot对象。我们可以打印测试效果。
class DangdangPipeline:def process_item(self, item, spider):print(type(item))print(str(item))return item
scrapy crawl magic_novels
思考:我们通过process_item可以获取到数据,但是每次循环获取数据再重新打开文件、写入数据,关闭文件明显不符合开发规范。
第五步:在pipelines.py文件中配置open_spider和close_spider方法,分别表示在爬虫程序执行前执行的方法和在爬虫程序执行之后执行的方法。我们可以打印日志测试。
class DangdangPipeline:#在爬虫文件开始之前就执行的方法def open_spider(self, spider):print("++++")def process_item(self, item, spider):print(type(item))print(str(item))return item#在爬虫文件执行之后再执行的方法def close_spider(self, spider):print("----")
scrapy crawl magic_novels
第六步: 下载JSON数据。
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
import json# useful for handling different item types with a single interface
from itemadapter import ItemAdapterclass DangdangPipeline:#在爬虫文件开始之前就执行的方法def open_spider(self, spider):self.fp=open("book.json","w",encoding="utf-8")self.fp.write("[")def process_item(self, item, spider):line = json.dumps(dict(item), ensure_ascii=False) + ",\n"self.fp.write(line)return item#在爬虫文件执行之后再执行的方法def close_spider(self, spider):# 删除最后一个多余的逗号,并关闭 JSON 数组self.fp.seek(self.fp.tell() - 3, 0) self.fp.write("\n]")self.fp.close()
scrapy crawl magic_novels
通过多条管道下载数据
第一步:在pipelines.py文件中定义新的管道类。
#下载图片
class DangdangDownloadImgPipeline:# 在爬虫文件开始之前就执行的方法def open_spider(self, spider):passdef process_item(self, item, spider):print(item.get('src'))url="http:"+item.get('src')filename='C:/Users/Administrator/Desktop/test/'+sanitize_filename(item.get("alt"))+'.jpg'urllib.request.urlretrieve(url=url,filename=filename)return item# 在爬虫文件执行之后再执行的方法def close_spider(self, spider):passdef sanitize_filename(filename):"""替换 Windows 文件名中不合法的字符为下划线。"""# 定义 Windows 文件名不允许的字符invalid_chars = r'[\\/:*?"<>|]'# 使用正则表达式将非法字符替换为下划线return re.sub(invalid_chars, '_', filename)
第二步:在settings.py中定义该管道类的优先级。
ITEM_PIPELINES = {"dangdang.pipelines.DangdangPipeline": 300,"dangdang.pipelines.DangdangDownloadImgPipeline": 300,
}
第三步:执行下载操作,可以看到JSON数据和图片都下载成功了。
scrapy crawl magic_novels
下载多页数据
思考:目前我们只是下载了第一页的数据,能否通过配置页码下载多个页面的数据呢?
第一步:去页面点击下一页,发现链接都差不多,区别在于pg后面的跟的页码。
https://category.dangdang.com/pg2-cp01.03.40.00.00.00.html
https://category.dangdang.com/pg3-cp01.03.40.00.00.00.html
第二步:在爬虫程序中,设置基础的url和页码,页码初始化为第一页。
class MagicNovelsSpider(scrapy.Spider):name = "magic_novels"allowed_domains = ["category.dangdang.com"]start_urls = ["https://category.dangdang.com/cp01.03.40.00.00.00.html"]base_url="https://category.dangdang.com/pg"page_num=1;
第三步:在parse方法中递归请求当当网,每次请求都将url的页码改变。注意:递归逻辑写在循环之外。
import scrapyfrom dangdang.items import DangdangItemclass MagicNovelsSpider(scrapy.Spider):name = "magic_novels"allowed_domains = ["category.dangdang.com"]start_urls = ["https://category.dangdang.com/cp01.03.40.00.00.00.html"]base_url="https://category.dangdang.com/pg"page_num=1;def parse(self, response):'''图片的链接:src=//ul[@id='component_59']/li//img/@src图书的名称:alt=//ul[@id='component_59']/li//img/@alt图书的价格:price=//ul[@id='component_59']/li//p[@class='price']/span考虑到所有的数据都来源于//ul[@id='component_59']/li,所以我们可以复用li对象。'''li_list = response.xpath("//ul[@id='component_59']/li")for i , li in enumerate(li_list):print(f'第{i+1}本书。')src = li.xpath(".//img/@data-original").get()if src is None:src = li.xpath(".//img/@src").get()alt = li.xpath(".//img/@alt").get()price = li.xpath(".//p[@class='price']/span[1]/text()").get()print(f'图片的链接:src={src}')print(f'图书的名称:alt={alt}')print(f'图书的价格:price={price}')print("\n")#该对象要通过管道去下载,通过yield可以在每次获得book后立刻返回book给管道。book=DangdangItem(src=src, alt=alt, price=price);yield bookif self.page_num<3:self.page_num+=1url=self.base_url+str(self.page_num)+"-cp01.03.40.00.00.00.html";#GET请求yield scrapy.Request(url=url, callback=self.parse)
第四步:运行项目。发现可以正常下载前三页的数据。
相关文章:

初步搭建并使用Scrapy框架
目录 目标 版本 实战 搭建框架 获取图片链接、书名、价格 通过管道下载数据 通过多条管道下载数据 下载多页数据 目标 掌握Scrapy框架的搭建及使用,本文以爬取当当网魔幻小说为案例做演示。 版本 Scrapy 2.12.0 实战 搭建框架 第一步:在D:\pyt…...

基于SpringBoot的软件产品展示销售系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...

pycharm 运行远程环境问题 Error:Failed to prepare environment.
问题排查 拿到更详细的报错信息: Help > Diagnostic Tools > Debug Log Settings section: 添加下面的配置 com.intellij.execution.configurations.GeneralCommandLine 重显报错,我这里是再次运行代码打开 Help | Collect Logs and Diagnosti…...

Redis vs. 其他数据库:深度解析,如何选择最适合的数据库?
一、如何为项目选择合适的数据库? 选择合适的数据库是一个复杂的过程,需要综合考虑多个因素。下面几个维度来详细阐述: 1.数据模型 关系型数据库(RDBMS):适用于高度结构化、关联性强的数据,如电…...

HTB:Support[WriteUP]
目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 将靶机TCP开放端口号提取并保存 使用nmap对靶机TCP开放端口进行脚本、服务扫描 使用nmap对靶机TCP开放端口进行漏洞、系统扫描 使用nmap对靶机常用UDP端口进行开放扫描 使用ldapsearch…...
导出地图为pdf文件
有时我们只是想创建能共享的pdf文件,而不是将地图打印出来,arcpy的ExportToPDF()函数可以实现该功能. 操作方法: 1.在arcmap中打开目标地图 2.导入arcpy.mapping模块 import arcpy.mapping as mapping 3.引用当前活动地图文档,把该引用赋值给变量 mxd mapping.MapDocumen…...
Linux中关于glibc包编译升级导致服务器死机或者linux命令无法使用的情况
服务器上编译glibc2.29版本导致命令不能用 Inconsistency detected by ld.so: dl-call-libc-early-init.c: 37: _dl_call_libc_early_init: Assertion sym ! NULL failed!下面是造成不可用的原因 1.编译完gcc 2.29版本后,开始做映射,以达到能使用最新版…...

Golang Gin系列-8:单元测试与调试技术
在本章中,我们将探讨如何为Gin应用程序编写单元测试,使用有效的调试技术,以及优化性能。这包括设置测试环境、为处理程序和中间件编写测试、使用日志记录、使用调试工具以及分析应用程序以提高性能。 为Gin应用程序编写单元测试 设置测试环境…...

linux如何修改密码,要在CentOS 7系统中修改密码
要在CentOS 7系统中修改密码,你可以按照以下步骤操作: 步骤 1: 登录到系统 在登录提示符 localhost login: 后输入你的用户名。输入密码并按回车键。 步骤 2: 修改密码 登录后,使用 passwd 命令来修改密码: passwd 系统会提…...
Kafka后台启动命令
#保存日志 nohup ./kafka-server-start.sh ../config/server.properties > /path/to/logfile.log 2>&1 &#不保存日志 nohup ./kafka-server-start.sh ../config/server.properties >/dev/null 2>&1 & nohup: 是一个Unix/Linux命令,用于…...

使用Cline+deepseek实现VsCode自动化编程
不知道大家有没有听说过cursor这个工具,类似于AIVsCode的结合体,只要绑定chatgpt、claude等大模型API,就可以实现对话式自助编程,简单闲聊几句便可开发一个软件应用。 但cursor受限于外网,国内用户玩不了,…...

【redis初阶】redis客户端
目录 一、基本介绍 二、认识RESP(redis自定的应用层协议名称) 三、访问github的技巧 四、安装redisplusplus 4.1 安装 hiredis** 4.2 下载 redis-plus-plus 源码 4.3 编译/安装 redis-plus-plus 五、编写运行helloworld 六、redis命令演示 6.1 通用命令的…...

【ComfyUI专栏】ComfyUI 部署Kolors
什么是Kolors?我相信一定会有朋友可能第一次听说这个生图的模型,开始我也很难想象,这竟然是快手推出的可灵AI的项目,我们可以直接利用模型来生成图片和视频。 大家可以通过直接访问可灵AI的网址获取到可灵的项目,但是对于我们来说我们需要基于ComfyUI来生成必要的图片和视…...
深入了解 HTTP 头部中的 Accept-Encoding:gzip、deflate、br、zstd
在现代Web开发中,性能优化是至关重要的一部分。HTTP协议中的Accept-Encoding头部正是为性能提升提供了一个非常有效的方式,它告知服务器客户端能够理解并接收哪些压缩算法的响应内容。在这篇博客中,我们将详细探讨Accept-Encoding头部的作用&…...

【含代码】逆向获取 webpack chunk 下的__webpack_require__ 函数,获悉所有的模块以及模块下的函数
背景 Webpack 打包后的代码是不会直接暴露 __webpack_require__ 函数,目的是为了避免污染全局变量同时也为了保护 webpack 的打包后的模块都隐藏在闭包函数里,达到数据的安全性。 而有时我们为了测试某个函数,想直接获取这个内置函数&#…...
2025牛客寒假算法基础集训营2
H 一起画很大的圆! 看起来像是一道计算几何的题,实际上通过分析和猜想,是有O1复杂度的结论的。具体证明略,结论是三点越接近共线,得出的半径越大。 #include <bits/stdc.h> using namespace std; #define endl \…...
落地 ORB角点检测与sift检测
ORB角点检测 可以说ORB是由FAST、灰度质心和BRIEF等技术组合优化形成的,不过更准确地说,ORB是在FAST特征检测算法基础上,结合了灰度质心确定方向以及改进后的BRIEF描述子等技术形成的,以下是具体分析: • FAST特征检…...
16 分布式session和无状态的会话
在我们传统的应用中session存储在服务端,减少服务端的查询压力。如果以集群的方式部署,用户登录的session存储在该次登录的服务器节点上,如果下次访问服务端的请求落到其他节点上就需要重新生成session,这样用户需要频繁的登录。 …...

SpringBoot整合Swagger UI 用于提供接口可视化界面
目录 一、引入相关依赖 二、添加配置文件 三、测试 四、Swagger 相关注解 一、引入相关依赖 图像化依赖 Swagger UI 用于提供可视化界面: <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactI…...

如何实现滑动开关功能
文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了PageView这个Widget,本章回中将介绍Switch Widget.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 我们在这里介绍的Switch是指左右滑动的开关,常用来表示某项设置是打开还是关闭。Fl…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...

免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...