爬虫入门五(Scrapy架构流程介绍、Scrapy目录结构、Scrapy爬取和解析、Settings相关配置、持久化方案)

文章目录

  • 一、Scrapy架构流程介绍
  • 二、Scrapy目录结构
  • 三、Scrapy爬取和解析
    • Scrapy的一些命令
    • css解析
    • xpath解析
  • 四、Settings相关配置提高爬取效率
    • 基础配置
    • 增加爬虫的爬取效率
  • 五、持久化数据
    • 1.在items中新建类
    • 2.在解析中,得到item对象,并且yield
    • 3.配置文件中
    • 4.pipelines.py
  • 六、爬虫中间件及下载中间件
    • 爬虫中间件
    • 下载中间件
    • 修改请求头的user-agent,referer,Authorization...
    • 加cookie
    • 加代理(MyfirstscrapyDownloaderMiddleware)
  • 七、scrapy集成selenium
    • 使用步骤
  • 八、源码去重规则(布隆过滤器)
    • 源码去重原理
    • 布隆过滤器
    • 自定义去重规则(通过布隆过滤器)
    • 写去重类
  • 九、分布式爬虫

一、Scrapy架构流程介绍

Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速、简单、可扩展的方式从网站中提取所需的数据。但目前Scrapy的用途十分广泛,可用于如数据挖掘、监测和自动化测试等领域,也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。

Scrapy 是基于twisted框架开发而来,twisted是一个流行的事件驱动的python网络框架。因此Scrapy使用了一种非阻塞(又名异步)的代码来实现并发。整体架构大致如下:

在这里插入图片描述

官网链接:https://docs.scrapy.org/en/latest/topics/architecture.html

官方原文解释:
1.The data flow in Scrapy is controlled by the execution engine, and goes like this:The Engine gets the initial Requests to crawl from the Spider.
(引擎从Spider获取要爬行的初始请求。)
2.The Engine schedules the Requests in the Scheduler and asks for the next Requests to crawl.
(引擎在调度器中对请求进行调度,并要求对下一个请求进行爬取。)
3.The Scheduler returns the next Requests to the Engine.
(调度器将下一个请求返回给引擎。)
4.The Engine sends the Requests to the Downloader, passing through the Downloader Middlewares (see process_request()).
(引擎将请求发送给下载器,通过下载器中间件(请参阅process_request())。)
5.Once the page finishes downloading the Downloader generates a Response (with that page) and sends it to the Engine, passing through the Downloader Middlewares (see process_response()).
(一旦页面完成下载,Downloader就会生成一个响应(使用该页面)并将其发送给引擎,通过Downloader中间件传递(请参阅process_response())。)
6.The Engine receives the Response from the Downloader and sends it to the Spider for processing, passing through the Spider Middleware (see process_spider_input()).
(引擎从下载器接收响应,并通过Spider中间件将其发送给Spider进行处理(参见process_spider_input())。)
7.The Spider processes the Response and returns scraped items and new Requests (to follow) to the Engine, passing through the Spider Middleware (see process_spider_output()).
(Spider处理响应,并通过Spider Middleware(参见process_spider_output())将抓取的项和新的请求返回给引擎。)
8.The Engine sends processed items to Item Pipelines, then send processed Requests to the Scheduler and asks for possible next Requests to crawl.
(引擎将处理过的项目发送到项目管道,然后将处理过的请求发送到调度器,并请求抓取可能的下一个请求。)
9.The process repeats (from step 1) until there are no more requests from the Scheduler.
(该过程重复(从步骤1开始),直到没有来自Scheduler的更多请求。)
	'架构'爬虫:spiders(自己定义的,可以有很多),定义起始爬取的地址,解析规则引擎:engine ---》控制整个框架数据的流动,大总管调度器:scheduler---》要爬取的 requests对象,放在里面,排队,去重下载中间件:DownloaderMiddleware---》处理请求对象,处理响应对象,下载中间件,爬虫中间件下载器:Downloader ----》负责真正的下载,效率很高,基于twisted的高并发的模型之上爬虫中间件:spiderMiddleware----》处于engine和爬虫直接的(用的少)管道:piplines---》负责存储数据(管道,持久化,保存,文件,mysql)'-----------------'引擎(EGINE)引擎负责控制系统所有组件之间的数据流,并在某些动作发生时触发事件。有关详细信息,请参见上面的数据流部分。调度器(SCHEDULER)用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL的优先级队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址下载器(DOWLOADER)用于下载网页内容, 并将网页内容返回给EGINE,下载器是建立在twisted这个高效的异步模型上的爬虫(SPIDERS)--->在这里写代码SPIDERS是开发人员自定义的类,用来解析responses,并且提取items,或者发送新的请求项目管道(ITEM PIPLINES)在items被提取后负责处理它们,主要包括清理、验证、持久化(比如存到数据库)等操作下载器中间件(Downloader Middlewares)位于Scrapy引擎和下载器之间,主要用来处理从EGINE传到DOWLOADER的请求request,已经从DOWNLOADER传到EGINE的响应response,你可用该中间件做以下几件事:设置请求头,设置cookie,使用代理,集成selenium爬虫中间件(Spider Middlewares)位于EGINE和SPIDERS之间,主要工作是处理SPIDERS的输入(即responses)和输出(即requests)

