Playwright 的使用

Playwright 的特点

支持当前所有主流浏览器,包括 Chrome 和 Edge (基于 Chromiuns), Firefox , Safari

支持移动端页面测试,使用设备模拟技术,可以让我们在移动Web 浏览器中测试响应式的 Web 应用程序

支持所有浏览器的无头模式和非无头模式的测试

安装和配置过程简单,安装过程中会自动安装对应的浏览器和驱动,不需要额外配置 WebDriber

提供和自动等待相关的API , 在页面加载时会自动等待对应的节点加载,大大减小了API 编写的复杂的

安装

1. 首先确保 python 版本大于 3.7

pip install playwright

这时,playwright 会安装 Chromium , Firefox 和 WebKit 浏览器并配置一些驱动

基本使用

Playwright 支持两种模式,同步 和 异步 根据需要选择不同的模式

from playwright.sync_api import sync_playwrightwith sync_playwright() as p:for browser_type in [p.chromium, p.firefox, p.webkit]:browser = browser_type.launch(headless=False)page = browser.new_page()page.goto('https://www.baidu.com')page.screenshot(path=f'screenshot-{browser_type.name}.png')print(page.title())browser.close()

代码执行后会依次使用三种浏览器打开百度首页

这里我们首先导入并直接调用了 sync_playwright 方法, 该方法的返回值是一个 PlaywrightContextManger 对象,可以理解为一个浏览器上下文管理器,我们将其配置为 p 变量。然后依次调用 p 的 chromium, firefox 和 webkit 属性创建了 Chromium, Firefox 以及 webkit 浏览器实例。接着用一个 for 循环依次执行了这 3 个浏览器实例的 launch 方法, 同时设置了 headless 参数为 False

如果不把 headless 设置为 False ,就会默认以无头模式打开浏览器,我们将看不到任何窗口

在 for 循环中, launch 方法返回一个 Browser 对象, 我们将其赋值为 browser 变量。 然后调用 browseer 的 new_page 方法新建了一个选项卡, 返回值是一个 Page  对象, 将其赋值为 page , ,之后调用 page 的一系列API 完成了各种自动化操作,调用 goto 方法加载某个页面,这里我们访问的是百度首页, 调用 screenshot 方法获取页面截图, 往其里面传入的文件名称是截图自动保存后的图片名称, 这里的名称中我们加入了 browser_type 的 name 属性, 代表浏览器的类型,于是 3 次循环中 screenshot 方法的结果分别是 chromium , firefox , 和 webkit 另外,还调用了 title 方法,该方法会返回页面的标题, 即 HTML 源代码中 title 节点的文字, 也就是选项卡上的文字,并将返回的页面标题打印到控制台, 最后,调用 browser 的 close 方法关闭整个浏览器,代码结束

上面演示的是同步模式,Playwright 还支持异步模式

import asyncio
from playwright.async_api import async_playwrightasync def main():async with async_playwright() as p:for browser_type in [p.chromium, p.firefox, p.webkit]:browser = await browser_type.launch()page = await browser.new_page()await page.goto('https://www.baidu.com')await page.screenshot(path=f'screenshot-{browser_type.name}.png')print(await page.title())await browser.close()asyncio.run(main())

可以看到,写法和同步模式基本一样,只不过这里导入的是 async_playwright 方法, 不再是 sync_playwright 方法, 以及写法上添加了 async / await 关键字, 最后运行效果和同步模式一样

另外可以注意到, 这两个例子中使用了 with as 语句,with 用于管理上下文对象,可以返回一个上下文管理器,寄一个 PlaywrightContextManger 对象,无论代码运行期间是否抛出异常,该对象都能帮助我们自动分配并且释放 Playwright 的资源

这里并没有传入 headless 为 True 所以没有显示浏览器页面,也就是用的是无头模式

代码生成

Playwright 还有一个强大的功能,是可以录制我们在浏览器中的操作并自动生成代码,有了这个功能,我们甚至一行代码都不用写。这个功能可以通过 playwright 命令行调用 codegen 实现,先来看看 codegen 有什么参数

在终端输入命令如下;

