初步搭建并使用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中开启管道配置。管道可以有很多个并且有优先级,300是默认值,值越大优先级越小。

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)

第四步:运行项目。发现可以正常下载前三页的数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/893421.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python网络自动化运维---用户交互模块

文章目录 目录 文章目录 前言 实验环境准备 一.input函数 代码分段解析 二.getpass模块 前言 在前面的SSH模块章节中&#xff0c;我们都是将提供SSH服务的设备的账户/密码直接写入到python代码中&#xff0c;这样很容易导致账户/密码泄露&#xff0c;而使用Python中的用户交…

【2024年 CSDN博客之星】我的2024年创作之旅:从C语言到人工智能,个人成长与突破的全景回顾

我的2024年创作之旅&#xff1a;从C语言到人工智能&#xff0c;个人成长与突破的全景回顾 引言 回望2024年&#xff0c;我不仅收获了技术上的成长&#xff0c;更收获了来自CSDN平台上无数粉丝、朋友以及网友们的支持与鼓励。在这条创作之路上&#xff0c;CSDN不仅是我展示技术成…

【程序化广告】相关技术(RTB竞价原理、Cookie映射流程、数据统计原理、程序化创意、防作弊方法)

上一篇介绍了【程序化广告】广告投放流程/漏斗/要素/策略/指标&#xff0c;本篇介绍一下程序化广告所使用到的相关技术&#xff0c;包括RTB竞价原理、Cookie映射流程、数据统计原理、程序化创意、防作弊方法等。 1. RTB竞价原理 1&#xff09;竞价逻辑 用户开启电脑&#xf…

软件测试入门—用例设计中的场景图和状态迁移图

在软件测试领域&#xff0c;用例设计是一项至关重要的工作&#xff0c;它直接关系到软件质量的高低。而场景图和状态迁移图作为用例设计中的两种有效工具&#xff0c;能够帮助测试人员更全面、系统地设计测试用例。下面我们就来深入了解一下这两种图。 一、场景图 场景图主要…

数据表中的数据查询

文章目录 一、概述二、简单查询1.列出表中所有字段2.“*”符号表示所有字段3.查询指定字段数据4.DISTINCT查询 三、IN查询四、BETWEEN ADN查询1.符合范围的数据记录查询2.不符合范围的数据记录查询 五、LIKE模糊查询六、对查询结果排序七、简单分组查询1.统计数量2.统计计算平均…

前端Vue2项目使用md编辑器

项目中有一个需求&#xff0c;要在前端给用户展示内容&#xff0c;内容有 AI 生成的&#xff0c;返回来的是 md 格式&#xff0c;所以需要给用户展示 md 格式&#xff0c;并且管理端也可以编辑这个 md 格式的文档。 使用组件库 v-md-editor。 https://code-farmer-i.github.i…

Windows系统提示RunDLL PcaWallpaperAppDetect错误修复方法

最近&#xff0c;Win11 24H2预览版和Win10 LTSC 2025功能更新偶尔会触发RunDLL错误弹窗 具体表现为 //英文提示 Error in C:\WINDOWS\system32\PcaSvc.dll Missing entry: PcaWallpaperAppDetect//中文提示 C:\WINDOWS\system32\PcaSvc.dll出错 丢失条目:PcaWallpaperAppDe…

光谱相机在智能冰箱的应用原理与优势

食品新鲜度检测 详细可点击查看汇能感知团队实验报告&#xff1a;高光谱成像技术检测食物新鲜度 检测原理&#xff1a;不同新鲜程度的食品&#xff0c;其化学成分和结构会有所不同&#xff0c;在光谱下的反射、吸收等特性也存在差异。例如新鲜肉类和蔬菜中的水分、蛋白质、叶…

手写SOCKET进行HTTP通信

网络基础 我们电脑主板上都内置了多种网卡&#xff0c;一般主要有以下几类&#xff1a; 虚拟网卡&#xff08;loopback&#xff09; 注意&#xff0c;它是虚拟的&#xff0c;并不是物理网卡&#xff0c;也被称为是本地环回地址(或接口)&#xff0c;一般将127.0.0.1作为本地环回…

MFC程序设计(二)基于对话框编程

