seleniumplaywright获取网站Authorization鉴权实现伪装requests请求

news2024/11/23 10:16:28

文章目录

  • selenium&playwright获取网站Authorization鉴权实现伪装requests请求
    • 需求背景
    • 知识点:selenium获取已登录网站的用户鉴权信息
    • 知识点:playwright获取cookie
    • 知识点:playwright获取storage_state提取cookie
    • 秃发状况
      • windows禁止chrome浏览器自动更新
      • selenium自动下载驱动
      • playwright无驱动操作已打开浏览器
    • Authorization鉴权
    • playwright 事件监听
    • 使用route劫持
    • 最终代码

selenium&playwright获取网站Authorization鉴权实现伪装requests请求

本文已实战为主,如果不熟悉selenium或playwright,建议补充相关知识点:

cookie、session、request、headers相关概念

selenium:get_log() 获取用户权限信息,打开指定浏览器,免登陆,伪造请求头

playwright:类方法-Page,Request,Route,Docs-Authentication,Network

本文使用的各个框架版本如下:

python-3.8.8
selenium-3.141.0
playwright-1.32.1
requests-2.27.1

其中selenium4与selenium3的操作有一些差异,这里不做研究。

吐槽一下,playwright的资料是真的很少(基础资料除外),只能自己去看官网,官网写的还是可以的,自己多试试还是可以搞出点东西来的,但真的好累,呜呜呜~

需求背景

1、登录google类web端,通过自动化手段登录会被google监控并屏蔽登录请求,严重有封号风险(在之前的文章有讲过)。

2、selenium或playwright打开指定已登录google账号的浏览器,获取用户鉴权信息。

3、伪造请求头,通过requests获取对应接口的信息,进行数据拉取。

本文实战背景以FireBase后台为列,https://console.firebase.google.com/

没有接触过的,可以用Gmail等其他系列的google应用,但重在思路和方法,详见后文一步步解析。

知识点:selenium获取已登录网站的用户鉴权信息

直接上代码

__author__ = "梦无矶小仔"
import json,time,requests
from datetime import datetime, timedelta
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

def get_headers():
    # 关键步骤 1:下面两行代码是用来设置特性,获取request的信息前提步骤。
    d = DesiredCapabilities.CHROME
    d['loggingPrefs'] = {'performance': 'ALL'}
    options = webdriver.ChromeOptions()
    options.add_experimental_option('useAutomationExtension', False)
    # # 防止打印一些无用的日志
    options.add_experimental_option("excludeSwitches", ['enable-automation', 'enable-logging'])
    options.add_argument("--disable-software-rasterizer")

    chrome_options = Options()
    chrome_options.add_experimental_option('w3c', False)
    chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
    chrome_driver = "./chromedriver.exe"  # 我是把chromedriver驱动放在项目根目录下
    driver = webdriver.Chrome(executable_path=chrome_driver, options=options, chrome_options=chrome_options)
    driver.get("https://console.firebase.google.com/")
    info = driver.get_log('performance')
    cookie_list = []
    for i in info:
        dic_info = json.loads(i["message"])  # 把json格式转成字典。
        infom = dic_info["message"]  # request 信息,在字典的 键 ["message"]['params'] 中。
        if infom['method'] == 'Network.requestWillBeSentExtraInfo' and infom["params"]["headers"].get(":authority"):
            if infom["params"]["headers"][":authority"] == "mobilesdk-pa.clients6.google.com" and \
                    infom["params"]["headers"][":method"] == 'POST':
                cookie_list.append(infom["params"]["headers"])

    authorization = cookie_list[0]["authorization"]
    cookie = cookie_list[0]["cookie"]
	
    # 伪造请求头
    headers = {
        "Host": "crashlytics-pa.clients6.google.com",
        "content-type": "application/json",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36 Edg/96.0.1054.62",
        "referer": "https://console.firebase.google.com/",
        "cookie": cookie,
        "origin": "https://console.firebase.google.com",
        "authorization": authorization
    }

    return headers