playwright codegen --help

结果类似如果下:

Usage: playwright codegen [options] [url]

open page and generate code for user actions

Options:
  -o, --output <file name>             saves the generated script to a file
  --target <language>                  language to generate, one of javascript, playwright-test, python, python-async,
                                       python-pytest, csharp, csharp-mstest, csharp-nunit, java, java-junit (default:
                                       "python")
  --save-trace <filename>              record a trace for the session and save it to a file
  --test-id-attribute <attributeName>  use the specified attribute to generate data test ID selectors
  -b, --browser <browserType>          browser to use, one of cr, chromium, ff, firefox, wk, webkit (default:
                                       "chromium")
  --block-service-workers              block service workers
  --channel <channel>                  Chromium distribution channel, "chrome", "chrome-beta", "msedge-dev", etc
  --color-scheme <scheme>              emulate preferred color scheme, "light" or "dark"
  --device <deviceName>                emulate device, for example  "iPhone 11"
  --geolocation <coordinates>          specify geolocation coordinates, for example "37.819722,-122.478611"
  --ignore-https-errors                ignore https errors
  --load-storage <filename>            load context storage state from the file, previously saved with --save-storage
  --lang <language>                    specify language / locale, for example "en-GB"
  --proxy-server <proxy>               specify proxy server, for example "http://myproxy:3128" or
                                       "socks5://myproxy:8080"
  --proxy-bypass <bypass>              comma-separated domains to bypass proxy, for example
                                       ".com,chromium.org,.domain.com"
  --save-har <filename>                save HAR file with all network activity at the end
  --save-har-glob <glob pattern>       filter entries in the HAR by matching url against this glob pattern
  --save-storage <filename>            save context storage state at the end, for later use with --load-storage
  --timezone <time zone>               time zone to emulate, for example "Europe/Rome"
  --timeout <timeout>                  timeout for Playwright actions in milliseconds, no timeout by default
  --user-agent <ua string>             specify user agent string
  --viewport-size <size>               specify browser viewport size in pixels, for example "1280, 720"
  -h, --help                           display help for command

Examples:

  $ codegen
  $ codegen --target=python
  $ codegen -b webkit https://example.com
 

说明:

1. 这里是命令行,所以要在终端 (cmd) 输入

2. 这里输入命令是配置了环境变量的, 如果没有配置环境变量则需要加上全路径

例如我的在: 

C:\Users\86151\AppData\Roaming\Python\Python311\Scripts

里面有

主要是找到自己的 python 环境, 然后找到 Scripts 文件夹

可以看到结果中有几个选项, -o 代表输出的代码文件名称, -target 代表使用的语言, 默认是 python , 代表会生成同步模式的代码, 如果传入 pythhon-async 则会生成异步模式的代码, -b 代表使用的浏览器, 默认是 chromium  还有很多其他设置, 例如 -device 可以模拟使用手机浏览器(如 iPthon 11), -lang 代表设置浏览器的语言, -timeout 可以设置页面加载超时时间

playwright codegen -o script.py -b firefox

运行代码后会弹出一个 Firefox 浏览器, 同时右侧输出一个脚本框,实时显示当前操作对应的代码,我们可以在浏览器随意操作,例如打开百度,点击搜索框输入 nba, 在点击搜索按钮

这里看到随着我们的操作,右侧也生成了对应的代码,操作完成之后,关闭浏览器,playwright 会生成一 script.py 的文件, 前面我们自定义的,这个文件的位置,取决于你执行命令时的位置

这个文件我们也是可以执行的,执行之后,它会重复我们刚刚的操作。这里哦们可以发现,自动生成的代码和我们写的是有些区别的,例如:这里的 new_page 方法并不是直接通过 browser 调用的,而是通过 context ,这个 context 又是由 browser 调用 new_context 方法生成的,这个context 变量其实是一个 BrowserContext 对象, 这是一个类似隐身模式的独立上下文环境, 其运行资源是单独隔离的, 在一些自动化测试过程中, 我们可以为每个测试用例单独创建一个 BrowserContext 对象, 这样能够保证各个测试用例互不干扰,就提API参考:

https://playwright.dev/python/docs/api/class-browsercontext

支持移动端浏览器

模拟移动端浏览器

from playwright.sync_api import sync_playwrightwith sync_playwright() as p:iphone_12_pro_max = p.devices['iPhone 12 Pro Max']browser = p.webkit.launch(headless=False)context = browser.new_context(**iphone_12_pro_max, locale='zh-CN')page = context.new_page()page.goto('https://www.whatismybrowser.com/')page.wait_for_load_state(state='networkidle')page.screenshot(path='browser-iphone.png')browser.close()

这里我们先用 PlaywrightContextManger 对象的 devices 属性指定了一台移动设备,传入的参数是移动设备的型号, 例如 iPhone 12 Pro Max ,当然也可以传入其他内容,例如 iPhone 8 ....

前面我们已经了解了 BrowserContext 对象, 它可以用来模拟移动端浏览器, 初始化一些移动设备的信息,语言,权限,位置等内容, 这里我们就创建了一个移动端 BrowserContext 对象, 最后把返回的 BrowserContext 对象赋值给了 context 变量

接着我们调用 context 的 new_page 方法创建了一个新的选项卡, 然后跳转到一个用于获取浏览器信息的网站, 调用 wait_for_load_state 方法等待页面的某个状态完成, 这里我们传入的 state 是 networkidle , 也就是网络空闲状态, 因为在页面初始化和数据加载过程中,肯定有网络请求伴随产生,所以加载过程肯定不算 networkle 状态,意味着这里传入 networkidle 可以标识当前页面初始化和数据加载完成的状态, 加载完成之后, 我们调用 screenshot 方法获取了当前页面的截图,最后关闭了浏览器

选择器

文本选择器

文本选择器支持用 text= 这样的语法进行筛选

page.click('text-log in ')

这里代表选择并点击文本的内容是 Log in  的节点

CSS 选择器

例如根据 id 或 class 筛选

page.click("button")

page.click("#nav-bar  .contact-us-item")

根据节点属性筛选

page.click("[data-test=login=button]")

page.click("[aria-label=Sign in ]")

CSS 选择器 + 文本值

可以结合CSS 选择器结合文本值的方式进行筛选,比较常见的方法是 has-text 和 text ,前者代表节点中包含指定的字符串, 后者代表节点中的文本值和指定的字符串完全匹配

page.click("article:has-text('Playwright')")

page.click("#nav-bar : text(' Contact us')")

第一行代码就是选择选择文本值中包含 Playwrght 字符串的 article 节点, 第二行代码是选择 id 为 nav-bar 的节点中文本值为 Contact us 的节点

CSS 选择器 +节点关系

CSS 选择器还可以结合节点关系来筛选节点,例如使用 has 指定另外一个选择器,

page.click(".item-description:has(.item-promo-banner)")

这里选择的就是class 为 item-description 的节点, 且该节点还要包含 class 为 item-promo-banner 的子节点

另外还可以结合一些相对位置关系,例如使用 right-of 指定位于某个节点右侧的节点

page.click("input:right:right-of(:text('Username'))")

这里选择的就是一个 imput 节点, 并且该节点要求位于文本值为 Username 的节点的右侧

XPath

当然 XPath 也是支持的, 不过 xpath 这个关键字需要我们自行指定

page.click("xpath=//button")

这里开头指定 xpath= 字符串 , 代表这个字符串是一个 XPath 表达式

更多关于选择器的用法和实践可以关注官网: 

https://playwright.dev/python/docs/api/class-page

常用操作方法

例如: click(点击), fill(输入)等

文档地址:

https://playwright.dev/python/docs/api/class-page

事件监听

page 对象提供一个 on 方法, 用来监听页面中发生的各个事件, 例如 close, console, load, request, response 等

这里我们监听 response 事件 , 在每次网络请求得到响应的时候会出发这个事件,我们可以设置回调方法来获取响应中的全部信息

from playwright.sync_api import sync_playwrightdef on_response(response):print(f"Statue {response.status}: {response.url}")with sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()page.on('response', on_response)page.goto('https://spa6.scrape.center/')page.wait_for_load_state('networkidle')browser.close()