二、Scrapy目录结构

myfirstscrapy 			# 项目名myfirstscrapy            # 文件夹名字,核心代码,都在这里面spiders            # 爬虫的文件,里面有所有的爬虫__init__.pybaidu.py      # 百度爬虫 cnblogs.py    #cnblogs爬虫items.py # 有很多模型类---》以后存储的数据,都做成模型类的对象,等同于django的models.pymiddlewares.py # 中间件:爬虫中间件,下载中间件都写在这里面pipelines.py   #项目管道---》以后写持久化,都在这里面写run.py         # 自己写的,运行爬虫settings.py    # 配置文件  django的配置文件scrapy.cfg          # 项目上线用的,不需要关注-以后咱们如果写爬虫,写解析,就写 spiders 下的某个py文件   咱么写的最多的
-以后配置都写在settings 中
-以后想写中间件:middlewares
-以后想做持久化:pipelines,items

三、Scrapy爬取和解析

Scrapy的一些命令

	1 创建项目:scrapy startproject 项目名2 创建爬虫:scrapy genspider 爬虫名 爬取的地址scrapy gensipder cnblogs www.cnblogs.com3 运行爬虫运行cnblgos爬虫---》对首页进行爬取scrapy crawl 爬虫名字scrapy crawl cnblogsscrapy crawl cnblogs --nolog  不打印日志4 快速运行,不用命令项目根路径新建 run.py,写入如下代码,以后右键运行run.py 即可from scrapy.cmdline import executeexecute(['scrapy', 'crawl', 'cnblogs', '--nolog'])5 解析数据---》提供了解析库--》css和xpath1 response对象有css方法和xpath方法-css中写css选择器     response.css('')-xpath中写xpath选择   response.xpath('')2 重点1-xpath取文本内容'.//a[contains(@class,"link-title")]/text()'-xpath取属性'.//a[contains(@class,"link-title")]/@href'-css取文本'a.link-title::text'-css取属性'img.image-scale::attr(src)'3 重点2.extract_first()  取一个.extract()        取所有

css解析

import scrapy
class CnblogsSpider(scrapy.Spider):name = "cnblogs"allowed_domains = ["www.cnblogs.com"]start_urls = ["https://www.cnblogs.com"]def parse(self, response):# response 就是爬取完后的对象# print(response.text)'使用css解析'article_list = response.css('article.post-item')for article in article_list:title = article.css('a.post-item-title::text').extract_first()# 取出所有后单独处理desc = article.css('p.post-item-summary::text').extract()real_desc = desc[0].replace('\n','').replace(' ','')if not real_desc:real_desc = desc[1].replace('\n', '').replace(' ', '')# print(title)# print(real_desc)# 作者名字author = article.css('footer.post-item-foot>a>span::text').extract_first()# print(author)# 头像image_url = article.css('img.avatar::attr(src)').extract_first()# print(image_url)# 发布日期data = article.css('span.post-meta-item>span::text').extract_first()# print(data)# 文章地址url = article.css('a.post-item-title::attr(href)').extract_first()print('''文章名:%s文章摘要:%s文章作者:%s作者头像:%s文章日期:%s文章地址:%s'''%(title,real_desc,author,image_url,data,url))

xpath解析

import scrapy
class CnblogsSpider(scrapy.Spider):name = "cnblogs"allowed_domains = ["www.cnblogs.com"]start_urls = ["https://www.cnblogs.com"]def parse(self, response):'使用xpath解析'article_list = response.xpath('//article[@class="post-itme"]')for article in article_list:title = article.xpath('.//a[@class="post-item-title"]/text()').extract_first()# 取出所有后单独处理desc = article.xpath('.//p[@class="post-item-summary"]/text()').extract()real_desc = desc[0].replace('\n','').replace(' ','')if not real_desc:real_desc = desc[1].replace('\n', '').replace(' ', '')# print(title)# print(real_desc)# 作者名字author = article.xpath('.//footer.[@class="post-item-foot"]/a/span/text()').extract_first()# print(author)# 头像image_url = article.xpath('.//img[@class="avatar"]/@src').extract_first()# print(image_url)# 发布日期data = article.xpath('.//span[@class="post-meta-item"]/span/text()').extract_first()# print(data)# 文章地址url = article.xpath('.//a[@class="post-item-title"]/@href').extract_first()print('''文章名:%s文章摘要:%s文章作者:%s作者头像:%s文章日期:%s文章地址:%s'''%(title,real_desc,author,image_url,data,url))

