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

2023-12-14 12:28

本文主要是介绍爬虫 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基础+爬虫案例)

这篇关于爬虫 scrapy ——scrapy shell调试及下载当当网数据(十一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/492509

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X