Statue 200: https://spa6.scrape.center/
Statue 200: https://spa6.scrape.center/js/chunk-19c920f8.c3a1129d.js
Statue 200: https://spa6.scrape.center/css/chunk-19c920f8.2a6496e0.css
Statue 200: https://spa6.scrape.center/css/chunk-2f73b8f3.5b462e16.css
Statue 200: https://spa6.scrape.center/js/chunk-vendors.77daf991.js
Statue 200: https://spa6.scrape.center/css/app.ea9d802a.css
Statue 200: https://spa6.scrape.center/js/chunk-4dec7ef0.e4c2b130.js
Statue 200: https://spa6.scrape.center/js/app.5ef0d454.js
Statue 200: https://spa6.scrape.center/js/chunk-2f73b8f3.8f2fc3cd.js

这里省略了一部分输出内容

我们在创建 page 对象后, 就开始监听 response 事件, 同时将回调函数方法设置为 on_response

on_response 接收一个参数,然后输出响应中的状态码和链接

可以发现输出结果其实正好对应浏览器 Network 面板中的所有请求和响应

这个网站真实的数据都是 Ajax 加载的, 同时 Ajax 请求中还带有加密参数, 不好轻易获取, 但有了 on_response 方法, 如果我们想截获 Ajax 请求,岂不是很容易

改写一下这里的判定条件, 输出对应的 JSON 结果

from playwright.sync_api import sync_playwright# 通过事件监听来获取 Ajax 加密的JSON 内容
def on_response(response):if '/api/movie/' in response.url and response.status ==200:print(response.json())with sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()page.on('response', on_response)page.goto('https://spa6.scrape.center/')page.wait_for_load_state('networkidle')

{'count': 103, 'results': [{'id': 1, 'name': '霸王别姬', 'alias': 'Farewell My Concubine', 'cover': 'https://p0.meituan.net/movie/ce4da3e03e655b5b88ed31b5cd7896cf62472.jpg@464w_644h_1e_1c', 'categories': ['剧情', '爱情'], 'published_at': '1993-07-26', 'minute': 171, 'score': 9.5, 'regions': ['中国内地', '中国香港']}, {'id': 2, 'name': '这个杀手不太冷', 'alias': 'Léon', 'cover':  'https://p0.meituan.net/movie/27b76fe6cf3903f3d74963f70786001e1438406.jpg@464w_644h_1e_1c', 'categories': ['动画', '歌舞', '冒险'], 'published_at': '1995-07-15', 'minute': 89, 'score': 9.0, 'regions': ['美国']}]}
 

这里省略了部分内容

可以看出来,相对来说简单了很多

获取页面源代码

获取页面源代码其实很简单,直接调用 Page 对象的 content 方法即可

from playwright.sync_api import sync_playwrightwith sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()page.goto('https://spa6.scrape.center/')page.wait_for_load_state('networkidle')html = page.content()print(html)browser.close()

运行之后就是网页源代码了, 借助工具就可以分析提取想要的信息了

页面点击

页面点击前面用过了, 就是 click 方法

page.click(selector, **kwargs)

可以看到必须传入的参数是 selector , 其他参数都是可选的。 selector 代表选择器,用来匹配想要点击的节点,如果有多个节点和传入的选择器匹配, 那么只使用第一个节点

其他一些比较重要的参数如下

click_count :点击次数,默认为1

timeout: 等待找到要点击得劲节点的超时时间(单位为秒),默认是 30

psition: 需要传入一个字典,带有 x 属性和 y 属性, 代表点击位置相对节点左上角的偏移量

force : 即使按钮设置了不可点击, 也要强制点击, 默认为 False 

click 内部执行逻辑如下

找到与 selector 匹配到的节点, 如果没有找到,就一直等待直到超时,超时时间由 timeout 参数设置

检查匹配到的节点是否存在可操作性,等待检查结果,如果某个按钮设置了不可点击,就等该按钮变成可点击的时候再去点击,除非通过 force 参数设置跳过了可操作性检查步骤,才会强制点击