代码解析

1、好像没啥解析的,就是通过performance的log去过滤我要的接口,拿到接口中的各项信息

2、哪里看不懂给我留言吧

注意

我使用的是selenium3,如果你是selenium4,你需要使用如下方法获取:

from seleniumwire import webdriver  #pip install selenium-wire
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('http://....') #打开
#获取Authorization_str
Authorization_str=''
for request in  browser.requests:  #遍历所有 请求
    # if request.method == 'POST' and \
    #    request.url == 'http://....': #找到这个请求
        if 'Authorization' in request.headers: #有这个标志
            Authorization_str = request.headers['Authorization']  #找到了结果
            break

要点:

1、装完selenium后,还得装selenium-wire

from seleniumwire import webdriver  #pip install selenium-wire
代替
from selenium import webdriver

2、仅browser 使用 seleniumwire, 其他都不变,例如 By、keys等还用selenium

知识点:playwright获取cookie

playwright官方cookie代码:BrowserContext | Playwright Python

方法一:

自动打开浏览器,手动登录后通过playwright保存cookie到本地,之后需要直接通过文件读取这个cookie。

__author__ = "梦无矶小仔"
from playwright.sync_api import sync_playwright
import json
# 先手动登录,保存Cooies到文件。
def saveCookies():
    with sync_playwright() as p:
        # 显示浏览器,每步操作等待100毫秒
        browser = p.chromium.launch(headless=False, slow_mo=100)
        context = browser.new_context()
        page = context.new_page()
        page.goto('https://cq.meituan.com/', timeout=50000)  # 设置超时时间为50s
        time.sleep(80)  # 此处手动登录,然后到个人信息页再获取cookie
        cookies = context.cookies()
        print(page.title())
        browser.close()
        f = open('cookies.txt', 'w+',,encoding="utf-8")
        json.dump(cookies, f)
        time.sleep(2)
        browser.close()
        print("cookie获取完毕")
saveCookies()#执行函数

方法二:

手动打开指定浏览器,使playwright指定改浏览器运行,获取已登录的cookie信息,保存到本地。

__author__ = "梦无矶小仔"
# 对已经打开的浏览器进行操作
import json
import subprocess
from pprint import pprint
from playwright.sync_api import Playwright,sync_playwright

playwright = sync_playwright().start()
# 连接已打开浏览器,指定端口
browser = playwright.chromium.connect_over_cdp("http://127.0.0.1:9222")
default_context = browser.contexts[0] # 注意这里不是browser.new_page()了
page = default_context.pages[0]
base_url = r"https://console.firebase.google.com/" # 我这里截去了项目网站的url进行脱敏
page.goto(base_url)
# page.wait_for_timeout(timeout=15000)
print(page.title()) #firebase标题
time.sleep(5)
cookies = default_context.cookies(urls=base_url) #指定url下的cookie值,不填则是所有的
pprint(cookies)
# 保存cookies到本地
filePath = r'cookies.txt'
with open(filePath,'w+',encoding="utf-8") as f:
    json.dump(cookies,f)

playwright.stop() 

知识点:playwright获取storage_state提取cookie

F12打开浏览器,在Aplication下可以看到本地存储的一些信息,比如cookie、session

请添加图片描述

官方教程:BrowserContext | Playwright Python

__author__ = "梦无矶小仔"
# 对已经打开的浏览器进行操作
import json
import subprocess
import time
from pprint import pprint
from playwright.sync_api import Playwright,sync_playwright

playwright = sync_playwright().start()
# 连接已打开浏览器,找好端口
browser = playwright.chromium.connect_over_cdp("http://127.0.0.1:9222")
default_context = browser.contexts[0] # 注意这里不是browser.new_page()了
page = default_context.pages[0]
base_url = r"https://console.firebase.google.com"  # 我这里截去了项目网站的url进行脱敏
page.goto(base_url)
print(page.title()) #firebase标题
filePath = r'storage_state.txt'
storage_state = default_context.storage_state(path=filePath)
pprint(storage_state)
playwright.stop()
# browser.close()

