|
安装全局工具:- # 安装全局工具
- dotnet tool install --global Microsoft.Playwright.CLI
- # 创建项目
- dotnet new console -n Console1
- cd Console1
- # 安装依赖
- dotnet add package Microsoft.Playwright
- # 用Playwright 工具安装所需的浏览器 C:\Users\Administrator\AppData\Local\ms-playwright
- playwright install
- # 运行项目
- dotnet run
复制代码 在新的环境中部署:- # 安装全局工具
- dotnet tool install --global Microsoft.Playwright.CLI
- # 用Playwright 工具安装浏览器(要在项目部署的目录)
- dotnet Microsoft.Playwright.dll -- install
复制代码 基本使用:- using var playwright = await Playwright.CreateAsync();
- await using var browser = await playwright.Chromium.LaunchAsync();
- var page = await browser.NewPageAsync();
- await page.GotoAsync("https://www.baidu.com");
- var title = await page.InnerTextAsync("title");
复制代码 Playwright Trace Viewer工具来追踪测试执行:- using var playwright = await Playwright.CreateAsync();
- await using var browser = await playwright.Chromium.LaunchAsync(new() { Headless = true });
- var context = await browser.NewContextAsync();
- #region 开始追踪记录
- await context.Tracing.StartAsync(new()
- {
- Title = $"qwe123",
- Screenshots = true,
- Snapshots = true,
- Sources = true
- });
- #endregion
- var page = await context.NewPageAsync();//await browser.NewPageAsync();
- await page.GotoAsync("https://www.baidu.com");
- //将上面链接打开后的page页面截图 保存成 screenshot.png
- await page.ScreenshotAsync(new PageScreenshotOptions { Path = Path.Combine(
- Environment.CurrentDirectory,
- "screenshot",
- $"{DateTime.Now.ToString("yyyyMMddHHmmss")}.png"
- ) });
- var title = await page.InnerTextAsync("title");
- #region 结束追踪记录
- await context.Tracing.StopAsync(new()
- {
- Path = Path.Combine(
- Environment.CurrentDirectory,
- "playwright-traces",
- $"{DateTime.Now.ToString("yyyyMMddHHmmss")}.zip"
- )
- });
- #endregion
复制代码 Playwright Trace Viewer工具记录多个追踪(trace chunk):- using var playwright = await Playwright.CreateAsync();
- await using var browser = await playwright.Chromium.LaunchAsync(new() { Headless = true });
- var context = await browser.NewContextAsync();
- #region 开始追踪记录
- await context.Tracing.StartAsync(new()
- {
- Title = $"qwe123",
- Screenshots = true,
- Snapshots = true,
- Sources = true
- });
- #endregion
- #region 开始追踪记录
- await context.Tracing.StartChunkAsync(new()
- {
- Title = $"qwe123"
- });
- #endregion
- var page = await context.NewPageAsync();//await browser.NewPageAsync();
- await page.GotoAsync("https://www.baidu.com");
- //将上面链接打开后的page页面截图 保存成 screenshot.png
- await page.ScreenshotAsync(new PageScreenshotOptions { Path = Path.Combine(
- Environment.CurrentDirectory,
- "screenshot",
- $"{DateTime.Now.ToString("yyyyMMddHHmmss")}.png"
- ) });
- var title = await page.InnerTextAsync("title");
- #region 结束追踪记录
- await context.Tracing.StopChunkAsync(new()
- {
- Path = Path.Combine(
- Environment.CurrentDirectory,
- "playwright-traces",
- $"{DateTime.Now.ToString("yyyyMMddHHmmss")}1.zip"
- )
- });
- #endregion
- #region 开始追踪记录
- await context.Tracing.StartChunkAsync(new()
- {
- Title = $"qwe1234"
- });
- #endregion
- await page.GotoAsync("https://www.baidu.com/");
- // 等待页面加载完成
- await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
- await page.GetByRole(AriaRole.Link, new() { Name = "登录" }).ClickAsync();
- await page.GetByPlaceholder("手机号/用户名/邮箱").ClickAsync();
- await page.GetByPlaceholder("手机号/用户名/邮箱").FillAsync("123456");
- await page.GetByPlaceholder("密码").ClickAsync();
- await page.GetByPlaceholder("密码").FillAsync("qwe123");
- await page.GetByRole(AriaRole.Checkbox, new() { Name = "阅读并接受" }).CheckAsync();
- await page.GetByRole(AriaRole.Button, new() { Name = "登录" }).ClickAsync();
- #region 结束追踪记录
- await context.Tracing.StopChunkAsync(new()
- {
- Path = Path.Combine(
- Environment.CurrentDirectory,
- "playwright-traces",
- $"{DateTime.Now.ToString("yyyyMMddHHmmss")}2.zip"
- )
- });
- #endregion
复制代码
本地打开跟踪文件:- playwright show-trace 12344.zip
复制代码
开启Playwright录制操作自动生成代码脚本:
Playwright发布与部署:
部署模式选择“独立”,可以不依赖框架运行
另一台机器上运行我们的程序之前,需要在这台机器上重新安装 Playwright,但无需安装 dotnet 框架或运行时。
运行发布文件夹下的安装命令:- .playwright\node\win32_x64\playwright.cmd install
复制代码 常用操作:- // 创建Chromium浏览器实例
- await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions()
- {
- Headless = false, // 关闭无头模式(有界面)
- SlowMo = 50, // 放慢执行速度
- Channel = "chrome", // 指定采用chrome浏览器类型
- Devtools = true, // 启用开发者工具
- ChromiumSandbox = false, // 关闭浏览器沙盒
- ExecutablePath = string.Empty, // 不指定浏览器可执行文件位置,会自动寻找 ms-playwright 下载的浏览器
- Args = new[] { "--enable-automation=true", "--disable-blink-features=AutomationControlled" }, // 防止selenium被检测
- });
- // 浏览器上下文
- await using var context = await browser.NewContextAsync(new BrowserNewContextOptions
- {
- ViewportSize = new ViewportSize
- {
- Width = 1536, // 1920 * 0.8
- Height = 864, // 1080 * 0.8
- }, // 窗口大小
- Locale = "zh-CN", // 指定语言(区域)
- TimezoneId = "Asia/Shanghai", // 指定时区
- });
- // 存储当前会话
- await context.StorageStateAsync(new BrowserContextStorageStateOptions
- {
- Path = "state.json"
- });
- // 使用会话,当state.json文件不存在时会报错
- await browser.NewContextAsync(new BrowserNewContextOptions
- {
- StorageStatePath = "state.json"
- });
- // 等待登录按钮出现
- await page.WaitForSelectorAsync(".login");
- // 点击登录
- await page.ClickAsync(".login");
- // 查找页面元素 可匹配到 美食
- var locator = page.Locator(“div[class^='title-text-']:text-is('美食')”);
- // 获取匹配到元素的个数
- var count = await locator.CountAsync();
- // 鼠标悬停在元素上
- await page.HoverAsync("#title");
- // 执行js获取页面地址
- var href = await page.EvaluateAsync<string>("document.location.href");
- // 定位器
- var element = page.Locator(".passMod_dialog-close-btn");
- // 等待1秒
- await Task.Delay(1000);
- await element.ClickAsync();
- // 显式等待 设定的超时时间内,仍然没有通过定位器等待到目标元素,将会抛出异常
- await page.GotoAsync("https://stackoverflow.com/");
- var elelment = page.Locator("id=noscript-warning");
- await elelment.WaitForAsync();
- var text = await elelment.InnerTextAsync(new LocatorInnerTextOptions { Timeout = 10 });
- // RunAndWaitForPopupAsync 方法可以帮助我们执行操作并等待弹出窗口出现
- await page.GotoAsync("https://www.baidu.com/");
- await page.RunAndWaitForPopupAsync(async () =>
- {
- await page.ClickAsync("text=新闻");
- },
- new PageRunAndWaitForPopupOptions
- {
- Predicate = (page) =>
- {
- return page.Url.Contains("news.baidu.com");
- }
- });
- // RunAndWaitForRequestAsync/RunAndWaitForResponseAsync两个方法可以通过传入URL地址或表达式来过滤等待的请求或响应,从而实现更加精细的控制。方法都是阻塞式的。也就是说,如果我们等待的情况一直未出现,后续的代码将不会执行。<br>// 在某些情况下,我们只需要在情况出现时进行一些操作,即使情况不出现也不应该影响整体的运行。这时,我们可以使用监听事件来实现。
- await page.RunAndWaitForRequestAsync(async () => {
- await page.GotoAsync("https://stackoverflow.com/",
- new PageGotoOptions{ WaitUntil = WaitUntilState.Commit});
- },
- request => {
- Console.WriteLine(request.Url);
- //return request.Url.Contains("jquery.min.js");
- return request.Url.Contains("stacks.min.js");
- });
- await page.RunAndWaitForResponseAsync(async () => {
- await page.ClickAsync("text='Login'"); },
- response => response.Url.Contains("users/login")
- );
- // 当页面发起的请求失败时触发
- page.RequestFailed += (sender, request) => {
- Console.WriteLine($"请求{request.Url}发生错误{request.Failure}");
- };
- // 当页面发起的请求完成时触发
- page.RequestFinished += (sender, request) => {
- Console.WriteLine($"请求{request.Url}发生错111111误{request.Failure}");
- };
- await page.GotoAsync("https://baidu.com/");
- // Close:当页面关闭时触发
- // Console:当控制台输出时触发
- // Crash:当页面崩溃时触发。例如,试图分配太多内存,浏览器页面可能会崩溃。
- // Dialog:当 JavaScript 对话框出现时触发。例如,alert、prompt、confirm等。
- // DOMContentLoaded:当页面的 DOMContentLoaded 事件触发时触发
- // Download:当下载开始时触发
- // FileChooser:当文件选择对话框出现时触发
- // FrameAttached:当 frame 连接到页面时触发
- // FrameDetached:当 frame 与页面分离时触发
- // FrameNavigated:当 frame 导航到一个新的 url 时触发
- // Load: 当页面的 load 事件触发时触发
- // PageError:当页面内发生未捕获异常时触发
- // Popup:当页面弹出新的窗口时触发
- // Request:当页面发起一个新的请求时触发
- // RequestFailed:当页面发起的请求失败时触发
- // RequestFinished:当页面发起的请求完成时触发
- // Response:当页面收到一个新的响应时触发
- // 输入搜索关键字
- await page.TypeAsync("input[name='q1']", "关键字");
- // 点击page按钮跳转到page1
- var page1 = await page.RunAndWaitForPopupAsync(async () =>
- {
- // 点击搜索
- await page.ClickAsync(".advanced-search-btn");
- });
- // 检查文本框内容
- var handleInput = await page1.WaitForSelectorAsync("#kw");
- var text = await handleInput.GetAttributeAsync("value");
- // 输入操作
- await page.Locator("#kw").FillAsync("1212121");
- // 点击操作
- await page.Locator("#kw").ClickAsync();
- // 单选(选中,已选中状态下无效)
- await page.Locator(".check1").SetCheckedAsync(true);
- await page.Locator(".Volvo").CheckAsync();
- // 复选框(选中,已选中状态下无效)
- await page.Locator("#checkbox [type='checkbox']:nth-child(7)").CheckAsync();
- await page.Locator("#checkbox [type='checkbox']:nth-child(7)").SetCheckedAsync(true);
- // 下拉框操作
- // 选择下拉框中的选项
- await page.SelectOptionAsync("select[name='country']", "Canada");
- // 通过value值选择
- await page.Locator("[name='select']").SelectOptionAsync("opel");
- // 通过可见文本选择
- await page.Locator("[name='select']").SelectOptionAsync(new SelectOptionValue { Label = "blue" });
- // 多个选定项目
- await page.GetByLabel("Choose multiple colors").SelectOptionAsync(new[] { "blue", "green", "red" });
- // 常规单击
- await page.Locator("#mouse2").ClickAsync();
- // 单击
- await page.GetByRole(AriaRole.Button).ClickAsync();
- // 双击
- await page.GetByText("Item").DblClickAsync();
- // 右击
- await page.GetByText("Item").ClickAsync(new() { Button = MouseButton.Right });
- // Shift + click
- await page.GetByText("Item").ClickAsync(new() { Modifiers = new[] { KeyboardModifier.Shift } });
- // Ctrl + click or Windows and Linux
- // Meta + click on macOS
- await page.GetByText("Item").ClickAsync(new() { Modifiers = new[] { KeyboardModifier.ControlOrMeta } });
- // Hover over element
- await page.GetByText("Item").HoverAsync();
- // Click the top left corner
- await page.GetByText("Item").ClickAsync(new() { Position = new Position { X = 0, Y = 0 } });
- //上传一个文件
- await page.Locator("#load").SetInputFilesAsync("demo.md");
- // 上传多个文件
- await page.Locator("#load").SetInputFilesAsync(new[] { "file1.txt", "file12.txt" });
- // 上传文件 找到文件上传输入框
- var fileInput = await page.QuerySelectorAsync("input[type='file']");
- string filePath = "path/to/your/file.txt"; // 你要上传的文件路径
- await fileInput.SetInputFilesAsync(filePath);
- // 提取页面标题
- string title = await page.TitleAsync();
- title = await page.InnerTextAsync("title");
- Console.WriteLine("Page title: " + title);
- // 提取页面 URL
- string url = page.Url;
- Console.WriteLine("Page URL: " + url);
- // 提取特定元素的文本内容
- var elementText = await page.EvaluateAsync<string>("document.querySelector('h1').textContent");
- Console.WriteLine("Header text: " + elementText);
- // 提取页面中的链接
- var links = await page.QuerySelectorAllAsync("a");
- foreach (var link in links)
- {
- var href = await link.GetAttributeAsync("href");
- Console.WriteLine("Link: " + href);
- }
- // 等待表格加载完毕
- await page.WaitForSelectorAsync("table");
- // 获取表格内容
- var tableHtml = await page.InnerHTMLAsync("table");
- // 使用正则表达式提取表格数据
- var regex = new Regex(@"<tr>(.*?)</tr>");
- var matches = regex.Matches(tableHtml);
- foreach (Match match in matches)
- {
- // 这里可以根据表格结构和需要自行解析数据
- var rowHtml = match.Groups[1].Value;
- Console.WriteLine("Row HTML: " + rowHtml);
- }
- // 等待页面加载完成
- await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
- // 等待页面跳转
- await page.WaitForNavigationAsync();
- // RunAndWaitForFileChooserAsync 方法可以帮助我们在执行操作的同时等待文件选择器的出现。
- await page.GotoAsync("https://image.baidu.com/");
- await page.RunAndWaitForFileChooserAsync(async () =>
- {
- await page.ClickAsync("id=sttb");
- await page.ClickAsync("id=uploadImg");
- }, new PageRunAndWaitForFileChooserOptions
- {
- Predicate = (fileChooser) =>
- {
- return !fileChooser.IsMultiple;
- }
- });
- // RunAndWaitForNavigationAsync 方法可以帮助我们执行操作并等待页面导航完成
- await page.GotoAsync("https://stackoverflow.com/");
- await page.RunAndWaitForNavigationAsync(async () =>
- {
- await page.ClickAsync("text='Log in'");
- }, new PageRunAndWaitForNavigationOptions
- {
- UrlFunc = (url) =>
- {
- return url.Contains("users/login");
- },
- WaitUntil = WaitUntilState.Commit
- });
- // JavaScript互操作
- await page.ExposeFunctionAsync("sha256", (string input) =>
- {
- return Convert.ToBase64String(
- SHA256.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(input)));
- });
- await page.SetContentAsync(@"
- <button onclick='onClick()'>Click me</button>
- "
- );
- await page.ClickAsync("button");
- // Locator(定位器)
- // 按 id 查找
- page.Locator("#su");
- page.Locator("id=su");
- // 按文本查找
- page.Locator("text=hao123");
- page.Locator("'hao123'");
- page.Locator("text=/^ha\\w+23$/i");
- // 按 CSS 查找
- page.Locator("input[value='百度一下']");
- page.Locator("input:text('百度')");
- //按 XPath 查找
- page.Locator("//*[@id="su"]");
- // BrowserContext(浏览器上下文)
- var browserContext1 = await browser.NewContextAsync();
- var cookie1 = await GetCookie(browserContext1);
- Console.WriteLine(cookie1);
- var browserContext2 = await browser.NewContextAsync();
- var cookie2 = await GetCookie(browserContext2);
- Console.WriteLine(cookie2);
- static async Task<string> GetCookie(IBrowserContext browserContext)
- {
- var page = await browserContext.NewPageAsync();
- await page.GotoAsync("https://www.baidu.com");
- var cookies = await browserContext.CookiesAsync();
- return cookies.First(p => p.Name == "BAIDUID").Value;
- }
- // Frame(框架)
- foreach (var frame in page.Frames)
- Console.WriteLine($"{frame.Url.Split('/').Last()}");
- Console.WriteLine("");
- Console.WriteLine("显示 Frame 嵌套树:");
- DumpFrameTree(page.MainFrame, string.Empty);
- static void DumpFrameTree(IFrame frame, string indent)
- {
- Console.WriteLine($"{indent}{frame.Url.Split('/').Last()}");
- foreach (var child in frame.ChildFrames)
- DumpFrameTree(child, indent + " ");
- }
复制代码
设置playwright环境的默认目录:- Environment.SetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ms-playwright"));
- //初始化playwright环境,chromium, chrome, chrome-beta, msedge, msedge-beta, msedge-dev, firefox, webkit 可选
- Microsoft.Playwright.Program.Main(new[] { "install", "chromium" });
复制代码
来源:https://www.cnblogs.com/sanday/p/18283994
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|