爬虫 scrapy ——scrapy shell调试及下载当当网数据(十一)

目录

一、scrapy shell

1.什么是scrapy shell?

 2.安装 ipython

3.使用scrapy shell

二、当当网案例

1.在items.py中定义数据结构

2.在dang.py中解析数据

3.使用pipeline保存

4.多条管道的使用

5.多页下载

参考


一、scrapy shell

1.什么是scrapy shell?

什么是scrapy shell?

        scrapy终端,是一个交互终端,供您在未启动spider的情况下尝试及调试您的爬取代码。其本意是用来测试提取数据的代码,不过您可以将其作为正常的python终端,在上面测任何的python代码。该终端是用来测试Xpath或css表达式,查看他们的工作方式及从爬取的网页中提取的数据。在编写您的spider时,一旦熟悉了scrapy终端后,您会发现其在开发和调试spider时发挥的最大作用。

 2.安装 ipython

安装ipython

        pip install ipython 

        安装ipython后,scrapy终端将使用ipython代替python终端,ipython终端与其他相比更为强大,提供智能的自动补全,高亮输出及其他特性。

3.使用scrapy shell

在终端输入以下命令

scrapy shell 域名

eg:scrapy shell www.baidu.com

输出:进入到ipython

以上命令返回了一个response,可以直接使用

如下所示:可以调试返回的结果

二、当当网案例

目标:爬取当当网目标图书类目的所有图片、书名和价格,实现三者并行下载。

1.在items.py中定义数据结构

定义要获取的图片、书名和价格

