段小非 发表于 2024-7-4 15:54:29

Playwright for .NET使用

安装全局工具:
# 安装全局工具
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"
      )
});
#endregionPlaywright 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 codege‍ 
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: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", "关键字");
// 点击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 :nth-child(7)").CheckAsync();
await page.Locator("#checkbox :nth-child(7)").SetCheckedAsync(true);
// 下拉框操作
// 选择下拉框中的选项
await page.SelectOptionAsync("select", "Canada");
// 通过value值选择
await page.Locator("").SelectOptionAsync("opel");
// 通过可见文本选择
await page.Locator("").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");
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.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");
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】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Playwright for .NET使用