如果需要,就滚动一下页面,使需要点击的节点呈现出来

调用 Page 对选哪个的 mouse 方法, 点击节点的中心位置,如果指定了 positon 参数, 就点击参数指定的位置

具体参数设置可以参考官方文档:

Page | Playwright

文本输入

文本输入对应的方法是 fill 其API 定义如下

page.fill(selector, value, **kwargs)

这个方法传入两个必要参数,第一个也是 selector ,依然代表选择器,第二个是 value,代表输入的文本内容,还可以通过 timeout 查找对应节点的最长等待时间

获取节点属性

除了操作本身,我们还可以获取节点的属性,方法是 get_attribute 其 API 定义如下

page.get_attribute(selector, name , **kwargs)

这个方法接收两个参数,第一个是 selector , 代表选择器。第二个是 name ,代表要获取的属性名称,还可以通过 timeout 查找对应节点的最长等待时间

from playwright.sync_api import sync_playwrightwith sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()page.goto('https://spa6.scrape.center/')page.wait_for_load_state('networkidle')href = page.get_attribute('a.name', 'href')print(href)browser.close()

/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx

可以看到获取的对应节点的 href 属性,但只有一条结果, 这是因为如果传入的选择器匹配到了多条件结果,就只会用第一个

获取多个节点

使用 query_selector_all 方法可以获取所有节点,它会返回节点列表,通过遍历得到其中的单个节点后,可以接着调用上面介绍的针对单个节点的方法完成一些操作和获取属性

from playwright.sync_api import sync_playwrightwith sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()page.goto('https://spa6.scrape.center/')page.wait_for_load_state('networkidle')elements = page.query_selector_all('a.name')for element in elements:print(element.get_attribute('href'))print(element.text_content())browser.close()

/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx
霸王别姬 - Farewell My Concubine
/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIy
这个杀手不太冷 - Léon

省略部分输出内容

这里我们通过 query_selector_all 方法获取了所有匹配到的节点, 每个节点各对应一个 ElementHandle 对象, 可以调用 ElementHandle 对象的 get_attribute 方法获取节点属性, 也可以通过 text_content 方法获取节点文本

获取单个节点

获取单个节点的特定方法 query_selector, 如果匹配到了多个节点,那么它只返回第一个

from playwright.sync_api import sync_playwrightwith sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()page.goto('https://spa6.scrape.center/')page.wait_for_load_state('networkidle')element = page.query_selector('a.name')print(element.get_attribute('href'))print(element.text_content())browser.close()

/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx
霸王别姬 - Farewell My Concubine

可以看到只输出了第一个节点的信息

网络劫持

在介绍一个方法 route 利用这个方法可以实现网络劫持和修改操作。如修改 request 的属性,修改响应结果等

from playwright.sync_api import sync_playwright
import re
import time# 设置图片不加载,劫持请求数据
with sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()def cancel_request(route, request):route.abort()page.route(re.compile(r"(\.png)|(\.jpg)"), cancel_request)page.goto("https://spa6.scrape.center/")page.wait_for_load_state('networkidle')page.screenshot(path='no_picture.png')time.sleep(3)browser.close()

这里我们调用了 route 方法, 第一个参数通过正则表达式传入了 URL 路径,这里的 (\.png) |(\.jpg)代表所有包含 .png 或 .jpg 的链接,遇到这样的请求,会回调 cancel_request 方法做处理。 cancel_request  方法接收两个参数,一个是 route 代表一个 CallableRoute 对象, 另一个是 request , 代表 Request 对象, 这里我们直接调用 CallableRoute 对象的 abort 方法,取消了这次请求,最终导致所有的图片都取消加载

这里解释这么做的一个作用: 图片资源都是二进制文件, 我们在爬取的过程中可能并不想关心具体的二进制内容,而只关心图片的 URL 是什么,所以浏览器是否把图片加载出来就不重要了,如此设置可以提高整个页面的加载速度,提高爬取效率

另外利用这个功能还可以对一些响应内容进行修改, 例如直接将响应结果修改为自定的文本

这里首先顶一个 HTML 文本文件, 命名为 custom__response.html