四、Settings相关配置提高爬取效率

基础配置

	1.是否遵循爬虫协议ROBOTSTXT_OBEY = False		# 正常来说你都来爬虫了 还遵循 ?2.LOG_LEVEL 日志级别LOG_LEVEL='ERROR'			# 可以查看具体信息 不会显示无效信息3.USER_AGENT					# 电脑UA版本信息user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.364.默认请求头DEFAULT_REQUEST_HEADERS = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Accept-Language': 'en',}5.爬虫中间件SPIDER_MIDDLEWARES = {'cnblogs.middlewares.CnblogsSpiderMiddleware': 543,}6.下载中间件DOWNLOADER_MIDDLEWARES = {'cnblogs.middlewares.CnblogsDownloaderMiddleware': 543,}7.持久化配置ITEM_PIPELINES = {'cnblogs.pipelines.CnblogsPipeline': 300,}8.爬虫项目名称BOT_NAME = 'myfirstscrapy'9.指定爬虫类的Py文件的位置SPIDER_MODULES = ['myfirstscrapy.spiders']NEWSPIDER_MODULE = 'myfirstscrapy.spiders'

增加爬虫的爬取效率

	1.增加并发量# 默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 1002.降低日志级别# 在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。LOG_LEVEL = 'INFO'3.禁止Cookie# 如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。COOKIES_ENABLED = False4.禁止重试# 对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。RETRY_ENABLED = False5.减少下载超时# 如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。DOWNLOAD_TIMEOUT = 10 	# 超时时间为10s

五、持久化数据

1.在items中新建类

	import scrapyclass MyfirstscrapyItem(scrapy.Item):# define the fields for your item here like:title = scrapy.Field()author = scrapy.Field()real_desc= scrapy.Field()data = scrapy.Field()img_url= scrapy.Field()url = scrapy.Field()# '----------文章详情--------'content = scrapy.Field()

2.在解析中,得到item对象,并且yield

import scrapy
from scrapy.http import Request
from myfirstscrapy.items import MyfirstscrapyItemclass CnblogsSpider(scrapy.Spider):name = "cnblogs"allowed_domains = ["www.cnblogs.com"]start_urls = ["https://www.cnblogs.com"]def parse(self, response):# response 就是爬取完后的对象# print(response.text)'使用css解析'article_list = response.css('article.post-item')for article in article_list:title = article.css('a.post-item-title::text').extract_first()# 取出所有后单独处理desc = article.css('p.post-item-summary::text').extract()real_desc = desc[0].replace('\n','').replace(' ','')if not real_desc:real_desc = desc[1].replace('\n', '').replace(' ', '')# print(title)# print(real_desc)# 作者名字author = article.css('footer.post-item-foot>a>span::text').extract_first()# print(author)# 头像image_url = article.css('img.avatar::attr(src)').extract_first()# print(image_url)# 发布日期data = article.css('span.post-meta-item>span::text').extract_first()# print(data)# 文章地址url = article.css('a.post-item-title::attr(href)').extract_first()# print('''#     文章名:%s#     文章摘要:%s#     文章作者:%s#     作者头像:%s#     文章日期:%s#     文章地址:%s# '''%(title,real_desc,author,image_url,date,url))# 解析出来的数据--放到item对象中,但是缺了文章详情'第一个解析'item=MyfirstscrapyItem(title=title,author=author,real_desc=real_desc,data=data,img_url=image_url,url=url)# 放到Request对象中# 1.保存数据# 2.继续爬取---->下一页文章详情yield Request(url=url,callback=self.parse_detail,meta={'item':item})# 继续爬下一个# yield Request(url=url, callback=self.parse_detail) # callback可以不写# 解析下一页地址之css解析# next_url = 'https://www.cnblogs.com'+response.css('div.pager a:last-child::attr(href)').extract_first()# 解析下一页地址之xpath解析next_url = 'https://www.cnblogs.com' + response.xpath('//div[@class="pager"]/a[last()]/@href').extract_first()print(next_url)yield Request(url=next_url, callback=self.parse)def parse_detail(self,response):# print(response.text)# 解析文章详情,存html# content=str(response.css('#cnblogs_post_body').extract_first())'第二个解析'item=response.meta.get('item')content=str(response.xpath('//div[@id="cnblogs_post_body"]').extract_first())item['content'] = content# print(content)yield item

