第6章 异步爬虫

目录

  • 1. 协程的基本原理
    • 1.1 案例引入
    • 1.2 基础知识
      • 阻塞
      • 非阻塞
      • 同步
      • 异步
      • 多进程
      • 协程
    • 1.3 协程的用法
    • 1.4 定义协程
    • 1.5 绑定回调
    • 1.6 多任务协程
    • 1.7 协程实现
    • 1.8 使用aiohttp
      • 安装
      • 使用
  • 2. aiohttp的使用
    • 2.1 基本介绍
    • 2.2 基本实例
    • 2.3 URL参数设置
    • 2.4 其他请求类型
    • 2.5 POST请求
      • 表单提交
      • JSON数据提交
    • 2.6 响应
    • 2.7 超时设置
    • 2.8 并发限制
  • 3. aiohttp异步爬取实战
    • 3.1 案例介绍
    • 3.2 准备工作
    • 3.3 页面分析
    • 3.4 实现思路
    • 3.5 基本配置
    • 3.6 爬取列表页
      • 实现
        • 通用的爬取方法
        • 爬取列表页
        • 串联并用
      • 合并
    • 3.7 爬取详情页
      • 实现
        • 在main方法中将详情页的ID获取出来
        • 爬取详情页
        • main方法增加对scrape_detail方法的调用
      • 合并

1. 协程的基本原理

1.1 案例引入

  • https://www.httpbin.org/delay/5
  • 服务器强制等待5秒才能返回响应
import logging
import time
import requestslogging.basicConfig(level=logging.INFO,format='%(asctime)s %(levelname)s: %(message)s')URL = "https://www.httpbin.org/delay/5"
TOTAL_NUMBER = 10start_time = time.time()for _ in range(1, TOTAL_NUMBER):logging.info(f"scraping {URL}")response = requests.get(URL)end_time = time.time()
logging.info(f"total time {end_time - start_time}")

1.2 基础知识

阻塞

  • 阻塞状态:程序未得到所需计算资源时被挂起的状态
  • 程序在操作上是阻塞的:程序在等待某个操作完成期间,自身无法继续干别的事情

非阻塞

  • 程序在操作上非是阻塞的:程序在等待某操作的过程中,自身不被阻塞,可以继续干别的事情
  • 仅当程序封装的级别可以囊括独立的子程序单元时,程序才可能存在非阻塞状态
  • 因阻塞的存在而存在

同步

  • 程序单元同步执行:不同程序单元为了共同完成某个任务,在执行过程中需要靠某种通信方式保持协调一致

异步

  • 为了完成某种任务,有时不同程序单元之间无需通信协调也能完成任务

多进程

  • 利用CPU的多核优势,在同i一时间并行执行多个任务,可以大大提高执行效率

协程

  • 一种运行在用户态的轻量级线程
  • 拥有自己的寄存器上下文和栈
  • 调度切换
    • 将寄存器上下文和栈保存到其他地方,等切回来时,再恢复先前保存的寄存器上下文和栈
  • 能保留上一次调用时的状态,所有局部状态的一个特定组合,每次过程重入,就相当于进入上一次调用的状态
  • 本质上是个单线程
  • 实现异步操作

1.3 协程的用法

  • asyncio库
    • event_loop:
      • 事件循环
      • 把函数注册到这个事件循环上,当满足发生条件时,就调用对应的处理方法
    • coroutine:
      • 协程
      • 代指协程对象类型
      • 可以将协程对象注册到时间循环中,它会被事件循环调用
    • task:
      • 任务
      • 对协程对象的进一步封装
        • 包含协程对象的各个状态
    • future:
      • 将来执行或者没有执行的任务的结果
      • 和task没有本质区别
    • async关键字:
      • 定义一个方法(协程)
        • 这个方法在调用时不会立即被执行,而是会返回一个协程对象
    • await关键字:
      • 挂起阻塞方法的执行

1.4 定义协程

import asyncioasync def execute(x):print(f"Number: {x}")coroutine = execute(1)
print(f"Coroutine: {coroutine}")
print("After calling execute")loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine)
print("After calling loop")
  • 把协程对象coroutine传递给run_until_complete方法的时候,实际上进行了一个操作
    • 将coroutine封装成task对象
  • 显示声明task