<!DOCTYPE html>
<html><head><title>Hack Response</title></head><body><h1>Hack Response</h1></body>
</html>

代码如下

from playwright.sync_api import sync_playwright
import time# 改变响应数据
with sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()def modify_response(route, request):route.fulfill(path='./custom_response.html')page.route('/', modify_response)page.goto('https://spa6.scrape.center/')time.sleep(3)browser.close()

这里按照教程所说应该是要展示出 上面自己编写的 HTML 内容,但是实际效果并没有。

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

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

相关文章

x264编解码库 -介绍和使用示例

目录 1&#xff1a;X264简单介绍 1.1&#xff1a;编译x264 1.2&#xff1a;x264简单介绍 1.3&#xff1a;x264的优势 1.4&#xff1a;x264与FFmpeg的关系 1.5&#xff1a;x264 编解码原理 1.6 进一步学习资源 2&#xff1a;demo效果 3&#xff1a;完整代码 4&#xff1a;附件…

6 网络

6 网络 1、概念2 IP地址3、套接字4、TCP协议4.1 TCP协议的基本特征4.2 建立连接4.4 终止连接4.5 编程模型 5、UDP协议5.1 UDP协议的基本特性5.2 常用函数5.3 UDP通信模型 6、域名解析 1、概念 计算机网络是实现资源共享和信息传递的计算机系统 ISO/OSI网络协议模型 TCP/IP协…

C语言进阶 10. 字符串

C语言进阶 10. 字符串 文章目录 C语言进阶 10. 字符串10.1. 字符串10.2. 字符串变量10.3. 字符串输入输出10.4. 字符串数组10.5. 单字符输入输出10.6. 字符串函数strlen()10.7. 字符串函数strc()10.8. 字符串函数strcpy()10.9. 字符串搜索函数10.10. PAT10-0. 说反话 (20)10-1.…

idea中导入外部依赖并打包到jar包中

前言&#xff1a; 很多时候在我们写项目对接三方的时候都需要导入三方jar包&#xff0c;而这时候我们用平常的pom里面写依赖发现导入不了&#xff08;直接把jar包放在本地导入的话打包的话也不会将该依赖打包进我们项目的jar包&#xff09;&#xff0c;我在网上找了几种方法 …

Linux网络-ss命令

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注我&#xff0c;我尽量把自己会的都分享给大家&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux服务器作为一个常用的网络服务器&#xff0c;主要的作用就是向客户端提供网络…

【C++】C++11中R字符串的作用

在 C11 中添加了定义原始字符串的字面量 1.定义和基本使用 定义方式为&#xff1a; R"xxx(原始字符串)xxx"其中 () 两边的字符串可以省略&#xff0c;R只会处理括号中的字符串。 原始字面量 R 可以直接表示字符串的实际含义&#xff0c;而不需要额外对字符串做转义…

谷歌团队新技术Alchemist:使用扩散模型对材料属性进行参数控制

Alchemist是由谷歌团队和麻省理工学院联合研发的一项创新技术&#xff0c;它利用扩散模型对材料属性进行精细的参数控制。这项技术的核心在于能够对真实图像中的物体材料属性进行调整&#xff0c;包括粗糙度、金属感、反照率和透明度等。Alchemist的实现依赖于先进的文本到图像…

【时时三省】(C语言基础)循环语句while(2)

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ——csdn时时三省 getchar和scanf的作用 示例: int main ( ) &#xff5b; char password[20] ( 0 ) ; printf ( "请输入密码&#xff1a;> " )&#xff1b; scanf ( " &#xff05;s…

Sping项目只能勾选17和21 (已解决) 导致的后续Invalid bound statement (not found):

问题发现 今天创建项目的时候发现 idea初始化spring的时候选择不了Java8 解决方案:替换URL为 https://start.aliyun.com/ 将IDEA页面创建Spring项目&#xff0c;其实是访问spring initializr去创建项目。故我们可以通过阿里云国服去间接创建Spring项目。 将https://start.spr…

使用 VMware vCenter Server(vSphere Client)迁移 ESXi 虚拟机

