python学习之第十六天(scrapy中间件及管道文件)

知识点目录
1.如何自定义中间件
2.如何使自己的中间件生效
3.如何禁用系统的中间件
4.如何自定义管道文件
5.管道文件常用的方法有哪些
6.scrapy自带有哪些中间件
7.数据去重的若干方式及优缺点对比
8.布隆过滤的原理
9.限制scrapy的日志输出级别
10.一个字符和以个汉字占多少字节
11.如何通过meta传值
12.如何动态根据item生成创建表语句和插入语句
13.管道文件如何读取settings中的相关配置
14.日志文件的五个级别
15.scrapy如何使用日志文件记录相关信息

1.如何自定义中间件

scrapy要让自定义中间件生效,则必须禁用系统自带的中间件

在这里插入图片描述
而自定义的管道文件(pipelines)不必禁用系统的自带的

scrapy中间件详解:
https://www.cnblogs.com/xieqiankun/p/know_middleware_of_scrapy_1.html

在Scrapy中有两种中间件:下载器中间件(Downloader Middleware)和爬虫中间件(Spider Middleware)
以自定义User-Agent中间件为例
首先要知道User-Agent属于下载器中间件,即DownloaderMiddleware

第一步,找到scrapy自带的User-Agent中间件(UserAgentMiddleware)
在这里插入图片描述

第二步:复制scrapy自带的User-Agent中间件(UserAgentMiddleware),到middlewarea.py中,自定义自己需要的User-Agent

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

上面在setting中自定义的USER_AGENT中间件为该项目的所有爬虫共用的USER_AGENT,要想只让某个爬虫用这个USER_AGENT,则执行下图的

在这里插入图片描述

2.如何使自己的中间件生效

禁用scrapy自带的中间件,加载自己的中间件,如下图使用自己定义的USER_AGENT中间件
在这里插入图片描述

3.如何禁用系统的中间件

把系统的中间件设置为None,如上图

4.如何自定义管道文件

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html

# pipeline,俗称管道文件,用于对爬虫数据进行二次处理
# 系统自带的pipeline
class Job51SpiderPipeline(object):
    def process_item(self, item, spider):
        return item


import sqlite3

# 重写的pipeline,存储到sqlite3数据库
class SqlitePipeline(object):

    # 类中只执行一次的方法有哪些?
    # 构造函数 析构函数 爬虫open 爬虫close

    def __init__(self,db_name):
        if not db_name:
            db_name = 'db.sqlite3'
        self.con = sqlite3.connect(db_name)
        self.cursor = self.con.cursor()

    # 处理item
    def process_item(self, item, spider):
        info = ""
        keys = ""
        values = []
        for key, value in item.items():
            keys += key + ","
            values.append(value)
            value_type = ""
            if isinstance(value, str):
                value_type = "VARCHAR(255),"
            elif isinstance(value, int):
                value_type = "INTEGER,"
            elif isinstance(value, float):
                value_type = "FLOAT,"
            info += key + " " + value_type
        sql1 = f"""
        CREATE TABLE IF NOT EXISTS {spider.name}(
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        {info[:-1]}
        )
        """
        self.cursor.execute(sql1)

        sql2 = f"""
            INSERT INTO {spider.name} ({keys[:-1]}) VALUES ({("?," * len(values))[:-1]}) 
        """
        self.cursor.execute(sql2, values)
        self.con.commit()
        return item

    # 关闭数据库连接
    def close_spider(self, spider):
        self.cursor.close()
        self.con.close()
        self.cursor = None
        self.con = None

    # 加载配置
    @classmethod
    def from_settings(cls, settings):
        db_name = settings['DB_NAME']
        return cls(db_name)
    #
    # def open_spider(self, spider):
    #     pass
    #
    # def item_completed(self, results, item, info):
    #     pass
    #
    # @classmethod
    # def from_crawler(cls, crawler):
    #     try:
    #         pipe = cls.from_settings(crawler.settings)
    #     except AttributeError:
    #         pipe = cls()
    #     pipe.crawler = crawler
    #     return pipe

# 存储到csv文件中
# 方法1:在自定义的run.py文件中 cmdline.execute(['scrapy','crawl','job51','-o','job.csv'])
# 方法2:重写的pipeline
class CsvPipeline(object):
    def process_item(self, item, spider):
        # gbk(2万多)  gb18030(范围较其它大,7万多个字)  gb2312(6千多)
        with open(f"{spider.name}.csv",'a',encoding='utf-8') as f:
            line = '"'+'","'.join(item.values())+'"'+"\n"
            f.write(line)
        return item


自定义pipeline后,要加入到setting或爬虫文件中才能生效

1.加入setting.py中,对项目的所有爬虫都有效
在这里插入图片描述

2…加入爬虫文件,只对当前文件有用,创建个类属性custom_settings,然后加入
custom_settings

在这里插入图片描述

5.管道文件常用的方法有哪些

当Item在Spider中被收集之后,它将会被传递到Item Pipeline,这些Item Pipeline组件按定义的顺序处理Item。每个Item Pipeline都是实现了简单方法的Python类,比如决定此Item是丢弃而存储。以下是Item Pipeline的一些典型应用:
(1)验证爬取的数据(检查Item包含某些字段,比如说name字段)
(2)查重复(并丢弃)
(3)将爬取结果保存到文件或者数据库中

编写item pipeline规范

 -*- coding: utf-8 -*-
#Define your item pipelines here
#Don't forget to add your pipeline to the ITEM_PIPELINES setting
 #See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
 