import asyncioasync def execute(x):print(f"Number: {x}")coroutine = execute(1)
print(f"Coroutine: {coroutine}")
print("After calling execute")loop = asyncio.get_event_loop()
task = loop.create_task(coroutine)
print(f"Task: {task}")loop.run_until_complete(task)
print(f"Task: {task}")
print("After calling loop")
  • 使用ensure_future定义task对象
import asyncioasync def execute(x):print(f"Number: {x}")coroutine = execute(1)
print(f"Coroutine: {coroutine}")
print("After calling execute")task = asyncio.ensure_future(coroutine)
print(f"Task: {task}")loop = asyncio.get_event_loop()
loop.run_until_complete(task)
print(f"Task: {task}")
print("After calling loop")

1.5 绑定回调

  • 为task对象绑定一个回调方法
import asyncio
import requestsasync def request():url = "https://www.baidu.com/"status = requests.get(url)return statusdef callback(task):print(f"Status: {task.result()}")coroutine = request()
task = asyncio.ensure_future(coroutine)
task.add_done_callback(callback)
print(f"Task: {task}")loop = asyncio.get_event_loop()
loop.run_until_complete(task)
print(f"Task: {task}")
  • 等效于
import asyncio
import requestsasync def request():url = "https://www.baidu.com/"status = requests.get(url)return statuscoroutine = request()
task = asyncio.ensure_future(coroutine)
print(f"Task: {task}")loop = asyncio.get_event_loop()
loop.run_until_complete(task)
print(f"Task: {task}")
print(f"Status: {task.result()}")

1.6 多任务协程

  • 定义一个task列表,然后使用wait方法执行
import asyncio
import requestsasync def request():url = "https://www.baidu.com/"status = requests.get(url)return statustasks = [asyncio.ensure_future(request()) for _ in range(5)]
print(f"Tasks: {tasks}")loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))for task in tasks:print(f"Task result: {task.result()}")

1.7 协程实现

  • 单纯使用上述方法
import asyncio
import time
import requestsasync def request():url = "https://www.httpbin.org/delay/5"print(f"Waiting for {url}")response = requests.get(url)print(f"Response: {response} from {url}")start = time.time()tasks = [asyncio.ensure_future(request()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))end = time.time()
print(f"Cost time: {end - start}")
  • 没有任何变化
  • 要实现异步处理,需要先执行挂起操作
    • 将耗时等待的操作挂起,让出控制权
import asyncio
import time
import requestsasync def request():url = "https://www.httpbin.org/delay/5"print(f"Waiting for {url}")response = await requests.get(url)print(f"Response: {response} from {url}")start = time.time()tasks = [asyncio.ensure_future(request()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))end = time.time()
print(f"Cost time: {end - start}")
  • 报错
    • requests返回的Response对象不能和await一起使用
    • await后面的对象必须是如下格式之一:
      • 一个原生协程对象
      • 一个由types.coroutine修饰的生成器
        • 这个生成器可以返回协程对象
      • 由一个包含__ await __方法的对象返回的一个迭代器
  • 将请求页面的方法独立出来
import asyncio
import time
import requestsasync def get(url):return requests.get(url)async def request():url = "https://www.httpbin.org/delay/5"print(f"Waiting for {url}")response = await get(url)print(f"Response: {response} from {url}")start = time.time()tasks = [asyncio.ensure_future(request()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))end = time.time()
print(f"Cost time: {end - start}")
  • 依然没有任何变化

1.8 使用aiohttp

安装

pip3 install aiohttp

使用

import asyncio
import time
import aiohttpasync def get(url):session = aiohttp.ClientSession()response = await session.get(url)await response.text()await session.close()return responseasync def request():url = "https://www.httpbin.org/delay/5"print(f"Waiting for {url}")response = await get(url)print(f"Response: {response} from {url}")start = time.time()tasks = [asyncio.ensure_future(request()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))end = time.time()
print(f"Cost time: {end - start}")

2. aiohttp的使用