但这个方法会有个问题,这里面会把你当前浏览器所有的strong存储的内容拿出来。

如果是像我只是针对某个网站接口的cookie,这个方法就显得有点臃肿,还需要自己去整体过滤,而且本地的还存在一个及时刷新的问题(我遇到过有效期非常短的)。

秃发状况

2023.5.10这天,windows自动更新了,它更新就算了,还自动把我固定版本的chrome浏览器也给更新到了最新版本。

我原先就禁用了chrome自动更新的功能,这次windows更新竟然可以解禁,就很离谱。

这里更新一下windows禁止chrome浏览器自动更新。当前版本是 113.0.5672.93(正式版本) (64 位)

那么浏览器更新了我会遇到一个怎样的问题?

1、selenium是倚靠驱动进行浏览器操作,浏览器更新了我就得更新驱动,但我没有做自动更新驱动的功能

2、之前一直用的是固定某个版本,这样驱动一直用一个就行,现在不得不面临三个选择

  • 更新驱动,再次禁用更新,以后遇到再说(麻烦)

  • 增加自动更新驱动的功能(后续会意想不到的坑)

  • UI层面改为playwright,因为playwright无需依赖三方驱动(懒汉必备)

于是这三个我都研究了一下,接下来一一解析一下。

windows禁止chrome浏览器自动更新

1、找到C:\Users\xiaozai\AppData\Local\Google目录下的Update文件夹

请添加图片描述

2、右键属性,选择安全选项,点击编辑,把这些用户的权限全部改成拒绝

请添加图片描述

3、在安全选项下,点击高级,点击禁用继承,删除允许用户,点击确认

请添加图片描述

4、中途点击确认的时候,由于你禁止了权限,会有一堆弹窗,一直点确认就ok了

5、验证,之后你再双击Updata文件夹,发现是无权访问了

请添加图片描述

6、去chrome查看更新选项,发现已经无法更新了

请添加图片描述

selenium自动下载驱动

使用Drivers的方式

官方介绍:https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/

先安装库:

pip install webdriver-manager

webdriver-manager 支持selenium3.0、selenium4.0

具体可以看github上的说明:https://github.com/SergeyPirogov/webdriver_manager

基于 selenium3 的chrome示列

# pip install webdriver-manager
#selenium3
import time
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get("https://www.baidu.com")
driver.maximize_window()
time.sleep(5)
driver.quit()

基于 selenium4 的chrome示列

import time
from selenium import webdriver
from selenium.webdriver.edge.service import Service
from webdriver_manager.chrome import ChromeDriverManager

service = Service(executable_path=ChromeDriverManager().install())
driver = webdriver.Ie(service=service)
driver.get("https://www.baidu.com")
driver.maximize_window()
time.sleep(5)
driver.quit()

是不是非常简单,非常nice?

官方的列子这里我就不放了,大家有兴趣自己去研究哈~

playwright无驱动操作已打开浏览器

详见我之前写的文章,这里就不赘述了,链接如下:

公众号:playwright连接已有浏览器操作 (qq.com)

CSDN:https://blog.csdn.net/qq_46158060/article/details/130429536?spm=1001.2014.3001.5501

Authorization鉴权

对于google类型的所有认证权限都含有一个Authorization,并且加密是SAPISIDHASH,这个我不会破解。

请添加图片描述

如果请求头不携带此鉴权字段,是无法访问相关接口的。

请添加图片描述

{
  "error": {
    "code": 401,
    "message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
    "status": "UNAUTHENTICATED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "CREDENTIALS_MISSING",
        "domain": "googleapis.com",
        "metadata": {
          "service": "crashlytics-pa.googleapis.com",
          "method": "google.internal.crashlytics.dashboard.v1.CrashlyticsMetricsReadService.GetCrashStatistics"
        }
      }
    ]
  }
}