我需要将虚拟机 k8s-dev-node4从 ESXi 主机 192.168.1.161 迁移到 ESXi 主机 192.168.1.162 上&#xff0c;使用 VMware vCenter Server&#xff08;vSphere Client&#xff09;在浏览器上可视化操作&#xff0c;将这个需求变的非常简单。 1、选中需要迁移的虚拟机&#xff0c…

【AI落地应用实战】Amazon Bedrock +Amazon Step Functions实现链式提示(Prompt Chaining)

一、链式提示 Prompt Chaining架构 Prompt Chaining 是一种在生成式人工智能&#xff08;如大型语言模型&#xff09;中广泛使用的技术&#xff0c;它允许用户通过一系列精心设计的提示&#xff08;Prompts&#xff09;来引导模型生成更加精确、丰富且符合特定需求的内容。 P…

获取手机当前信号强度(dbm/asu值)解决 getGsmSignalStrength()总是返回99问题

能看到这篇文章说明网上哪些获取 &#xff08;dbm/asu值&#xff09;不适合你&#xff0c;不是他们的代码不正确&#xff0c;而是不符合你的情况 比如安卓6获取android手机信号强度 可以看这篇文章 https://blog.csdn.net/sinat_31057219/article/details/81134030 当然如果你…

Javaweb项目|springboot医院管理系统

收藏点赞不迷路 关注作者有好处 文末获取源码 一、系统展示 二、万字文档展示 基于springboot医院管理系统 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringSpringMVCMyBatisVue 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 编号&#xff1a;…

Source insight 配置代码格式化

代码格式化工具&#xff1a;Artistic Style Files Download 配置 Source Insight 添加 Astyle 命令 Tools --> Custom Commands -->Add 在 Run 栏填入格式化命令&#xff1a; "D:\Program Files\astyle-3.5.2-x64\astyle.exe" -A3 -t -xV -w -Y -m0 -p -H …

【Vulnhub系列】Vulnhub_Raven2靶场渗透(原创)

【Vulnhub系列靶场】Vulnhub_Raven2 渗透 原文转载已经过授权 原文链接&#xff1a;Lusen的小窝 - 学无止尽&#xff0c;不进则退 (lusensec.github.io) 一、环境准备 从网盘下载该靶机&#xff0c;在vm中选择【打开】 然后设置好存储路径&#xff0c;开机后检查靶机的网络连…

Redis缓存数据库进阶——Redis缓存数据同步问题(8)

Redis缓存使用问题 数据一致性 只要使用到缓存&#xff0c;无论是本地内存做缓存还是使用 redis 做缓存&#xff0c;那么就会存在数据同步的问题。 我以 Tomcat 向 MySQL 中写入和删改数据为例&#xff0c;来给你解释一下&#xff0c;数据的增删改操作具体是如何进行的。 我…

从入门到精通:电商设计师的职业发展指南

在当今数字时代&#xff0c;电商设计师的作用越来越重要。从电子商务网站的整体造型设计到产品页面的具体布局&#xff0c;他们的工作范围是电子商务企业成功的关键因素之一。然而&#xff0c;并不是每个人都对这个职业有深刻的理解。因此&#xff0c;在本文中&#xff0c;我们…

【Git-驯化】一文学会git中对代码进行存储操作:git stash技巧

【Git-驯化】一文学会git中对代码进行存储操作&#xff1a;git stash技巧 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 免费获取相关内…

【无标题】DNS域名解析

回顾指令&#xff1a; samba机器&#xff1a; 安装samba Yum -y install samba 自建库&#xff0c;只下载不安装 Yum -y install --downloadonly --downloaddir./soft/ 配置samba Vim /etc/samba/smb.conf [smb_share] comment smb share service path /share/ guest…

python爬虫的基础知识

1.学习爬虫的好处 提升编程技能&#xff1a;爬虫开发需要掌握编程基础&#xff0c;特别是网络请求、HTML/CSS/JavaScript解析、数据存储和异常处理等技能。通过学习爬虫&#xff0c;你可以巩固和提升你的编程技能&#xff0c;特别是Python等编程语言的应用能力。 数据驱动决策…