import json
class LybbnspiderPipeline(object):
    def __init__(self):
    #可选方法,用于做参数初始化等操作,常用于保存item到文件中,文件打开时用到
        #doing someting
    def process_item(self, item, spider):
        #参数item---被爬取的item
        #参数spider--爬取该item的spider
        #该方法process_item是必须的方法
        return item
    def open_spider(self,spider):
        #参数spider---被开启的spider
        #当spider被开启时,该方法open_spider会被调用
        #该方法open_spider为可选方法
    def close_spider(self,spider):
        #参数spider---被开启的spider
        #当spider爬虫被关闭时,close_spider方法会被调用
        #该方法open_spider为可选方法

6.scrapy自带有哪些中间件

在Scrapy中有两种中间件:下载器中间件(Downloader Middleware)和爬虫中间件(Spider Middleware)

下载器中间件有
在这里插入图片描述

爬虫中间件

在这里插入图片描述

7.数据去重的若干方式及优缺点对比

"""
            数据去重的若干方案:

            方式1.基于内存  列表 参考类属性exists_url
                优点:逻辑简单,性能高
                缺点:占内存,该方式适用于运行一次的项目
            方式2:基于文件(基于普通文件)
                    优点:程序可以运行多次,逻辑相对简单
                    缺点:性能不高
             方式3:基于文件(基于数据库)
                    优点:程序可以运行多次,逻辑相对简单
                    缺点:性能不高(redis可以缓解性能)
            方式4:布隆过滤(推荐的数据去重方式)(百度布隆过滤原理及优缺点)
                    依赖的包bloomfilter4py3
                    优点:节省空间,逻辑简单,持久化,读写性能良好
                    缺点:会有误差
                    原理:多哈希函数映射的快速查找算法
            """
            jobs = response.xpath("//div[@id='resultList']/div[@class='el']")
            for job in jobs:
                job_href = job.xpath("p/span/a/@href").extract_first("没有详情")
                if not job_href:
                    continue

                # 数据去重  方式1
                # if job_href in Job51Spider.exists_url:
                #     print('数据已存在')
                #     continue
                # Job51Spider.exists_url.append(job_href)

                #数据去重 方式2
                # h=hashlib.md5()
                # h.update(job_href.encode())
                # file_name =h.hexdigest()
                # if os.path.exists(file_name):
                #     print("数据已存在")
                #     continue
                # with open(file_name,'w') as f:
                #     f.write("")

                # 方式4:布隆过滤
                if self.bloom.test(job_href):
                    print("数据已存在")
                    continue
                self.bloom.add(job_href)
                self.bloom.save("bloom.cache")

8.布隆过滤的原理

布隆过滤(推荐的数据去重方式)(百度布隆过滤原理及优缺点)
依赖的包bloomfilter4py3
优点:节省空间,逻辑简单,持久化,读写性能良好,利用布隆过滤器减少磁盘 IO 或者 网络请求
缺点:会有误差
原理:多哈希函数映射的快速查找算法
https://www.cnblogs.com/aspnethot/articles/3442813.html

100亿条数据
根据数据大小创建一个变量来表示每条数据的状态
变量 = 00000。。。。0000 100亿个0
数据1插入,通过hash算法计算该数据的位置,例如在第10位,变量会将第十位改为1
10亿个状态0/1 1位=1个状态

9.限制scrapy的日志输出级别

在这里插入图片描述

10.一个字符和一个汉字各占多少字节

utf-8编码:一个中文包含繁体字等于三个字节,一个英文字符等于一个字节。
gbk编码:一个中文包含繁体字等于二个字节,一个英文字符等于一个字节

11.如何通过meta传值

在这里插入图片描述

12.如何动态根据item生成创建表语句和插入语句

#  连接数据库
 def __init__(self,db_name):
        if not db_name:
            db_name = 'db.sqlite3'
        self.con = sqlite3.connect(db_name)
        self.cursor = self.con.cursor()

    # 处理item,动态创建表及插入语句
    def process_item(self, item, spider):
        info = ""
        keys = ""
        values = []
        for key, value in item.items():
            keys += key + ","
            values.append(value)
            value_type = ""
            if isinstance(value, str):
                value_type = "VARCHAR(255),"
            elif isinstance(value, int):
                value_type = "INTEGER,"
            elif isinstance(value, float):
                value_type = "FLOAT,"
            info += key + " " + value_type
        sql1 = f"""
        CREATE TABLE IF NOT EXISTS {spider.name}(
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        {info[:-1]}
        )
        """
        self.cursor.execute(sql1)

        sql2 = f"""
            INSERT INTO {spider.name} ({keys[:-1]}) VALUES ({("?," * len(values))[:-1]}) 
        """
        self.cursor.execute(sql2, values)
        self.con.commit()
        return item

    # 关闭数据库连接
    def close_spider(self, spider):
        self.cursor.close()
        self.con.close()
        self.cursor = None
        self.con = None

13.管道文件如何读取settings中的相关配置

# 加载配置
    @classmethod
    def from_settings(cls, settings):
        db_name = settings['DB_NAME']
        return cls(db_name)

在这里插入图片描述

在这里插入图片描述

14.日志文件的五个级别

			#logging.info()  # 一般信息
            # logging.warning()# 警告信息
            # logging.error() #一般错误
            # logging.debug() # 调试信息
            # logging.critical() # 严重错误

15.scrapy如何使用日志文件记录相关信息

首先导入包logging并创建日志文件

在这里插入图片描述

logging.info('  '.join([job_name,job_href,company_name,job_place,job_salary,job_date]))  # 一般信息
                # logging.warning()# 警告信息
                # logging.error() #一般错误
                # logging.debug() # 调试信息
                # logging.critical() # 严重错误

把哪种信息写入日志文件就用logging调用哪个方法

猜你喜欢

转载自blog.csdn.net/qq_41150890/article/details/99599084
今日推荐