2.1 基本介绍

  • asyncio:实现对TCP、UDP、SSL协议的异步操作
  • aiohttp:实现对HTTP请求的异步操作
  • aiohttp是基于asyncio的异步HTTP网络模块
    • 既提供了服务端,又提供了客户端
      • 服务端
        • 可以搭建一个支持异步处理的服务器
          • 用于处理请求并返回响应
        • 类似于Django、Flask、Tornado等一些Web服务器
      • 客户端
        • 发起请求
        • 类似于使用request发起一个HTTP请求然后获得响应
          • request发起的是同步网络请求
          • aiohttp发起的是异步网络请求

2.2 基本实例

import aiohttp
import asyncioasync def fetch(session, url):# 上下文管理器,自动分配和释放资源async with session.get(url) as response:return await response.json(), response.statusasync def main():# 上下文管理器,自动分配和释放资源async with aiohttp.ClientSession() as session:url = "https://www.httpbin.org/delay/5"html, status = await fetch(session, url)print(f"html: {html}")print(f"status: {status}")if __name__ == "__main__":loop = asyncio.get_event_loop()loop.run_until_complete(main())# 较高版本的python可以不显示声明事件循环asyncio.run(main())

2.3 URL参数设置

import aiohttp
import asyncioasync def main():params = {"name": "abc", "age": 10}async with aiohttp.ClientSession() as session:async with session.get("https://www.httpbin.org/get", params=params) as response:print(await response.text())if __name__ == "__main__":asyncio.run(main())

2.4 其他请求类型

session.post("https://www.httpbin.org/post", data=b"data")
session.put("https://www.httpbin.org/put", data=b"data")
session.delete("https://www.httpbin.org/delete")
session.head("https://www.httpbin.org/get")
session.options("https://www.httpbin.org/get")
session.patch("https://www.httpbin.org/patch", data=b"data")

2.5 POST请求

表单提交

import aiohttp
import asyncioasync def main():data = {"name": "abc", "age": 10}async with aiohttp.ClientSession() as session:async with session.post("https://www.httpbin.org/post", data=data) as response:print(await response.text())if __name__ == "__main__":asyncio.run(main())

JSON数据提交

import aiohttp
import asyncioasync def main():data = {"name": "abc", "age": 10}async with aiohttp.ClientSession() as session:async with session.post("https://www.httpbin.org/post", json=data) as response:print(await response.text())if __name__ == "__main__":asyncio.run(main())

2.6 响应

import aiohttp
import asyncioasync def main():data = {"name": "abc", "age": 10}async with aiohttp.ClientSession() as session:async with session.post("https://www.httpbin.org/post", data=data) as response:print(f"status: {response.status}")print(f"headers: {response.headers}")print(f"body: {await response.text()}")print(f"bytes: {await response.read()}")print(f"json: {await response.json()}")if __name__ == "__main__":asyncio.run(main())

2.7 超时设置

  • 使用ClientTimeout对象设置超时
import aiohttp
import asyncioasync def main():# 设置2秒的超时时间timeout = aiohttp.ClientTimeout(total=2)async with aiohttp.ClientSession(timeout=timeout) as session:async with session.get("https://www.httpbin.org/get") as response:print(f"status: {response.status}")if __name__ == "__main__":asyncio.run(main())

2.8 并发限制

  • 使用Semeaphore来控制并发量
    • 防止网站在短时间内无法响应
    • 避免将目标网站爬挂掉的风险
import aiohttp
import asyncio# 爬取的最大并发量
CONCURRENCY = 5
URL = "https://www.baidu.com/"# 创建一个信号量对象
semaphore = asyncio.Semaphore(CONCURRENCY)
session = Noneasync def scrape_api():# 信号量可以控制进入爬取的最大协程数量async with semaphore:print(f"Scraping {URL}")async with session.get(URL) as response:await asyncio.sleep(1)return await response.text()async def main():global sessionsession = aiohttp.ClientSession()scrape_index_tasks = [asyncio.ensure_future(scrape_api()) for _ in range(1000)]await asyncio.gather(*scrape_index_tasks)if __name__ == "__main__":asyncio.run(main())

3. aiohttp异步爬取实战

3.1 案例介绍

  • 目标网站:Scrape | Book
    • 网站数据由JavaScript渲染获得
    • 数据可以通过Ajax接口获取
    • 接口没有设置任何反爬措施和加密参数
  • 目标:
    • 使用aiohttp爬取全站的数据
    • 将数据通过异步的方式保存到 MongoDB 中