通过selenium知道可以在performance获取request请求信息(前文有demo),那么playwright是否有类似的方法?

通过查阅官方文档发现,确实有,它叫事件监听。

目前我们就需要拿到请求头的这些信息,从而通过接口进行获取数据。

Authorization
Cookie
Origin
Referer
User-Agent

playwright 事件监听

官方文档:

page.on事件监听:https://playwright.dev/python/docs/api/class-page#page-event-request

request拦截接口:https://playwright.dev/python/docs/api/class-request

事件监听我们主要使用的是page.on("request",my_request),其他监听事件可以参考官网。

Request事件里面有个all_headers方法,会以字典的形式返回我们请求的请求头信息。

请添加图片描述

request拦截接口代码示列:

def my_request(request):
    print(request.all_headers())

page.on("request",my_request) # 创建拦截请求,获取请求的hearders  
# 这里推荐使用requestfinished

注意:page.on在page实例后就要创建,代表监控之后page上发生的对应事件。如果在事件发生后创建page.on方法,则无法监控该事件,只能监控创建page.on之后的操作。

如我监控了FireBase后台数据页面,示列代码如下

import json
from pprint import pprint
import requests
from playwright.sync_api import sync_playwright

def my_request(request):
    print(request.all_headers())
    # 对headers进行劫持处理

playwright = sync_playwright().start()
# 连接已打开浏览器,找好端口
browser = playwright.chromium.connect_over_cdp("http://127.0.0.1:9222")
default_context = browser.contexts[0] # 注意这里不是browser.new_page()了
page = default_context.pages[0]
page.on("requestfinished",my_request) # 创建拦截请求,获取请求的hearders
base_url = r"https://console.firebase.google.com/"
page.goto(base_url)
page.wait_for_load_state('networkidle') #等待资源加载,直到没有网络请求,否则得到的资源不完整,拿不到想要的鉴权信息

控制台输出监控到了的所有请求头信息,authorization字段赫然在列,我们可以继续改造my_request方法,拿到我们所需要的headers信息。

请添加图片描述

但这个时候还遇到个问题,这里获取到的authorization并不是我真正能够使用的,我还需要对referer字段进行过滤,但发现并没有我要找的,F12查看network发现前端是刷新出来了。打印出来的却全是https://console.firebase.google.com/

请添加图片描述

需要在请求后加上这句,表示等待资源加载,直到没有网络请求。详细可以看官网:https://playwright.dev/python/docs/api/class-page#page-wait-for-load-state

page.wait_for_load_state('networkidle')

但有时候也会有点不灵,所以我推荐使用强制等待。

page.wait_for_timeout(timeout=20000) # 这个timeout是毫秒

接下来需要对这些请求头进行过滤,我只需要拿到一个包含Authorization字段的headers字段的信息就可以结合前面拿到的cookie进行伪造了。

同时过滤:authority字段,注意,F12你看到的首字母是大写,playwright官方文档中有说明,headers返回的都是小写字段,所以我们拿的时候要以小写的方式进行提取。

改造后的my_request方法

# 全局变量
user_headers = {}
def my_request(request):
    all_headers_dict = request.all_headers()
    # 过滤请求(这里我对:path也进行了过滤,完整path我脱敏处理了)
    if all_headers_dict.get(':path') == "/metrics:getCrashFree.." and not user_headers:
        if all_headers_dict[":method"]=='POST' and all_headers_dict[":authority"]=='crashlytics-pa.clients6.google.com' :
            # 提取我需要的信息
            user_headers["cookie"] = all_headers_dict.get("cookie")
            user_headers["user-agent"] = all_headers_dict.get("user-agent")
            user_headers["authorization"] = all_headers_dict.get("authorization")

最终会将第一次获取到的headers信息记录到user_headers字典中。