从现在开始&#xff0c;我们将以基于对话框的MFC应用程序来讲解MFC应用 向导生成基于对话框MFC应用程序 对话框是一种特殊类型的窗口&#xff0c;绝大多数Windows程序都通过对话框与用户进行交互。在Visual C中&#xff0c;对话框既可以单独组成一个简单的应用程序&#xff0…

Flink Gauss CDC:深度剖析存量与增量同步的创新设计

目录 设计思路 1.为什么不直接用FlinkCDC要重写Flink Gauss CDC 2.存量同步的逻辑是什么 2.1、单主键的切片策略是什么 2.2、​​​​​复合主键作切片&#xff0c;怎么保证扫描到所有的数据 3、增量同步的逻辑是什么 4、存量同步结束之后如何无缝衔接增量同步 5、下游…

idea新增java快捷键代码片段

最近在写一些算法题&#xff0c;有很多的List<List这种编写&#xff0c;想着能否自定义一下快捷键 直接在写代码输入&#xff1a;lli&#xff0c;即可看见提示

深度学习-91-大语言模型LLM之基于langchain的模型IO的提示模板

文章目录 1 Model的输入输出2 提示模板2.1 提示模板的特点2.2 提示模板的类型3 使用提示模板3.1 设置环境变量3.2 PromptTemplate提示模板3.2.1 通过from_template方法3.2.2 直接生成提示模板3.2.3 使用提示模板3.2.4 复用提示模板3.3 ChatPromptTemplate聊天提示模板3.3.1 通过…

stm8s单片机(二)外部中断实验

中断优先级 stm8的中断优先级不是固定不变的&#xff0c;stm8的中断分为硬件优先级与软件优先级&#xff1b;当多个中断发生时&#xff0c;cpu会先响应软件优先级高的中断&#xff0c;若软件优先级相同会先响应硬件优先级高的&#xff1b; 其中软件优先级有四个 /*** brief …

社区版Dify实现文生视频 LLM+ComfyUI+混元视频

社区版Dify实现文生视频 LLMComfyUI混元视频 一、 社区版Dify实现私有化混元视频效果二、为什么社区版Dify可以在对话框实现文生视频&#xff1f;LLMComfyUI混元视频 实现流程图&#xff08;重点&#xff09;1. 文生视频模型支持ComfyUI2. ComfyUI可以轻松导出API实现封装3. Di…

helm推送到harbor私有库--http: server gave HTTP response to HTTPS client

harbor私有库访问的是http模式 harbor 2.8版本以上可以存储helm镜像 docker镜像推送的时候需要docker端配置insecure-registries 发现helm推送只能在harbor部署的本机使用localhost才能推送成功&#xff0c;即 helm push xxx.tgz oci://localhost:80/library 使用helm pus…

transformers使用过程问题

transfomers新旧版本冲突&#xff0c;和accelerate、datasets、evaluate这些库直接也经常会发生冲突 我使用了下面的版本&#xff0c;暂时没有冲突&#xff0c;如果有冲突再更新 transformers4.41.2 datasets2.20.0 accelerate0.31.0 evaluate0.4.2pip install transformers安…

svn tag

一般发布版本前&#xff0c;需要在svn上打个tag。步骤如下&#xff1a; 1、空白处右击&#xff0c;选择TortoiseSVN->Branch/tag; 2、填写To path&#xff0c;即tag的路基以及tag命名&#xff08;一般用版本号来命名&#xff09;&#xff1b;填写tag信息&#xff1b;勾选cr…

【JavaSE】(8) String 类

一、String 类常用方法 1、构造方法 常用的这4种构造方法&#xff1a;直接法&#xff0c;或者传参字符串字面量、字符数组、字节数组。 在 JDK1.8 中&#xff0c;String 类的字符串实际存储在 char 数组中&#xff1a; String 类也重写了 toString 方法&#xff0c;所以可以直…

【理解工具调用的流程,本质体现了大模型智能性】

1、工具调用 调用完结果看里面tool_calls 是否为空&#xff0c;不为空就调用工具函数处理&#xff0c; 如果为空就中断循环。大模型返回的message结果智能判断是否继续调用 输入输出如下&#xff1a; 请输入&#xff1a;深圳西安天气 ------------------------------------…