3.配置文件中

	ITEM_PIPELINES = {"myfirstscrapy.pipelines.MyfirstscrapyFilePipeline": 300,"myfirstscrapy.pipelines.MyfirstscrapyMysqlPipeline": 100,}

4.pipelines.py

from itemadapter import ItemAdapter
class MyfirstscrapyFilePipeline:# 每条记录,都会走这里,如果打开mysql和关闭,都在这个方法中得话# 我们应该在爬虫开启的时候,打开mysql链接,爬虫关闭的时候,关闭链接def open_spider(self, spider):print('开了')# 打开文件self.f = open('cnblogs.txt', 'wt', encoding='utf-8')# 先用文件演示def process_item(self, item, spider):self.f.write(item['title'] + '\n')# print('=======', item['title'])# self.f.flush()return itemdef close_spider(self,spider):print('关了')self.f.close()import pymysql
class MyfirstscrapyMysqlPipeline:def open_spider(self, spider):self.conn=pymysql.connect(user='root',password="1234",host='127.0.0.1',database='cnblogs',port=3306,)self.cursor=self.conn.cursor()def process_item(self, item, spider):self.cursor.execute('INSERT INTO article (title, author, real_desc, data, img_url, url, content)VALUES (%s,%s,%s,%s,%s,%s,%s)',args=[item['title'],item['author'],item['real_desc'],item['data'],item['img_url'],item['url'],item['content']])self.conn.commit()return itemdef close_spider(self, spider):self.cursor.close()self.conn.close()

六、爬虫中间件及下载中间件

Scrapy的所有中间件都写在Middlewares.py中 跟Djagno非常像做一些拦截

引擎和下载器之间的叫:下载中间件。爬虫和引擎之间的叫:爬虫中间件

爬虫中间件

	1 写一个类:middlewares.pyMyfirstscrapySpiderMiddleware2 在配置文件中注册SPIDER_MIDDLEWARES = {"myfirstscrapy.middlewares.MyfirstscrapySpiderMiddleware": 543,}3 中间件类中得方法class MyfirstscrapySpiderMiddleware:# 内部自动触发,不需要我们手动调用@classmethoddef from_crawler(cls, crawler):s = cls()# 信号crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)return sdef process_spider_input(self, response, spider):# 走架构图第6步,会触发这里return Nonedef process_spider_output(self, response, result, spider):# 架构图,第1,7步走这里for i in result:yield idef process_spider_exception(self, response, exception, spider):# 出异常会走passdef process_start_requests(self, start_requests, spider):# 第一爬取起始地址时会走for r in start_requests:yield rdef spider_opened(self, spider):# 爬虫开启时会走spider.logger.info("Spider opened: %s" % spider.name)

下载中间件

	1 写一个类:middlewares.pyMyfirstscrapyDownloaderMiddleware2 在配置文件中注册DOWNLOADER_MIDDLEWARES = {"myfirstscrapy.middlewares.MyfirstscrapyDownloaderMiddleware": 543,}3 中间件类中得方法class MyfirstscrapyDownloaderMiddleware:# 自动会触发,不需要我们手动调用@classmethoddef from_crawler(cls, crawler):s = cls()crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)return sdef process_request(self, request, spider):# 请求来了--》执行它--》架构图 第 4 步# 必须返回 return 以下之一:# - return None: 继续下一个中间件# - return a Response:直接返回给引擎 Response---》引擎把Response给爬虫# - return a Request:直接把返回给引擎---》引擎会把Request给调度器--》等待下次调度# - raise 异常: process_exception() 的执行return Nonedef process_response(self, request, response, spider):# 请求走了--》执行它---》架构图 第 5 步# - return  Response:正常继续往后走--》给引擎---》引擎给爬虫去解析# - return a Request :给引擎--》引擎放到调度器--》等待下次调度# - raise IgnoreRequest:抛异常return responsedef process_exception(self, request, exception, spider):# 执行中间件出异常# Must either:# - return None: continue processing this exception# - return a Response object: stops process_exception() chain# - return a Request object: stops process_exception() chainpassdef spider_opened(self, spider):spider.logger.info("Spider opened: %s" % spider.name)4 重点是:process_requestprocess_response

