爬虫 scrapy (十一)

目录

一、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 = img
    else:
         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 = img
    else:
       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.html

if self.page < 10:
     self.page = self.page + 1
     url = 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 Scrapy095Item

class 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 = 1

    def 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 = img
            else:
                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.html

        if self.page < 10:
            self.page = self.page + 1
            url = 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.html

import scrapy


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

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基础+爬虫案例)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

设计模式(2)--对象创建(3)--工厂方法

1. 意图 定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。 工厂方法使一个类的实例化延迟到其子类。 2. 四种角色 抽象产品、具体产品、抽象构造者、具体构造者 3. 优点 3.1 仅处理抽象产品(Product)接口 3.2 给子类一个钩子(hook)以提供对象的扩展版本(父…

C/C++ 快乐数: 编写一个算法来判断一个数n是不是快乐数

题目&#xff1a; 编写一个算法来判断一个数n是不是快乐数。 快乐数的定义&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。 如果这个过…

面试必备的Linux常用命令

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 Linux常用命令 1、文件及内容2、网络3、进程服务4、…

C++寻找特殊年号 2023年3月C++一级 电子学会中小学生软件编程C++等级考试一级真题答案解析

目录 C/C寻找特殊年号 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C寻找特殊年号 2023年3月 C编程等级考试一级编程题 一、题目要求 1、编程实现 年号中的每个数之和为20的年号是特殊年号。例如: 2…

计算机操作系统-第十四天

目录 前言 线程 线程机制带来的变化 线程的属性 前言 在还没有引入进程的概念时&#xff0c;系统中的各个程序只能串行执行&#xff0c;即不能边听音乐边QQ聊天&#xff0c;在引入了进程的概念后&#xff0c;就可以实现边听音乐边QQ聊天。 但是我们在使用QQ时除了聊天还会进…

Python实现多种图像去噪方法

Python实现多种图像去噪方法&#xff1a;中值滤波&#xff0c;均值滤波&#xff0c;高通滤波&#xff0c;低通滤波&#xff0c;高斯滤波&#xff0c;同态滤波 图像和视频逐渐成为人们生活中信息获取的重要来源。人们准确地获取信源发出的图像和视频信息需要保证在传输过程中的…

性能优化 vue2/vue3 通过CDN 减少项目启动时间

其实更多可以通过压缩图片等文件大小 也会让项目运行快一些 以及尽量使用异步或者懒加载 使用CDN可以避免在项目中使用npm导入Vue的依赖项&#xff0c;从而减少项目启动时的加载时间 使用方法如下 <!-- Vue 2 --> <script src"https://cdn.jsdelivr.net/npm/vue…

[Linux] Tomcat

一、Tomcat相关知识 1.1 Tomcat的简介 Tomcat 是 Java 语言开发的&#xff0c;Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器&#xff0c;是 Apache 软件基金会的 Jakarta 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。 …

防职业掉坑必看,电商设计主要做什么?

今年双十一刚结束&#xff0c;各电商平台不公布总销售额的新闻就上了热搜。外行人乍一看可能觉得消费意愿下降&#xff0c;消费水平降级&#xff0c;电商行业不景气&#xff0c;但实际上电商领域在国内突飞猛进了10几年后&#xff0c;仍然还有很大的上升空间。很多人说&#xf…

shiro入门demo(二)授权

在前面认证的基础上&#xff0c;认证通过后一般还有个授权的操作。授权根据业务需求有两种维度&#xff0c;基于角色的授权和基于资源的授权。 一、授权-基于角色授权&#xff1a; shiro中授权实现方式&#xff1a;有三种 1、编程式 Subject subject SecurityUtils.getSubje…

电路中的repeater是什么?

最近在看interlaken协议&#xff0c;有一个单词&#xff0c;repeater&#xff0c;不知道是什么含义&#xff0c;查了一下发现它的功能是提高数据的完整性&#xff0c;要么是修复时钟&#xff0c;要么是提高信号裕量等。总之是让信号变好的一个东西。 具体可以参见TI的说明。 【…

企业资产负债表API:获取企业资产负债表数据的重要工具

前言 在当今的数字化时代&#xff0c;信息的获取和整合对于企业的决策和规划至关重要。企业资产负债表API是一种强大的工具&#xff0c;可以帮助企业快速、准确地获取资产负债表数据&#xff0c;从而更好地分析财务状况、做出投资决策以及评估经营绩效。本文将介绍企业资产负债…

【Linux | C++ 】生产者消费者模型(Linux系统下C++ 代码模拟实现)

阅读导航 引言一、生产者消费者问题&#x1f341;将生产者消费者模型比喻为超市的顾客和供货商 二、C queue模拟阻塞队列的生产消费模型&#xff08;伪代码&#xff09;三、RAII风格的加锁方式1. 简介2. 示例 四、基于Linux操作系统使用C代码&#xff0c;采用RAII风格的加锁方式…

flutter的ListView和SingleChildScrollView有什么区别?他们的使用场景有什么不一样?

文章目录 简介ListViewSingleChildScrollView使用场景的不同 简介 ListView和SingleChildScrollView都是在Flutter中用于处理滚动内容的组件&#xff0c;但它们有一些关键的区别。 ListView 多个子元素&#xff1a; ListView是一个滚动的可滚动组件&#xff0c;通常用于包含多…

写字基本功 - 正确握笔姿势

写字基本功 - 正确握笔姿势 1. 写字基本功 郑文彬 (布衣) 先生 2. 正确握笔步骤 握笔姿势教学 http://www.bebosspen.com/index.php/correct 3. 正确握笔姿势 - 重点解说图 握笔姿势教学 http://www.bebosspen.com/index.php/correct 3.1. 食指 食指低于拇指 两段弯曲勿三…

【价值几十万的仿抖音直播电商系统源码共享】

当下&#xff0c;传统的图文电商模式已经走向没落&#xff0c;以抖音为首的直播电商模式备受用户追捧&#xff0c;它具有实时直播和强互动的特点&#xff0c;是传统电商所不具备的优势。而且&#xff0c;当前正是直播电商的红利期&#xff0c;很多主播和品牌商都通过直播电商业…

[Halcon模块] Halcon13.0查询算子模块归属

&#x1f4e2;博客主页&#xff1a;https://loewen.blog.csdn.net&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由 丶布布原创&#xff0c;首发于 CSDN&#xff0c;转载注明出处&#x1f649;&#x1f4e2;现…

【C语言 | 指针】数组参数 和 指针参数

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

IDEA利用插件完成properties与yml的互相转换(mac与wins通用)

步骤一、插件安装 点击屏幕左上方的IDEA&#xff0c;然后点击Preferences(相当于wins里的settings) 进入后点击Plugins&#xff0c;在插件商城中搜索并安装 Convert YAML and Properties File 这个插件 二、使用 右键选择你需要转换的配置文件&#xff0c;选择Convert YAML …

解决高风险代码:Mass Assignment: Insecure Binder Configuration

Abstract 用于将 HTTP 请求参数绑定到模型类的框架绑定器未显式配置为允许或禁止特定属性 Explanation 为便于开发和提高生产率&#xff0c;现代框架允许自动实例化一个对象&#xff0c;并使用名称与要绑定的类的属性相匹配的 HTTP 请求参数填充该对象。对象的自动实例化和填充…