接着我们就可以使用requests进行携带带有认证信息的请求头进行接口请求了。

使用route劫持

官方文档:Route | Playwright Python

用这个方法也可以获取到请求头的相关信息,它最终还是使用了request获取请求头。

我在使用的过程中发现有时候请求会被阻塞,不知道为啥,对这方面有研究的大佬请指教我一哈,万分感谢。

user_msg_list = []
def handler(route):
    headers_dict = {}
    all_headers_dict = route.request.headers
    if all_headers_dict.get('authorization') and all_headers_dict.get('cookie'):
        # if 'https://scone-pa.clients6.google.com/static/proxy' in all_headers_dict["referer"]:
            # 提取我需要的信息
            headers_dict["referer"] = all_headers_dict.get("referer")
            headers_dict["user-agent"] = all_headers_dict.get("user-agent")
            headers_dict["authorization"] = all_headers_dict.get("authorization")
            headers_dict["cookie"] = all_headers_dict.get("cookie")
            user_msg_list.append(headers_dict)
    route.continue_()

page.route(**/*,handler)
page.wait_for_load_state('networkidle')

最终代码

注意:对敏感信息已脱敏

# -*- coding: utf-8 -*-
'''
@Time : 2023/5/10 13:42
@Author : Vincent.xiaozai
@Email : Lvan826199@163.com
@File : demo06_整合请求伪造.py
'''
__author__ = "梦无矶小仔"

import json
import subprocess
import time
from datetime import datetime, timedelta
from pprint import pprint

import requests
from playwright.sync_api import Playwright,sync_playwright

# 全局变量
user_headers = {}
def my_request(request):
    all_headers_dict = request.all_headers()
    # 过滤请求
    if all_headers_dict.get(':path') == "/metrics:getCrashFreeTime..." and not user_headers:
        if all_headers_dict[":method"]=='POST' and all_headers_dict[":authority"]=='crashlytics-pa.clients6.google.com' :
            # 提取我需要的信息
            user_headers["cookie"] = all_headers_dict.get("cookie")
            user_headers["user-agent"] = all_headers_dict.get("user-agent")
            user_headers["authorization"] = all_headers_dict.get("authorization")
            user_headers["referer"] = all_headers_dict.get("referer")
            user_headers["origin"] = all_headers_dict.get("origin")

playwright = sync_playwright().start()
# 连接已打开浏览器,找好端口
browser = playwright.chromium.connect_over_cdp("http://127.0.0.1:9222")
default_context = browser.contexts[0] # 注意这里不是browser.new_page()了
page = default_context.pages[0]
page.on("requestfinished",my_request) # 创建拦截请求,获取请求的hearders
base_url = "https://console.firebase.google.com/u/0/project/..." #完整url已脱敏
page.goto(base_url) 
# 如果要保证刷新可以强制等待
page.wait_for_timeout(timeout=20000)

# 请求头伪造
headers = {
    "Host": "crashlytics-pa.clients6.google.com",
    "content-type": "application/json",
    'user-agent':user_headers["user-agent"],
    "referer": user_headers["referer"],
    'cookie':user_headers["cookie"],
    "origin": user_headers["origin"],
    'authorization': user_headers["authorization"]
}
print("---------------用户cookie及Authorization--------------------------")
print(f"伪造的请求头:{headers}")
print("---------------用户cookie及Authorization--------------------------")

## 执行request请求获取数据
crashAndUsersUrl = "https://crashlytics-pa.clients6.google.com/v1/projects" # 完整url已脱敏
crashAndUsersNum = get_all_crashAndUser(day=2,headers=headers,url=crashAndUsersUrl,the_latest="None",version_bt_list="None",platform='Android',eventType=["FATAL"])
print("----------接口信息打印-------------------")
print(crashAndUsersNum)

这里的get_all_crashAndUser就是我的业务代码,里面是对接口的请求进行了处理,这里就不放出来了。

可以看到最终我们拿到了这个接口的信息。

请添加图片描述

在之后的操作中,就可以一直使用requests进行接口请求了,如果cookie有使用有效期,那么每隔一段时间用playwright进行重新获取,重新伪造请求头就可以了。

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

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

相关文章

OpenCV实现提取水平线和垂直线,提取验证码

1.提取水平线和垂直线 在之前的博客中,我们介绍了很多形态学操作。其中,膨胀与腐蚀操作可以使用任意的结构元素,例如矩形、圆、直线等各种自定义形状。 提取水平线和垂直线的具体步骤见下: 1.1.步骤一:读入原始图像…

提速YOLOv7:用MobileNetV3更换骨干网络加速目标检测

目录 前言一、MobileNetV3的介绍1、MobileNetV3的原理和特点2、MobileNetV3的结构 二、YOLOv7的介绍1、YOLOv7的结构和流程2、YOLOv7的性能指标 三、MobileNetV3替换YOLOv7的骨干网络1、替换骨干网络2、修改neck部分3、微调模型 四、实验结果与分析1、数据集和实验设置2、实验结…

【Prompting】ChatGPT Prompt Engineering开发指南(3)

ChatGPT Prompt Engineering开发指南3 总结文字使用单词/句子/字符限制进行总结以运输和交付为重点进行总结以价格和价值为重点进行总结 尝试“extract”而不是“summarize”总结多个产品评论内容来源 本文承接上文:ChatGPT Prompt Engineering开发指南2&#xff0c…

RK3588平台开发系列讲解(进程篇)图解linux netlink

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、netlink协议簇二、netlink初始化沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 netlink 协议是一种进程间通信(Inter Process Communication,IPC)机制,为的用户空间和内核空间以及内核的某些部分之间…

解决FTD2000 麒麟系统下计算机属性中显示的内存比实际内存少

FTD2000 麒麟系统下计算机属性中显示的内存比实际内存少,首先确认问题点,判断是飞腾D2000的bios问题,还是麒麟系统问题 可以用如下方式做出判断 1、D2000 log打印进入shell 后 exit 在弹出来的界面中选 bios set 选项、进入bios 设置界面,如下图 可以看到 bios 下,Tota…

总结851

每周小结 英语背了3篇文章 高数一直刷关于一元积分的题目,一共150道左右,平均一天20道左右,强化课看到第2讲数列。 每日必复习(5分钟) 线性代数 向量组 学习内容: 暴力英语:继续背诵《The kin…

YOLOv5:解读yolo.py

YOLOv5:解读yolo.py 前言前提条件相关介绍yolo.pyparse_model()函数Detect类Model类 参考 前言 记录一下自己阅读yolo.py代码的一些重要点,方便自己查阅。特别感谢,在参考里,列举的博文链接,写得很好,对本人…

康耐视智能相机insight主从触发以及康耐视insight视觉系统之间数据特有交互方式

1、一个相机设置为主系统,指定自己的名称,下方可以指定发给从系统的数据,触发方式不要设置 成网络 2、另外一个相机触发方式设置成网络,然后下方指定主系统的名称 3、主系统每触发一次,就会带动从系统触发,同时指定的数据会发送到从系 统,从系统使用函数getstring获取…

【数据结构】图的创建和深度(DFS)广度(BFS)优先遍历

一、图 1.图的概念 图是由顶点的有穷非空集合和顶点之间边的集合组成,通过表示为G(V,E),其中,G标示一个图,V是图G中 顶点的集合,E是图G中 边的集合。 2.图的种类 图分为无向图和有向图 无向图:若顶点V…

用于OOD预测的稳定学习

当测试数据和训练数据共享相似的分布时,基于深度神经网络的方法取得了惊人的性能,但在其他情况下可能会失败。因此,消除训练和测试数据之间分布变化的影响对于构建有前景的深度模型至关重要。作者考虑了一个更具挑战性的情况。通过训练样本的…

大数据Doris(二十一):Bloom Filter索引以及Doris索引总结

文章目录 Bloom Filter索引以及Doris索引总结 一、Bloom Filter索引 1、BloomFilter索引原理 2、BloomFilter索引语法 3、注意事项 二、Doris索引总结 Bloom Filter索引以及Doris索引总结 一、Bloom Filter索引 1、BloomFilter索引原理 BloomFilter是由Bloom在1970年提…

移动机器人运动规划---基于图搜索的基础知识---广度优先遍历与深度优先遍历

移动机器人运动规划---基于图搜索的基础知识---广度优先遍历与深度优先遍历 广度优先搜索(BFS)深度优先搜索(DFS)BFS vs DFS 图搜索优化的方向就是: 按照什么规则去访问节点,按照什么规则弹出节点&#xff…

快速了解 TypeScript

目录 1、简介 2、安装TypeScript 3、编译代码 4、类型注解 5、接口 6、类 7、运行TypeScript Web应用 1、简介 TypeScript是JavaScript类型的超集,它可以编译成纯JavaScript。 TypeScript可以在任何浏览器、任何计算机和任何操作系统上运行,并且…

【哈士奇赠书活动 - 23期】-〖你好 ChatGPT〗

文章目录 ⭐️ 赠书 - 《你好 ChatGPT》⭐️ 内容简介⭐️ 作者简介⭐️ 精彩书评⭐️ 赠书活动 → 获奖名单 ⭐️ 赠书 - 《你好 ChatGPT》 ⭐️ 内容简介 人工智能(AI)时代已经来临,AIGC(人工智能生成内容)正在进一步…

【精选】各种节日祝福(C语言,可修改),Easyx图形库应用+源代码分享

博主:命运之光✨✨ 专栏:Easyx图形库应用📂 目录 ✨一、程序展示 范例一:❤新年祝福❤ 范例二:❤母亲节祝福❤ ✨二、项目环境 简单介绍一下easyx图形库应用 Easyx图形库 ✨三、运行效果展示(视频&am…

【C++起飞之路】初级——缺省参数、函数重载、引用

C:函数重载、引用 一、缺省参数🛫1.1 🚝什么是缺省参数1.2 🚝缺省参数的分类a. 全缺省参数b. 半缺省参数(部分缺省参数) 1.3 🚝注意事项 二、函数重载🛫2.1 🚝什么是函数…

时间复杂度:根号n一般来说大于log(n)

f ( x ) x − l o g 2 x f(x)\sqrt{x}-log_2 x f(x)x ​−log2​x 对这函数求导后,比较分母大小,可以得到结论 f ( x ) f(x) f(x)先减后增,分界点为 x 4 ( l n 2 ) 2 x \frac{4}{(ln2)^2} x(ln2)24​ f ( x ) f(x) f(x)的图像如下所示&a…

PPT技能之文字格式,转身的文字这样做

只要用PPT,一定需要设置文字格式。好的文字格式,给人惊艳的感觉,是一种愉悦的享受。 你的关注,是我最大的动力!你的转发,我的10W!茫茫人海有你的支持,给我无限动力。 1、字体。 按…

什么是Java中的阻塞队列?它有什么作用?

在Java中,阻塞队列是一种特殊的队列,它可以在队列为空或队列已满时阻塞添加或移除元素的操作。阻塞队列通常用于多线程编程中,可以帮助我们更加方便地进行线程通信和协作。在本文中,我将从面试的角度,详细讲解Java中的…

在线办公时代,如何选择合适的云办公软件?

文章目录 在线办公时代,如何选择合适的云办公软件?在线文档石墨文档腾讯文档飞书文档 远程控制ToDesk向日葵 会议协同腾讯会议ZOOM 总结 在线办公时代,如何选择合适的云办公软件? 随着数字经济的发展和疫情的影响,云办…