Python爬虫从0到1(第十六天)——scrapy之数据存储

在上篇文章中我们学习了关于scrapy中的数据解析以及在scrapy框架中的日志配置方法。那么在今天的文章中我们就来看关于scrapy中对于数据的存储是如何实现的。

在前面的文章中我们介绍到scrapy中的五大组件,其中专门用于存储阶段的组件就是管道,所以今天主要呢也是对围绕着管道来对scrapy中的存储进行学习。

一、数据存储的方式

在scrapy中管道是实现数据存储的组件,但是并不是说我们在保存数据的时候只能够在管道中进行(注意:只是在管道实现这个过程,管道本身是不存储数据的),也可以在爬虫文件中实现、或者在中间件中实现都是可以的。但是在管道中存储存在以下几种优势。

1.实时性:管道能提供实时的数据传输,并不用等待所有的数据处理完成之后才输出。

2.单向性:管道只允许数据单向流动,可以避免数据出现混淆或者重复的情况。

3.节省空间:管道不需要存储数据,因此节省了存储空间。

4.高效性:管道的本质就是一个内存缓存区,所以读写速度比硬盘块,并且没有磁盘访问时间,同时管道具有可并发性,能够在多个进程只见实现并发传输数据。

5.灵活性:管道可以在不进行额外的配置或安装的情况下配合不同的程序使用。

那么接下来我们就来看scrapy中的终端存储方式与管道存储方式的简单应用。

1.1 基于终端指令实现持久化存储

继续以上篇文章中的素材网为例,此次我们将图片的标题进行存储。

基于终端指令的存储首先要知道,保存的时候在爬虫文件中需要有返回值,也就是说我们需要在爬虫文件的parse方法中return出一个结果,然后才能够在终端实现这个返回结果的存储。代码如下:

import scrapy


class Spider01Spider(scrapy.Spider):
    name = "spider01"
    allowed_domains = ["chinaz.com"]
    start_urls = ["https://sc.chinaz.com/tupian/siwameinvtupian.html"]
    page = 1

    def parse(self, response):
        titles = response.xpath('/html/body/div[3]/div[2]/div/img/@alt').extract()
        dic = {}    # 声明用于存储标题的字典
        for i in range(1, len(titles)+1):
            dic[str(i)] = titles[i-1]   # 注意使用终端存储时字典中的键不要是整数类型
        print(dic)
        return dic

然后在终端输入命令

scrapy crawl spider01 -o result.json

在这里插入图片描述

执行结束之后就可以在项目中看到生成了一个result.json的文件,其中就有我们保存的数据。

但是要知道这种存储的方式是有一定的局限性的,其保存的文件类型只能够为:‘json’,‘jsonlines’,‘jl’,‘csv’,‘xml’,'marshal ',‘pickle’。虽然使用方式比较方便,不过相对其局限性而言就不太够看了,所以这种方式只适合数据量较少且结构分明的数据。

1.2 基于管道实现持久化存储

基于管道实现持久化存储的话我们要直到其在scrapy框架中的一个编码流程,不能够说随随便便想到哪里就写哪里,要知道框架中是有很多个文件的,没有一定的逻辑去写的话最后你都不知道你写到了哪一个文件之中了。

1.2.1 编码思路(仅供参考)

1.完成数据提取

2.在item类中定义相关属性

3.将解析到的数据封装到item中

4.将item提交到管道进行存储操作

5.在管道类中的process_item方法中将接收到的item对象进行持久化的存储操作。

6.在配置中开启管道

接下来按照该流程(从第2步开始)来对刚刚提取出来的图片标题进行存储。

1.2.2 构建字段

打开items.py文件开始构建

在这里插入图片描述