修改请求头的user-agent,referer,Authorization…

	随机生成user-agent# pip3 install fake-useragentfrom fake_useragent import UserAgentua=UserAgent()# print(ua.random)# print(ua.firefox)# print(ua.chrome)print(ua.edge)def process_request(self, request, spider):# 修改请求头中得user-agentprint('-----',request.headers)# if 'userinfo' in request.url: # 当访问查询用户信息地址,再改referer,改useragent,加登录信息# 1 上次访问的域request.headers['referer'] = 'http://www.lagou.com'# 2 登录认证的信息request.headers['Authorization']='asfasf.asfas.asfas'# 3 客户端类型--》fake_useragent--》随机生成客户端类型 user-agentfrom fake_useragent import UserAgentua = UserAgent()# print(ua.random)request.headers['User-Agent'] = ua.randomreturn None

加cookie

	def process_request(self, request, spider):print('-----',request.cookies)# cnblogs-->cookie 文件request.cookies['name'] = 'lqz'return None

加代理(MyfirstscrapyDownloaderMiddleware)

	def get_proxy(self):import requestsres = requests.get('http://127.0.0.1:5010/get/').json()if res.get('https'):return 'https://' + res.get('proxy')else:return 'http://' + res.get('proxy')def process_request(self, request, spider):# request.meta['proxy'] = self.get_proxy()request.meta['proxy'] = 'http://192.168.11.11:8888'return None

七、scrapy集成selenium

	scrapy 下载的内容,是不包含执行完js后的数据--》等同于requests发送请求有的网站---》需要执行完js,数据才完整(分离项目)对于前后端分离项目--》使用scrapy发送请求会导致数据不完整--》需要执行完js后才能解析数据在scrapy中集成 selenium---》使用selenium去加载网页-->数据是执行完js后,完整的数据

使用步骤

	1 在爬虫类中写 开启浏览器class CnblogsSpider(scrapy.Spider):###### 爬虫开启---》打开浏览器--->类属性--》对象可以取到from selenium.webdriver.edge.service import Serviceser = Service()ser.path = r'.\myfirstscrapy\chromedriver.exe'bro = webdriver.Chrome(service=ser)2 爬虫结束,关闭浏览器,爬虫类中写## 爬虫结束---》关闭浏览器def close(spider, reason):# spider.bro.close()spider.bro.quit()3 在中间件中def process_request(self, request, spider):from scrapy.http.response.html import HtmlResponsespider.bro.get(request.url)response=HtmlResponse(url=request.url,body=spider.bro.page_source.encode('utf-8'))return response4 区分不同的地址,选择使用selenium或scrapy原生爬取-1 通过 url区分-2 通过在request对象的meta中加入标志# 爬虫类中yield Request(url=url, callback=self.parse_detail, meta={'item': item,'is_selenium':True})#中间件中:if request.meta.get('is_selenium'):# 使用scrapy效率低

八、源码去重规则(布隆过滤器)

scrapy 的调度器,会自动去重。研究原理—》自己写去重规则

源码去重原理

	要爬取的Request对象,在进入到scheduler调度器排队之前,先执行enqueue_request,它如果return False,这个Request就丢弃掉,不爬了----》如何判断这个Request要不要丢弃掉,执行了self.df.request_seen(request),它来决定的-----》RFPDupeFilter类中的方法----》request_seen---》会返回TrueFalse----》如果这个request在集合中,说明爬过了,就return True,如果不在集合中,就加入到集合中,然后返回False# 本质原理,通过集合--》根据爬取的地址--》去重的-爬取路径一样---》post--》请求体不一样---》不要去重-如果使用默认去重规则---》这个不会提交多次---》只会提交一次--》有问题源码分析--->scrapy.Spider## 起始爬取的地址# 1 类属性中写了起始位置: start_urls = ["https://www.cnblogs.com"]# 2 爬虫运行时,会执行类中得start_requestsdef start_requests(self) -> Iterable[Request]:for url in self.start_urls:yield Request(url, dont_filter=True)######### 去重位置---from scrapy.core.scheduler import Scheduler# 默认配置文件中有:DUPEFILTER_CLASS = "scrapy.dupefilters.RFPDupeFilter"class Scheduler:# 在排队之前---》先执行enqueue_request--》完成去重def enqueue_request(self, request: Request) -> bool:# self 是调度器#self.df 是去重类 RFPDupeFilter 的对象# 调用RFPDupeFilter中得方法request_seen,会返回True或Falseif self.df.request_seen(request): #返回True说明集合中有了return False # 说明不再爬取了dqok = self._dqpush(request)return Trueclass RFPDupeFilter:def request_seen(self, request: Request) -> bool:# 16 进制字符串fp = self.request_fingerprint(request)#self.fingerprints 是 set() 集合if fp in self.fingerprints:return True # 如果在集合中,就返回True# 加入到集合中,返回Falseself.fingerprints.add(fp)return Falsedef request_fingerprint(self, request: Request) -> str:return self.fingerprinter.fingerprint(request).hex() # 16进制 字符串# request_fingerprint 生成指纹# 请求回来的数据是完全一致的---》如果仅仅使用地址区分-->他们不是一个# 但是被request_fingerprint执行完后,它生成的16进制是一样的-www.cnblogs.com/?name=lqz&age=19-www.cnblogs.com/?age=19&name=lqz# 总结:1 去重是使用集合去重-高级在(生成的指纹):-get请求,参数如果一样,就是一样的-post请求,请求体不一样,就不一样# 代码from scrapy.utils.request import RequestFingerprinterfrom scrapy.http import Requestf=RequestFingerprinter()res1=Request(url='http://www.cnblogs.com/',method='POST',body='name=lqz&age=19')res2=Request(url='http://www.cnblogs.com/',method='POST',body='name=lqz&age=20')res1_hex=f.fingerprint(res1)res2_hex=f.fingerprint(res2)print(res2_hex)print(res1_hex)