3.2 准备工作

  • MongoDB数据库

3.3 页面分析

  • 列表页的Ajax请求接口的格式:https://spa5.scrape.center/api/book/?limit=18&offset={offset}
    • limit:每一页包含多少书
    • offest:每一页的偏移量( o f f s e t = l i m i t ∗ ( p a g e − 1 ) offset=limit*(page-1) offset=limit(page1)
  • Ajax接口返回的数据中有每本书的id,利用id可以进入该书的详情页
  • 详情页的Ajax请求接口的格式:https://spa5.scrape.center/detail/{id}
    • id:书本身的ID

3.4 实现思路

  • 爬取的两个阶段:
    • 异步爬取所有列表页
      • 将所有列表页的爬取任务集合在一起,并将其声明为由task组成的列表,进行异步爬取
    • 拿到上一步列表页的所有内容并解析
      • 将所有图书的id信息组合为所有详情页的爬取任务集合,并将其声明为task组成的列表,进行异步爬取,同时爬取结果也以异步方式存储到MongoDB中

3.5 基本配置

import logginglogging.basicConfig(level=logging.INFO,format='%(asctime)s %(levelname)s: %(message)s')INDEX_URL = "https://spa5.scrape.center/api/book/?limit=18&offset={offset}"
DETAIL_URL = "https://spa5.scrape.center/detail/{id}"
PAGE_SIZE = 18
PAGE_NUMBER = 100
CONCURRENCY = 5

3.6 爬取列表页

实现

通用的爬取方法
import asyncio
import aiohttpasync def scrape_api(url):async with semaphore:try:logging.info(f"Scraping: {url}")# verify_ssl: 是否开启SSL认证async with session.get(url, verify_ssl=False) as response:return await response.json()except aiohttp.ClientError:logging.info(f"Error: {url}", exc_info=True)
爬取列表页
async def scrape_index(page):url = INDEX_URL.format(offset=PAGE_SIZE * (page - 1))return await scrape_api(url)
串联并用
import jsonasync def main():global sessionsession = aiohttp.ClientSession()scrape_index_tasks = [asyncio.ensure_future(scrape_index(page)) for page in range(1, PAGE_NUMBER + 1)]results = await asyncio.gather(*scrape_index_tasks)logging.info(f"Results: {json.dumps(results, ensure_ascii=False, indent=2)}")if __name__ == "__main__":asyncio.run(main())

合并

import json
import asyncio
import logging
import aiohttplogging.basicConfig(level=logging.INFO,format='%(asctime)s %(levelname)s: %(message)s')INDEX_URL = "https://spa5.scrape.center/api/book/?limit=18&offset={offset}"
DETAIL_URL = "https://spa5.scrape.center/detail/{id}"
PAGE_SIZE = 18
PAGE_NUMBER = 100
CONCURRENCY = 5semaphore = asyncio.Semaphore(CONCURRENCY)
session = Noneasync def scrape_api(url):async with semaphore:try:logging.info(f"Scraping: {url}")async with session.get(url, verify_ssl=False) as response:return await response.json()except aiohttp.ClientError:logging.info(f"Error: {url}", exc_info=True)async def scrape_index(page):url = INDEX_URL.format(offset=PAGE_SIZE * (page - 1))return await scrape_api(url)async def main():global sessionsession = aiohttp.ClientSession()scrape_index_tasks = [asyncio.ensure_future(scrape_index(page)) for page in range(1, PAGE_NUMBER + 1)]results = await asyncio.gather(*scrape_index_tasks)logging.info(f"Results: {json.dumps(results, ensure_ascii=False, indent=2)}")if __name__ == "__main__":asyncio.run(main())

3.7 爬取详情页

实现

在main方法中将详情页的ID获取出来
ids = []
for index_data in results:if not index_data:continuefor item in index_data.get("results"):ids.append(item.get("id"))
爬取详情页
async def scrape_detail(id):url = DETAIL_URL.format(id=id)data = await scrape_api(url)logging.info(f"Saving: {data}")
main方法增加对scrape_detail方法的调用
scrape_detail_tasks = [asyncio.ensure_future(scrape_detail(id)) for id in ids]await asyncio.wait(scrape_detail_tasks)await session.close()

合并

import json
import asyncio
import logging
import aiohttplogging.basicConfig(level=logging.INFO,format='%(asctime)s %(levelname)s: %(message)s')INDEX_URL = "https://spa5.scrape.center/api/book/?limit=18&offset={offset}"
DETAIL_URL = "https://spa5.scrape.center/api/book/{id}"
PAGE_SIZE = 18
PAGE_NUMBER = 100
CONCURRENCY = 5semaphore = asyncio.Semaphore(CONCURRENCY)
session = Noneasync def scrape_api(url):async with semaphore:try:logging.info(f"Scraping: {url}")async with session.get(url, verify_ssl=False) as response:return await response.json()except aiohttp.ClientError:logging.info(f"Error: {url}", exc_info=True)async def scrape_index(page):url = INDEX_URL.format(offset=PAGE_SIZE * (page - 1))return await scrape_api(url)async def scrape_detail(id):url = DETAIL_URL.format(id=id)data = await scrape_api(url)logging.info(f"Saving {url}: {data}")async def main():global sessionsession = aiohttp.ClientSession()scrape_index_tasks = [asyncio.ensure_future(scrape_index(page)) for page in range(1, PAGE_NUMBER + 1)]results = await asyncio.gather(*scrape_index_tasks)logging.info(f"Results: {json.dumps(results, ensure_ascii=False, indent=2)}")ids = []for index_data in results:if not index_data:continuefor item in index_data.get("results"):ids.append(item.get("id"))scrape_detail_tasks = [asyncio.ensure_future(scrape_detail(id)) for id in ids]await asyncio.wait(scrape_detail_tasks)await session.close()if __name__ == "__main__":asyncio.run(main())

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

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

相关文章

Java数据结构之《哈希查找》题目

一、前言: 这是怀化学院的:Java数据结构中的一道难度中等的一道编程题(此方法为博主自己研究,问题基本解决,若有bug欢迎下方评论提出意见,我会第一时间改进代码,谢谢!) 后面其他编程题只要我写完…

ChatGPT成为“帮凶”:生成虚假数据集支持未知科学假设

ChatGPT 自发布以来,就成为了大家的好帮手,学生党和打工人更是每天都离不开。 然而这次好帮手 ChatGPT 却帮过头了,莫名奇妙的成为了“帮凶”,一位研究人员利用 ChatGPT 创建了虚假的数据集,用来支持未知的科学假设。…

HarmonyOS应用开发——程序框架UIAbility、启动模式与路由跳转

前言 UIAbility简单来说就是一种包含用户界面的应用组件,用于和用户进行交互。每一个UIAbility实例,对应于一个最近任务列表中的任务。 一个应用可以有一个UIAbility,也可以有多个UIAbility。一个UIAbility可以对应于多个页面,建议…

半监督语义分割综述

paper link:https://arxiv.org/pdf/2302.09899.pdf 1. Introduction 图像分割是最古老、研究最广泛的计算机视觉 (CV) 问题之一。图像分割是指将图像划分为不同的非重叠区域,并将相应的标签分配给图像中的每个像素,最终获得ROI区域位置及其类…

线上CPU飙高问题排查!

https://v.douyin.com/iRTqH5ug/ linux top命令 top 命令是 Linux 下一个强大的实用程序,提供了系统资源使用情况的动态、实时概览。它显示了当前正在运行的进程信息,以及有关系统性能和资源利用情况的信息。 以下是 top 命令提供的关键信息的简要概述…

Linux 内核源码各版本下载

下载地址: kernel/git/stable/linux.git - Linux kernel stable treehttps://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/refs/ 1. Linux 内核的基本概念: 内核是什么? 内核是操作系统的核心部分,负责管理系统…

springboot工作原理

Spring Boot 是一个用于创建独立的、基于Spring框架的Java应用程序的开发框架。它简化了Spring应用程序的配置和部署过程,提供了一种快速、方便的方式来构建可扩展的、可部署的应用程序。 Spring Boot 的工作原理可以概括如下: 1. 自动配置&#xff08…

割裂式“多渠道”不是真正的全渠道!浅析全渠道零售和DTC在理念上的不谋而合|徐礼昭

图文:徐礼昭 全渠道零售概念解析 全渠道零售概念由来已久,单纯从业务经营角度,一个品牌在线上线下多个渠道铺货卖货,只能说是多渠道零售,而不是全渠道零售。商派市场负责人徐礼昭认为,品牌企业应该从消费者…

Java JDBC SQLite 示例

SQLite是一个简单、小巧、快速、可靠、无服务器、零配置和无需安装的 SQL 数据库库,它与客户端应用程序在进程中运行。尽管www.sqlite.org没有官方的 JDBC 驱动程序库,但www.xerial.org提供了一个——一个 XML 数据库管理系统项目。 1.下载SQLite JDBC驱…

wpf devexpress 使用IDataErrorInfo实现input验证

此处下载源码 当form初始化显示,Register按钮应该启动和没有输入错误应该显示。如果用户点击注册按钮在特定的输入无效数据,form将显示输入错误和禁用的注册按钮。实现逻辑在标准的IDataErrorInfo接口。请查阅IDataErrorInfo接口(System.Com…

Fabric:创建应用通道

搭建自定义网络可以参考文章: https://blog.csdn.net/yeshang_lady/article/details/134113296 1 创建通道 网络搭建完成之后,就可以开始创建通道了。Fabric V2.5.4中可以在不创建系统通道的情况下直接创建应用通道。 1.1 修改配置文件 先创建配置文…

【AIGC】接着昨天的AI“洗图”骚操作,继续调戏国产大模型

目录 一、洗稿,洗图,洗视频 二、如何洗图 2.1 先看看效果 2.2 如何做的 2.3 提示词示例 三、试试星火和通义 2.1 星火和通义的特点 2.2 星火的做图能力理解力强,准确度还有待提高 2.3 通义大模型伺候 2.4 这3个大模型可以配合使用 …

【1day】华天软件 OA ntkodownload接口任意文件读取学习

注:该文章来自作者日常学习笔记,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与作者无关。 目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现

结构体||联合体

1.结构体 1.1实际生活中一些东西往往有多个元素组成。如一名学生有身高、体重、名字、学号等。这时候就需要用到结构体。 结构体是一些值的结合,这些值被称为成员变量。结构体的每个成员可以是不同类型的变量,如:标量、数组、指针、甚至是其…

基于模型生成代码(MBD)

基于模型生成代码(MBD) 1、MBD的基本概念 图形化模型:MBD主要使用图形化的方式来表示系统。这些模型可以是控制流程图、状态机、或者其他形式的图形表示,能够清晰地展示系统的行为和逻辑。从概念到实现:在MBD中,整个开发流程从概念设计开始,直至实现和测试,都围绕模型…

基于2D激光雷达匹配的充电桩位姿检测

原理 1. 激光雷达滤波,滤除太远的雷达数据,并降采样 2. 对雷达数据进行分割聚类出candidates 3. 通过策略,过滤掉大部分不符合的candidates 4. 对candidates与充电桩模板数据进行PCA、ICP匹配 5. 选择距离最小或者得分最高的一帧作为输出…

传纸条(算法题)

题目来源 传纸条 题目描述: 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法…

提高wordpress网站收录速度,设置wp后台的“更新服务”功能

搜索引擎会按照某个规律定期的来抓取网站的内容,其抓取你网站的频率一般和网站的更新速度有关,如果网站内容更新频繁,那么网络蜘蛛也会频繁的访问网站。每天坚持更新文章显然这对一般个人博主来说有难度,另一个方法就是每当我们发…

redis——布隆过滤器

一:布隆过滤器是什么? 由一个初值都为零的bit数组和多个哈希函数构成,用来快速判断集合中是否存在某个元素,不保存数据信息,只是在内存中做一个是否存在的标记 二:布隆过滤器能干什么? 高效…

HTB_Archetype攻击全流程

Archetype (SMB、SQL Server xp_cmdshell、反弹shell、winPEASx64、psexec远程连接) TASK 1 问题: 哪个TCP端口托管着数据库服务器?目的: 识别运行数据库服务的端口,通常通过端口扫描(如使用nmap)来完成。 TASK 2 问题: 通过S…