字段的构建方式在文件中是直接给出的,所以我们就严格按照提示来进行即可。构建字段title

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class Myproject01Item(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    index = scrapy.Field()
    title = scrapy.Field()
    pass

1.2.3 封装item及提交

在爬虫文件中进行item的封装

import scrapy
from myproject01.items import Myproject01Item

class Spider01Spider(scrapy.Spider):
    name = "spider01"
    allowed_domains = ["chinaz.com"]
    start_urls = ["https://sc.chinaz.com/tupian/siwameinvtupian.html"]
    page = 1

    def parse(self, response):
        titles = response.xpath('/html/body/div[3]/div[2]/div/img/@alt').extract()
        items = Myproject01Item()   # 实例化items
        for i in range(1, len(titles)+1):
            items['title'] = titles[i-1]    # 逐个添加到items中
            items['index'] = str(i)
            yield items # 将items提交到管道中
1.2.4 编辑管道类存储方法

打开pipelines.py文件

在这里插入图片描述

在process_item中实现存储,可以是任何可交互存储媒介,在此处的item

是一个类字典对象但不是一个字典,虽然在输出的时候在终端上看到的是一个字典结构的数据,但是其本质并不是一个字典,大家可以输出其type验证。此处存储以MongoDB为例。

# 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
import pymongo


class Myproject01Pipeline:
    def process_item(self, item, spider):
        conn = pymongo.MongoClient(host='mongodb://localhost', port=27017)
        mydb = conn['zzsc']
        mycol = mydb['titles']
        mycol.insert_one({item['index']: item['title']})
        return item
1.2.5 启动管道

启动管道只需要在配置文件中取消默认的这个管道类的注释即可。如下:

在这里插入图片描述

然后便可以开始执行任务了。待执行结束之后在MongoDB中进行查看。

在这里插入图片描述

可以看到数据就成功的保存在数据库之中了。但是细心点小伙伴就会发现一个问题,循环这么多次,每一次循环都要去提交到管道,也就意味着process_item方法调用了很多次,那么与mongo的连接就连接了很多次,这样不是很浪费资源嘛?没错,所以这个地方在scrapy框架中也是考虑到了的,因此其是提供了一个在任务开始的时候便会调用一次的方法,而在之后提交管道的时候是不会再次执行的,如下代码:

# 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
import pymongo


class Myproject01Pipeline:
    def open_spider(self, spider):
        """在爬虫任务开始时调用一次"""
        self.conn = pymongo.MongoClient(host='mongodb://localhost', port=27017)
        self.mydb = self.conn['zzsc']
        self.mycol = self.mydb['titles']
        
    def process_item(self, item, spider):
        self.mycol.insert_one({item['index']: item['title']})
        return item
    
    def close_spider(self, spider):
        """在爬虫任务结束时被调用一次"""
        self.conn.close()

这样代码就重写好啦,就不会出现每一次提交的时候都去连接数据库的情况了。

二、基于管道的图片存储

相较于文本类型数据而已,图片的存储在scrapy中是有着一个完善的封装的,准确的说文件的存储在scrapy中都是封装好的功能来实现文件的快速保存。接下来我们就以图片保存为例来简单了解一下在scrapy中封装好的关于文件的存储类。

首先是关于字段的设置,items中必须要有的字段是文件所在的地址,也就是我们必须将文件的url解析出来。

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class Myproject01Item(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    index = scrapy.Field()
    title = scrapy.Field()
    url = scrapy.Field()
    pass

此时的爬虫文件中的代码如下:

import scrapy
from myproject01.items import Myproject01Item

class Spider01Spider(scrapy.Spider):
    name = "spider01"
    allowed_domains = ["chinaz.com"]
    start_urls = ["https://sc.chinaz.com/tupian/siwameinvtupian.html"]
    page = 1

    def parse(self, response):
        titles = response.xpath('/html/body/div[3]/div[2]/div/img/@alt').extract()
        urls = ['https:'+url for url in response.xpath('/html/body/div[3]/div[2]/div/img/@data-original').extract()]
        for i in range(1, len(titles)+1):
            items = Myproject01Item()  # 实例化items
            items['title'] = titles[i-1]    # 逐个添加到items中
            items['index'] = str(i)
            items['url'] = urls[i-1]
            yield items # 将items提交到管道中

然后来到管道文件中创建一个类,名字自定义,但是需要继承固定的scrapy提供的父类。

# 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
import scrapy
from scrapy.pipelines.images import ImagesPipeline


class MyImagesPipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        yield scrapy.Request(item['url'])
        
    def file_path(self, request, response=None, info=None, *, item=None):
        imgName = item['title'] + '.jpg'	# 图片名保存时的名称
        return imgName
        
    def item_completed(self, results, item, info):
        return item

再将此管道类注册到项目之中。

在这里插入图片描述

最后再配置文件中去指定一下图片文件的保存路径。

在这里插入图片描述

注意如果没有imgs文件夹的话需要手动创建!!!!同时要保证自己的环境中存在着pillow库,否则代码运行会出BUG!

pip install pillow

代码执行结果:

在这里插入图片描述

在这里插入图片描述

关于代码中的任何疑惑点或者其他问题,大家可私聊本人或者进群讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的工作流程包括以下几个关键步骤: URL收集: 爬虫从一个或多个初始URL开始,递归或迭代地发现新的URL,构建一个URL队列。这些URL可以通过链接分析、站点地图、搜索引擎等方式获取。 请求网页: 爬虫使用HTTP或其他协议向目标URL发起请求,获取网页的HTML内容。这通常通过HTTP请求库实现,如Python中的Requests库。 解析内容: 爬虫对获取的HTML进行解析,提取有用的信息。常用的解析工具有正则表达式、XPath、Beautiful Soup等。这些工具帮助爬虫定位和提取目标数据,如文本、图片、链接等。 数据存储爬虫将提取的数据存储数据库、文件或其他存储介质中,以备后续分析或展示。常用的存储形式包括关系型数据库、NoSQL数据库、JSON文件等。 遵守规则: 为避免对网站造成过大负担或触发反爬虫机制,爬虫需要遵守网站的robots.txt协议,限制访问频率和深度,并模拟人类访问行为,如设置User-Agent。 反爬虫应对: 由于爬虫的存在,一些网站采取了反爬虫措施,如验证码、IP封锁等。爬虫工程师需要设计相应的策略来应对这些挑战。 爬虫在各个领域都有广泛的应用,包括搜索引擎索引、数据挖掘、价格监测、新闻聚合等。然而,使用爬虫需要遵守法律和伦理规范,尊重网站的使用政策,并确保对被访问网站的服务器负责。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

quanmoupy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值