布隆过滤器

	# https://zhuanlan.zhihu.com/p/94668361布隆过滤器是什么?bloomfilter:是一个通过多哈希函数映射到一张表的数据结构,能够快速的判断一个元素在一个集合内是否存在,具有很好的空间和时间效率。(典型例子,爬虫url去重)布隆过滤器原理原理: BloomFilter 会开辟一个m位的bitArray(位数组),开始所有数据全部置 0 。当一个元素过来时,通过多个哈希函数(h1,h2,h3....)计算不同的在哈希值,并通过哈希值找到对应的bitArray下标处,将里面的值 0 置为 1布隆过滤器可能存在误差-误差大小:由数组长度和hash函数绝对的-允许出现误差python 字典的key值必须可以 hash-不可变数据类型---》数字和字符串---》布尔,元组,对象-元组可以作为字典key使用布隆过滤器  安装:pip3 install pybloom_live# 布隆过滤器---》可以自动扩容---》规定错误率# from pybloom_live import ScalableBloomFilter## bloom = ScalableBloomFilter(initial_capacity=100, error_rate=0.001, mode=ScalableBloomFilter.LARGE_SET_GROWTH)## url = "www.cnblogs.com"## url2 = "www.liuqingzheng.top"## bloom.add(url)## print(url in bloom)## print(url2 in bloom)布隆过滤器---》定长,不扩容# BloomFilter 是定长的from pybloom_live import BloomFilterbf = BloomFilter(capacity=1000)url = 'www.baidu.com'bf.add(url)print(url in bf)print("www.liuqingzheng.top" in bf)### redis可以实现布隆过滤器## 布隆过滤器可以做什么?1 爬虫去重2 垃圾邮件过滤3 黑白名单4 布隆过滤器避免缓存击穿

自定义去重规则(通过布隆过滤器)

	集合去重,随着数据量越来越大---》很占空间sad  3bytesaaa   3bytes1bytes就有8个格00100000   00100000 00100000 00000000   00000000 00000000使用布隆过滤器实现去重from scrapy.dupefilters import BaseDupeFilterfrom scrapy.utils.request import RequestFingerprinterfrom pybloom_live import ScalableBloomFilterclass MyPDupeFilter(BaseDupeFilter):fingerprints = ScalableBloomFilter(initial_capacity=100, error_rate=0.001,mode=ScalableBloomFilter.LARGE_SET_GROWTH)fingerprinter = RequestFingerprinter()def request_seen(self, request):print('zoule')fp = self.request_fingerprint(request)if fp in self.fingerprints:return Trueself.fingerprints.add(fp)return Falsedef request_fingerprint(self, request) -> str:return self.fingerprinter.fingerprint(request).hex()

写去重类

	from scrapy.dupefilters import BaseDupeFilterfrom scrapy.utils.request import RequestFingerprinterfrom pybloom_live import ScalableBloomFilterfrom scrapy.dupefilters import RFPDupeFilterclass MyPDupeFilter(BaseDupeFilter):fingerprints = ScalableBloomFilter(initial_capacity=100, error_rate=0.001,mode=ScalableBloomFilter.LARGE_SET_GROWTH)fingerprinter = RequestFingerprinter()def request_seen(self, request):print('zoule--------------')fp = self.request_fingerprint(request)if fp in self.fingerprints:return Trueself.fingerprints.add(fp)return Falsedef request_fingerprint(self, request) -> str:return self.fingerprinter.fingerprint(request).hex()配置文件DUPEFILTER_CLASS = "myfirstscrapy.MyPDupeFilter.MyPDupeFilter"