class Scrapy095Item(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()# 通俗地讲就是你下载的数据都有什么# 爬取图片img = scrapy.Field()# 爬取书名name = scrapy.Field()# 爬取价格price = scrapy.Field()pass

2.在dang.py中解析数据

同时下载书名、图片和价格,找到三者共在的标签 ‘ul’

定位Xpath路径,我们之前是这样写的,获取了每个内容的列表,但是我们想要的是书名、图片和价格相对应的结果。

# 找到三者共同所在的标签
img = response.xpath('//ul[@id="component_59"]/li//img/@src')
name = response.xpath('//ul[@id="component_59"]/li//img/@alt')
response.xpath('//ul[@id="component_59"]/li//p[@class="price"]/span[1]/text()')

所以我们现在这样写:

调用selector下的Xpath,可以同时获取一个 li 中的三个内容。

# 所有selector对象可以在此调用 Xpath方法
li_list = response.xpath('//ul[@id="component_59"]/li')
for li in li_list:img = li.xpath('.//img/@src').extract_first()name = li.xpath('.//img/@alt').extract_first()price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()print(img,name,price)

这样就获取到了。 

但是发现,图片全都为 “none”,这是因为网页的懒加载造成的,避免网页一下子加载太多数据。

所以我们要找到真正的图片链接,即 ‘data-original’,而不是‘src’。

然后我们修改路径,得到下面结果。

又发现了问题,我们并没有拿到第一个数据的链接,因为第一个数据没有‘data-original’属性。

修改为以下代码

 # 所有selector对象可以在此调用 Xpath方法
li_list = response.xpath('//ul[@id="component_59"]/li')
for li in li_list:# 第一章图片的链接在 src 里# 其余图片的链接在 data-original 里img = li.xpath('.//img/@data-original').extract_first()if img:img = imgelse:img = li.xpath('.//img/@src').extract_first()name = li.xpath('.//img/@alt').extract_first()price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()print(img,name,price)

 这样我们就获取到了所有数据

3.使用pipeline保存

将数据交给 pipeline,添加最后两行代码。

调用 items.py 中的 Scrapy095Item 类。其中img=,name=和price=为 items.py中定义的变量。

# 所有selector对象可以在此调用 Xpath方法
li_list = response.xpath('//ul[@id="component_59"]/li')
for li in li_list:# 第一章图片的链接在 src 里# 其余图片的链接在 data-original 里img = li.xpath('.//img/@data-original').extract_first()if img:img = imgelse:img = li.xpath('.//img/@src').extract_first()name = li.xpath('.//img/@alt').extract_first()price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()print(img,name,price)book = Scrapy095Item(img=img,name=name,price=price)# 将 book 交给 pipeline 下载yield book

什么是yield?        

        带有yield的函数可以视作一个生成器generator,可用于迭代。yield是一个类似于return的关键字,迭代一个遇到yield时就返回yield后面的值。重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码开始执行。

        也就是说,yield会不断把book传递给pipeline。

如果要使用管道的话,就要在 settings.py 中开启管道,解开注释。

在 pipelines.py 中保存数据

# 如果要使用管道的话,就要在 settings.py 中开启管道
class Scrapy095Pipeline:# item 就是 yield 的返回值def process_item(self, item, spider):# 保存数据with open('book.json','a', encoding='utf-8') as file:# 存在的问题# item 是一个对象,需要将其转换为 str# 写文件的方式要改为 ‘a’ 追加模式,而不是 ‘w’覆盖模式。file.write(str(item))return item

需要注意的是:

        item 是一个对象,需要将其转换为 str

        写文件的方式要改为 ‘a’ 追加模式,而不是 ‘w’覆盖模式。

这样就把内容保存下载来了

但是这样写文件的缺点是,写数据时需要频繁的打开关闭文件,对文件的操作过于频繁。

所以我们只要打开并关闭一次文件

定义两个函数 open_spider 和 close_spider ,这两个函数是 scrapy的内置函数,可以操作文件只打开或者关闭一次。

# 如果要使用管道的话,就要在 settings.py 中开启管道
class Scrapy095Pipeline:# 在爬虫文件开始之前就执行的一个文件def open_spider(self, spider):print('++++++++++++++++++++++++++')self.fp = open('book.json','w',encoding='utf-8')# item 就是 yield 的返回值def process_item(self, item, spider):# 我们不这样保存# # 保存数据# with open('book.json','a', encoding='utf-8') as file:#     # 存在的问题#     # item 是一个对象,需要将其转换为 str#     # 写文件的方式要改为 ‘a’ 追加模式,而不是 ‘w’覆盖模式。#     file.write(str(item))self.fp.write(str(item))return item# 在爬虫文件执行完之后再执行的方法def close_spider(self, spider):print('----------------------')self.fp.close()

4.多条管道的使用

在 pipelines.py 中添加一个类,模仿上一个类写,用来下载图片,注意,这个类中定义的方法要与上一个类相同,然后我们在这个类中写下载图片的代码,最后返回 item

import urllib.request
# 多条管道开启
# (1)定义管道类
# (2)在settings中开启管道
class Scrapy095_download_Pipeline:def process_item(self, item, spider):url = 'http:' + item.get('img')filename = './books/' + item.get('name') + '.jpg'urllib.request.urlretrieve(url=url, filename=filename)return item

重要的是,我们要为下图片创建一个新管道,才能实现JSON数据保存和图片下载的同时进行。

在 settings.py 中新添加一个管道,修改的名字就是我们定义的类名。

这样再运行爬虫文件,就可以得到JSON文件和所有的图片了。

5.多页下载

找一下每一页的url之间的规律

# http://category.dangdang.com/pg2-cp01.36.04.00.00.00.html

# http://category.dangdang.com/pg3-cp01.36.04.00.00.00.html

# http://category.dangdang.com/pg4-cp01.36.04.00.00.00.html

可以看到,只有page不一样

所以我们可以在 dang.py 的类中定义一个url_base。

url_base = 'http://category.dangdang.com/pg'
page = 1

然后在 parse方法中添加以下代码

使用 yield 将新的url再传递给 parse() 方法。

# 多个页面的请求
# 每一页爬取的业务逻辑都是一样的,所以我们只需要将执行的那个页的请求再次调用parse方法
# http://category.dangdang.com/pg2-cp01.36.04.00.00.00.html
# http://category.dangdang.com/pg3-cp01.36.04.00.00.00.html
# http://category.dangdang.com/pg4-cp01.36.04.00.00.00.htmlif self.page < 10:self.page = self.page + 1url = self.url_base + str(self.page) + '-cp01.36.04.00.00.00.html'# 怎么调用 parse 方法# scrapy.Request 就是scrapy的get请求# url 就是请求地址,callback就是你要执行的那个函数,不需要加‘ () ’yield scrapy.Request(url=url, callback=self.parse)

完整代码:

dang.py

import scrapy
from ..items import Scrapy095Itemclass DangSpider(scrapy.Spider):name = 'dang'# 如果是多页下载,allowed_domains只保留域名,去掉协议和地址,为的是扩大允许范围allowed_domains = ['category.dangdang.com']start_urls = ['http://category.dangdang.com/cp01.36.04.00.00.00.html']url_base = 'http://category.dangdang.com/pg'page = 1def parse(self, response):print('=============================')# pipeline  下载数据# items     定义数据结构# 找到三者共同所在的标签# img = response.xpath('//ul[@id="component_59"]/li//img/@data-original')# name = response.xpath('//ul[@id="component_59"]/li//img/@alt')# price = response.xpath('//ul[@id="component_59"]/li//p[@class="price"]/span[1]/text()')# 所有selector对象可以在此调用 Xpath方法li_list = response.xpath('//ul[@id="component_59"]/li')for li in li_list:# 第一章图片的链接在 src 里# 其余图片的链接在 data-original 里img = li.xpath('.//img/@data-original').extract_first()if img:img = imgelse:img = li.xpath('.//img/@src').extract_first()name = li.xpath('.//img/@alt').extract_first()price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()print(img,name,price)book = Scrapy095Item(img=img,name=name,price=price)# 将 book 交给 pipeline 下载yield book# 多个页面的请求# 每一页爬取的业务逻辑都是一样的,所以我们只需要将执行的那个页的请求再次调用parse方法# http://category.dangdang.com/pg2-cp01.36.04.00.00.00.html# http://category.dangdang.com/pg3-cp01.36.04.00.00.00.html# http://category.dangdang.com/pg4-cp01.36.04.00.00.00.htmlif self.page < 10:self.page = self.page + 1url = self.url_base + str(self.page) + '-cp01.36.04.00.00.00.html'# 怎么调用 parse 方法# scrapy.Request 就是scrapy的get请求# url 就是请求地址,callback就是你要执行的那个函数,不需要加‘ () ’yield scrapy.Request(url=url, callback=self.parse)print('=============================')

items.py

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.htmlimport scrapyclass Scrapy095Item(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()# 通俗地讲就是你下载的数据都有什么# 爬取图片img = scrapy.Field()# 爬取书名name = scrapy.Field()# 爬取价格price = scrapy.Field()pass

pipelines.py

# 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# useful for handling different item types with a single interface
from itemadapter import ItemAdapter# 如果要使用管道的话,就要在 settings.py 中开启管道
class Scrapy095Pipeline:# 在爬虫文件开始之前就执行的一个文件def open_spider(self, spider):print('++++++++++++++++++++++++++')self.fp = open('book.json', 'w', encoding='utf-8')# item 就是 yield 的返回值def process_item(self, item, spider):# 我们不这样保存# # 保存数据# with open('book.json','a', encoding='utf-8') as file:#     # 存在的问题#     # item 是一个对象,需要将其转换为 str#     # 写文件的方式要改为 ‘a’ 追加模式,而不是 ‘w’覆盖模式。#     file.write(str(item))self.fp.write(str(item))return item# 在爬虫文件执行完之后再执行的方法def close_spider(self, spider):print('----------------------')self.fp.close()import urllib.request
# 多条管道开启
# (1)定义管道类
# (2)在settings中开启管道
class Scrapy095_download_Pipeline:def process_item(self, item, spider):url = 'http:' + item.get('img')filename = './books/' + item.get('name') + '.jpg'urllib.request.urlretrieve(url=url, filename=filename)return item

settings.py 中只 取消ROBOTSTXT_OBEY的注释,并添加下面的管道。

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {# 管道可以有很多个,但管道是有优先级的,优先级范围是 1-1000, 值越小,优先级越高。'scrapy_095.pipelines.Scrapy095Pipeline': 300,'scrapy_095.pipelines.Scrapy095_download_Pipeline': 301,
}

参考

尚硅谷Python爬虫教程小白零基础速通(含python基础+爬虫案例)

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

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

相关文章

【如何提取React项目中的公共模块,多个项目共用】

文章目录 目录 前言 一、创建公共模块 二、初始化公共模块 三、给公共模块添加内容 四、添加对公共模块的依赖 五、使用公共模块里的资源 后记 前言 在工作中经常会遇到这样的需求&#xff0c;有个React项目&#xff0c;代码分为客户端&#xff0c;管理端两份&#xff…

Vue3-21-组件-子组件给父组件发送事件

情景描述 【子组件】中有一个按钮&#xff0c;点击按钮&#xff0c;触发一个事件&#xff0c; 我们希望这个事件的处理逻辑是&#xff0c;给【父组件】发送一条消息过去&#xff0c; 从而实现 【子组件】给【父组件】通信的效果。这个问题的解决就是 “发送事件” 这个操作。 …

arthas获取spring bean

参考文章 arthas获取spring bean 写一个工具Util package com.example.lredisson.util;import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import o…

HarmonyOS给应用添加消息通知

给您的应用添加通知 通知介绍 通知旨在让用户以合适的方式及时获得有用的新消息&#xff0c;帮助用户高效地处理任务。应用可以通过通知接口发送通知消息&#xff0c;用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用&#xff0c;通知主要有以下使用场景…

Cell Systems | 深度学习开启蛋白质设计新时代

今天为大家介绍的是来自Bruno Correia团队的一篇综述。深度学习领域的迅速进步对蛋白质设计产生了显著影响。最近&#xff0c;深度学习方法在蛋白质结构预测方面取得了重大突破&#xff0c;使我们能够得到数百万种蛋白质的高质量模型。结合用于生成建模和序列分析的新型架构&am…

相机倾斜棋盘格标定全记录 vs200+opencv安装

论文参考是这个 Geiger A, Moosmann F, Car , et al. Automatic camera and range sensor calibration using a single shot[C]//Robotics and Automation (ICRA), 2012 IEEE International Conference on. IEEE, 2012: 3936-3943. 代码是这个github 花了一上午配好了c环境。。…

Flink系列之:SQL提示

Flink系列之&#xff1a;SQL提示 一、动态表选项二、语法三、例子四、查询提示五、句法六、加入提示七、播送八、随机散列九、随机合并十、嵌套循环十一、LOOKUP十二、进一步说明十三、故障排除十四、连接提示中的冲突案例十五、什么是查询块 SQL 提示可以与 SQL 语句一起使用来…

Sci. Rep. | 一个对任意分子体系实现准确且高效几何深度学习的通用框架

这篇工作是来自纽约城市大学/康奈尔医学院谢磊团队的一篇论文。作者提出了一个通用框架&#xff0c;PAMNet&#xff0c;可以对任意分子体系实现准确且高效的几何深度学习。在小分子性质、RNA三维结构以及蛋白质-配体结合亲和力的预测任务上&#xff0c;PAMNet在准确性和效率方面…

【ESXi】ESXi 版本回退

目录 8. ESXi 版本回退8.1 版本回退条件与注意事项8.2 版本回退步骤8.3 示例演示&#xff08;1&#xff09;准备工作&#xff08;2&#xff09;进入DCUI界面&#xff08;3&#xff09;按 F11 重启系统引导&#xff08;4&#xff09;进入引导选项&#xff08;5&#xff09;进入 …

弧形导轨的精度等级

为符合工控自动化生产制造必须&#xff0c;弧形导轨在运输武器装备领域应时而生&#xff0c;并已在电子生产制造、手机上、半导体材料、动力锂电池等领域获得广泛运用。其中&#xff0c;弧形导轨的精度等级是评估其运动精度的重要指标&#xff0c;通常包括制造精度和运行精度两…

Flink系列之:大状态与 Checkpoint 调优

Flink系列之&#xff1a;大状态与 Checkpoint 调优 一、概述二、监控状态和 Checkpoints三、Checkpoint 调优四、RocksDB 调优五、增量 Checkpoint六、RocksDB 或 JVM 堆中的计时器七、RocksDB 内存调优八、容量规划九、压缩十、Task 本地恢复十一、主要&#xff08;分布式存储…

spring-kakfa依赖管理之org/springframework/kafka/listener/CommonErrorHandler错误

问题&#xff1a; 整个项目使用spring-boot2.6.8版本&#xff0c;使用gradle构建&#xff0c;在common模块指定了implementation org.springframework.kafka:spring-kafka:2.6.8’这个工程也都能运行&#xff08;这正常发送kafka消息和接收消息&#xff09;&#xff0c;但是执行…

java --- 集合进阶

目录 一、单列集合顶层接口 Collection 1.1 基本方法 1.2 Collection 的遍历方式 二、list集合 1.2 ArrayList Vector 底层结构 1.3 LinkedList ArrayList 和 LinkedList 比较 三、set接口 3.1、Set 接口和常用方法 3.2 HashSet HashSet 底层机制&#xff08;HashMap…

Python【Matplotlib】图例可拖动改变位置

代码&#xff1a; import matplotlib.pyplot as plt from matplotlib.widgets import Button# 创建一个示例图形 fig, ax plt.subplots() line, ax.plot([1, 2, 3], labelLine 1)# 添加图例 legend ax.legend(locupper right, draggableTrue)# 添加一个按钮&#xff0c;用于…

mybatis动态SQL-sql片段

1、建库建表 create database mybatis-example; use mybatis-example; create table emp (empNo varchar(40),empName varchar(100),sal int,deptno varchar(10) ); insert into emp values(e001,张三,8000,d001); insert into emp values(e002,李四,9000,d001); insert into…

简单电子报警器设计与制作方法

简单电子报警器设计与制作方法 注&#xff1a; 1、按上图连接好。 2、改变R&#xff58;的大小即使基极电路的电流发生改变&#xff0c;使频率发生改变。 3、增大电容&#xff0c;有利于低音向第一个三极管的基极反馈&#xff0c;因此最终 输出频率变低。 4、R2处接光敏电阻…

数据结构和算法-AOV与AOE网络和(逆)拓扑排序与关键路径

文章目录 AOV网络拓扑排序代码实现时间复杂度 逆拓扑排序实现DFS算法实现逆拓扑排序小结 AOE网络关键路径求关键路径求事件最早发生时间求事件最迟发生时间求活动最早发生时间求活动最迟发生时间求活动余量 关键活动 关键路径的特性小结 AOV网络 必须是DAG图&#xff08;有向无…

本科论文降重修改技巧 神码ai

大家好&#xff0c;今天来聊聊本科论文降重修改技巧&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 本科论文降重修改技巧 对于本科论文的写作&#xff0c;降重修改是一个…

飞天使-docker知识点6-容器dockerfile各项名词解释

文章目录 docker的小技巧dockerfile容器为什么会出现启动了不暂停查看docker 网桥相关信息 docker 数据卷 docker的小技巧 [rootlight-test playbook-vars[]# docker inspect -f "{{.NetworkSettings.IPAddress}}" d3a9ae03ae5f 172.17.0.4docker d3a9ae03ae5f:/etc…

【idea】解决sprintboot项目创建遇到的问题

目录 一、报错Plugin ‘org.springframework.boot:spring-boot-maven-plugin:‘ not found 二、报错java: 错误: 无效的源发行版&#xff1a;17 三、java: 无法访问org.springframework.web.bind.annotation.CrossOrigin 四、整合mybatis的时候&#xff0c;报java.lang.Ill…