知识点目录
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调用哪个方法