九、分布式爬虫

	第三方的scrapy-redis 帮助我们实现分布式爬虫什么是分布式爬虫10条数据要爬取一台机器爬103台机器爬10条数据11--324--738--10条实现分布式爬虫的核心#1、共享队列    schudler 多台机器共享同一个队列#2、同一套去重规则#### 使用步骤####0 下载:pip3 install scrapy-redis1 把之前爬虫类,继承class CnblogsSpider(RedisSpider):2 去掉起始爬取的地址,加入一个类属性redis_key = 'myspider:start_urls'  # redis列表的key,后期我们需要手动插入起始地址3 配置文件中配置DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"  # scrapy redis去重类,使用redis的集合去重# 不使用原生的调度器了,使用scrapy_redis提供的调度器,它就是使用了redis的列表SCHEDULER = "scrapy_redis.scheduler.Scheduler"REDIS_HOST = 'localhost'                            # 主机名REDIS_PORT = 6379                                   # 端口ITEM_PIPELINES = {'mysfirstscrapy.pipelines.MyCnblogsMySqlPipeline': 301,'scrapy_redis.pipelines.RedisPipeline': 400,}4 在不同多台机器上运行scrapy的爬虫,就实现了分布式爬虫:在一台机器上开启多个程序即可5 写入到redis的列表中起始爬取的地址:列表key:myspider:start_urlsrpush myspider:start_urls https://www.cnblogs.com执行报错scrapy-redis(没有做好兼容)和scrapy(很新)的版本要对应版本对应关系--》改scrapy-redis源码

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LabVIEW开发FPGA的高速并行视觉检测系统

LabVIEW开发FPGA的高速并行视觉检测系统 随着智能制造的发展,视觉检测在生产线中扮演着越来越重要的角色,尤其是在质量控制方面。传统的基于PLC的视觉检测系统受限于处理速度和准确性,难以满足当前生产需求的高速和高精度要求。为此&#xf…

Tomcat线程池原理(上篇:初始化原理)

文章目录 前言正文一、从启动脚本开始分析二、ProtocolHandler 的启动原理三、AbstractEndPoint 的启动原理四、创建默认线程池五、参数配置原理5.1 常规的参数配置5.2 自定义线程池5.3 测试自定义线程 前言 在Java Web的开发过程中,Tomcat常用的web容器。SpringBo…

书生·浦语大模型全链路开源体系介绍

背景介绍 随着人工智能技术的迅猛发展,大模型技术已成为当今人工智能领域的热门话题。2022 年 11 月 30 日,美国 OpenAI 公司发布了 ChatGPT 通用型对话系统 并引发了全球 的极大关注,上线仅 60 天月活用户数便超过 1 亿,成为历史…

密码学系列(四)——对称密码2

一、RC4 RC4(Rivest Cipher 4)是一种对称流密码算法,由Ron Rivest于1987年设计。它以其简单性和高速性而闻名,并广泛应用于网络通信和安全协议中。下面是对RC4的详细介绍: 密钥长度: RC4的密钥长度可变&am…

Python爬虫实战入门:爬取360模拟翻译(仅实验)

文章目录 需求所需第三方库requests 实战教程打开网站抓包添加请求头等信息发送请求,解析数据修改翻译内容以及实现中英互译 完整代码 需求 目标网站:https://fanyi.so.com/# 要求:爬取360翻译数据包,实现翻译功能 所需第三方库 …

【OnlyOffice】 桌面应用编辑器,版本8.0已发布,PDF表单、RTL支持、Moodle集成、本地界面主题

ONLYOFFICE桌面编辑器v8.0是一款功能强大、易于使用的办公软件,适用于个人用户、企业团队和教育机构,帮助他们高效地处理文档工作并实现协作。无论是在Windows、macOS还是Linux平台上,ONLYOFFICE都能提供无缝的编辑和共享体验。 目录 ONLYOFF…

Jmeter接口测试+压力测试

Jmeter-http接口脚本 一般分五个步骤:(1)添加线程组 (2)添加http请求 (3)在http请求中写入接入url、路径、请求方式和参数 (4)添加查看结果树 (5)调用接口、…

化学分子Mol2文件格式与使用注意事项

欢迎浏览我的CSND博客! Blockbuater_drug …点击进入 文章目录 前言一、Mol2文件示例二、 Mol2文件主要结构解释及注意事项MOLECULE 字段解释ATOM 字段解释BOND 字段解释SUBSTRUCTURE字段解释 总结参考资料 前言 Mol2格式文件是一个ASCII 文件,由Tripos…

STM32控制max30102读取血氧心率数据(keil5工程)

一、前言 MAX30102是一款由Maxim Integrated推出的低功耗、高精度的心率和血氧饱和度检测传感器模块,适用于可穿戴设备如智能手环、智能手表等健康管理类电子产品。 该传感器主要特性如下: (1)光学测量:MAX30102内置…

Rocky Linux 运维工具yum

一、yum的简介 ​​yum​是用于在基于RPM包管理系统的包管理工具。用户可以通过 ​yum​来搜索、安装、更新和删除软件包,自动处理依赖关系,方便快捷地管理系统上的软件。 二、yum的参数说明 1、install 用于在系统的上安装一个或多个软件包 2、seach 用…

Docker 常用操作命令备忘

Docker 一旦设置好了环境,日常就只要使用简单命令就可以运行和停止。 于是,我每次用的时候,都想不起来一些关键性的命令到底怎么用,特此记录。 一、镜像管理 从公有仓库拉取镜像 (对于使用苹果电脑 M1/M2/M3 芯片的 …

完全分布式运行模式

完全分布式运行模式 分析:之前已经配置完成 ​ 1)准备3台客户机(关闭防火墙、静态ip、主机名称) ​ 2)安装JDK ​ 3)配置环境变量 ​ 4)安装Hadoop ​ 5)配置环境变量 ​ 6&am…

Springboot集成Druid实现监控功能

Druid是阿里巴巴开发的号称为监控而生的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource等等等,秒杀一切。Druid可以很好的监控DB池连接和SQL的执行情况&#…

AOSP10 替换系统launcher

本文实现将原生的launcher 移除&#xff0c;替换成我们自己写的launcher。 分以下几个步骤&#xff1a; 一、新建一个自己的launcher项目。 1.直接使用android studio 新建一个项目。 2.修改AndroidManifest.xml <applicationandroid:persistent"true"androi…

nginx实现http反向代理

一、代理概述 1、代理概念 1.1 正向代理&#xff08;Forward Proxy&#xff09; 概念&#xff1a;正向代理是位于客户端和目标服务器之间的代理服务器&#xff0c;代表客户端向目标服务器发送请求。客户端将请求发送给代理服务器&#xff0c;然后代理服务器将请求转发给目标服…

Prompt 编程的优化技巧

一、为什么要优化 一&#xff09;上下文限制 目前 GPT-3.5 以及 GPT-4最大支持 16K 上下文&#xff0c;比如你输入超过 16k 的长文本&#xff0c;ChatGPT 会提示文本过大&#xff0c;为了避免 GPT 无法回复&#xff0c;需要限制 上下文在16k 以内 上下文对于 GPT 来说是非常重…

【手机端测试】adb基础命令

一、什么是adb adb&#xff08;Android Debug Bridge&#xff09;是android sdk的一个工具 adb是用来连接安卓手机和PC端的桥梁&#xff0c;要有adb作为二者之间的维系&#xff0c;才能让用户在电脑上对手机进行全面的操作。 Android的初衷是用adb这样的一个工具来协助开发人…

第103讲:配置Mycat的Schema逻辑库列表

文章目录 1.Schema逻辑库2.自定义Mycat连接后显示那些Schema 1.Schema逻辑库 使用Mycat登录到数据库后&#xff0c;发现仅显示了一个TESTDB&#xff0c;这个TESTDB并不是后台数据库节点中的数据库&#xff0c;只是Mycat定义的逻辑库Schema&#xff0c;接下来我们就来说明如果自…

蓝桥杯Learning

Part 1 递归和递推 1. 简单斐波那契数列 n int(input())st [0]*(47) # 注意这个地方&#xff0c;需要将数组空间设置的大一些&#xff0c;否则会数组越界 st[1] 0 st[2] 1 # 这个方法相当于是递推&#xff0c;即先求解一个大问题的若干个小问题 def dfs(u):if u 1:print(…

CKA认证,开启您的云原生之旅!

在当今数字化时代&#xff0c;云计算已经成为企业和个人发展的关键技术。而获得CKA&#xff08;Certified Kubernetes Administrator&#xff09;认证&#xff0c;将是您在云原生领域迈出的重要一步。 CKA认证是由Kubernetes官方推出的权威认证&#xff0c;它旨在验证您在Kuber…