翼度科技»论坛 编程开发 .net 查看内容

Playwright for .NET使用

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
安装全局工具:
  1. # 安装全局工具
  2. dotnet tool install --global Microsoft.Playwright.CLI
  3. # 创建项目
  4. dotnet new console -n Console1
  5. cd Console1
  6. # 安装依赖
  7. dotnet add package Microsoft.Playwright
  8. # 用Playwright 工具安装所需的浏览器  C:\Users\Administrator\AppData\Local\ms-playwright
  9. playwright install
  10. # 运行项目
  11. dotnet run
复制代码
在新的环境中部署:
  1. # 安装全局工具
  2. dotnet tool install --global Microsoft.Playwright.CLI
  3. # 用Playwright 工具安装浏览器(要在项目部署的目录)
  4. dotnet Microsoft.Playwright.dll -- install
复制代码
基本使用:
  1. using var playwright = await Playwright.CreateAsync();
  2. await using var browser = await playwright.Chromium.LaunchAsync();
  3. var page = await browser.NewPageAsync();
  4. await page.GotoAsync("https://www.baidu.com");
  5. var title = await page.InnerTextAsync("title");
复制代码
Playwright Trace Viewer工具来追踪测试执行:
  1. using var playwright = await Playwright.CreateAsync();
  2. await using var browser = await playwright.Chromium.LaunchAsync(new() { Headless = true });
  3. var context = await browser.NewContextAsync();
  4. #region 开始追踪记录
  5. await context.Tracing.StartAsync(new()
  6. {
  7.     Title = $"qwe123",
  8.     Screenshots = true,
  9.     Snapshots = true,
  10.     Sources = true
  11. });
  12. #endregion
  13. var page = await context.NewPageAsync();//await browser.NewPageAsync();
  14. await page.GotoAsync("https://www.baidu.com");
  15. //将上面链接打开后的page页面截图 保存成 screenshot.png
  16. await page.ScreenshotAsync(new PageScreenshotOptions { Path = Path.Combine(
  17.         Environment.CurrentDirectory,
  18.         "screenshot",
  19.         $"{DateTime.Now.ToString("yyyyMMddHHmmss")}.png"
  20.         ) });
  21. var title = await page.InnerTextAsync("title");
  22. #region 结束追踪记录
  23. await context.Tracing.StopAsync(new()
  24. {
  25.     Path = Path.Combine(
  26.         Environment.CurrentDirectory,
  27.         "playwright-traces",
  28.         $"{DateTime.Now.ToString("yyyyMMddHHmmss")}.zip"
  29.         )
  30. });
  31. #endregion
复制代码
Playwright Trace Viewer工具记录多个追踪(trace chunk):
  1. using var playwright = await Playwright.CreateAsync();
  2. await using var browser = await playwright.Chromium.LaunchAsync(new() { Headless = true });
  3. var context = await browser.NewContextAsync();
  4. #region 开始追踪记录
  5. await context.Tracing.StartAsync(new()
  6. {
  7.     Title = $"qwe123",
  8.     Screenshots = true,
  9.     Snapshots = true,
  10.     Sources = true
  11. });
  12. #endregion
  13. #region 开始追踪记录
  14. await context.Tracing.StartChunkAsync(new()
  15. {
  16.     Title = $"qwe123"
  17. });
  18. #endregion
  19. var page = await context.NewPageAsync();//await browser.NewPageAsync();
  20. await page.GotoAsync("https://www.baidu.com");
  21. //将上面链接打开后的page页面截图 保存成 screenshot.png
  22. await page.ScreenshotAsync(new PageScreenshotOptions { Path = Path.Combine(
  23.         Environment.CurrentDirectory,
  24.         "screenshot",
  25.         $"{DateTime.Now.ToString("yyyyMMddHHmmss")}.png"
  26.         ) });
  27. var title = await page.InnerTextAsync("title");
  28. #region 结束追踪记录
  29. await context.Tracing.StopChunkAsync(new()
  30. {
  31.     Path = Path.Combine(
  32.         Environment.CurrentDirectory,
  33.         "playwright-traces",
  34.         $"{DateTime.Now.ToString("yyyyMMddHHmmss")}1.zip"
  35.         )
  36. });
  37. #endregion
  38. #region 开始追踪记录
  39. await context.Tracing.StartChunkAsync(new()
  40. {
  41.     Title = $"qwe1234"
  42. });
  43. #endregion
  44. await page.GotoAsync("https://www.baidu.com/");
  45. // 等待页面加载完成
  46. await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
  47. await page.GetByRole(AriaRole.Link, new() { Name = "登录" }).ClickAsync();
  48. await page.GetByPlaceholder("手机号/用户名/邮箱").ClickAsync();
  49. await page.GetByPlaceholder("手机号/用户名/邮箱").FillAsync("123456");
  50. await page.GetByPlaceholder("密码").ClickAsync();
  51. await page.GetByPlaceholder("密码").FillAsync("qwe123");
  52. await page.GetByRole(AriaRole.Checkbox, new() { Name = "阅读并接受" }).CheckAsync();
  53. await page.GetByRole(AriaRole.Button, new() { Name = "登录" }).ClickAsync();
  54. #region 结束追踪记录
  55. await context.Tracing.StopChunkAsync(new()
  56. {
  57.     Path = Path.Combine(
  58.         Environment.CurrentDirectory,
  59.         "playwright-traces",
  60.         $"{DateTime.Now.ToString("yyyyMMddHHmmss")}2.zip"
  61.         )
  62. });
  63. #endregion
复制代码
 
本地打开跟踪文件:
  1. playwright show-trace 12344.zip
复制代码
 
开启Playwright录制操作自动生成代码脚本:
  1. playwright codege‍
复制代码
 
Playwright发布与部署:
部署模式选择“独立”,可以不依赖框架运行
另一台机器上运行我们的程序之前,需要在这台机器上重新安装 Playwright,但无需安装 dotnet 框架或运行时。
运行发布文件夹下的安装命令:
  1. .playwright\node\win32_x64\playwright.cmd install
复制代码
常用操作:
  1. // 创建Chromium浏览器实例
  2. await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions()
  3. {
  4.     Headless = false, // 关闭无头模式(有界面)
  5.     SlowMo = 50, // 放慢执行速度
  6.     Channel = "chrome", // 指定采用chrome浏览器类型
  7.     Devtools = true, // 启用开发者工具
  8.     ChromiumSandbox = false, // 关闭浏览器沙盒
  9.     ExecutablePath = string.Empty, // 不指定浏览器可执行文件位置,会自动寻找 ms-playwright 下载的浏览器
  10.     Args = new[] { "--enable-automation=true", "--disable-blink-features=AutomationControlled" }, // 防止selenium被检测
  11. });
  12. // 浏览器上下文
  13. await using var context = await browser.NewContextAsync(new BrowserNewContextOptions
  14. {
  15.     ViewportSize = new ViewportSize
  16.     {
  17.         Width = 1536, // 1920 * 0.8
  18.         Height = 864, // 1080 * 0.8
  19.     }, // 窗口大小
  20.     Locale = "zh-CN", // 指定语言(区域)
  21.     TimezoneId = "Asia/Shanghai", // 指定时区
  22. });
  23. // 存储当前会话
  24. await context.StorageStateAsync(new BrowserContextStorageStateOptions
  25. {
  26.     Path = "state.json"
  27. });
  28. // 使用会话,当state.json文件不存在时会报错
  29. await browser.NewContextAsync(new BrowserNewContextOptions
  30. {
  31.     StorageStatePath = "state.json"
  32. });
  33. // 等待登录按钮出现
  34. await page.WaitForSelectorAsync(".login");
  35. // 点击登录
  36. await page.ClickAsync(".login");
  37. // 查找页面元素 可匹配到 美食
  38. var locator = page.Locator(“div[class^='title-text-']:text-is('美食')”);
  39. // 获取匹配到元素的个数
  40. var count = await locator.CountAsync();
  41. // 鼠标悬停在元素上
  42. await page.HoverAsync("#title");
  43. // 执行js获取页面地址
  44. var href = await page.EvaluateAsync<string>("document.location.href");
  45. // 定位器
  46. var element = page.Locator(".passMod_dialog-close-btn");
  47. // 等待1秒
  48. await Task.Delay(1000);
  49. await element.ClickAsync();
  50. // 显式等待 设定的超时时间内,仍然没有通过定位器等待到目标元素,将会抛出异常
  51. await page.GotoAsync("https://stackoverflow.com/");
  52. var elelment = page.Locator("id=noscript-warning");
  53. await elelment.WaitForAsync();
  54. var text = await elelment.InnerTextAsync(new LocatorInnerTextOptions { Timeout = 10 });
  55. // RunAndWaitForPopupAsync 方法可以帮助我们执行操作并等待弹出窗口出现
  56. await page.GotoAsync("https://www.baidu.com/");
  57. await page.RunAndWaitForPopupAsync(async () =>
  58. {
  59.     await page.ClickAsync("text=新闻");
  60. },
  61.     new PageRunAndWaitForPopupOptions
  62.     {
  63.         Predicate = (page) =>
  64.         {
  65.             return page.Url.Contains("news.baidu.com");
  66.         }
  67.     });
  68. // RunAndWaitForRequestAsync/RunAndWaitForResponseAsync两个方法可以通过传入URL地址或表达式来过滤等待的请求或响应,从而实现更加精细的控制。方法都是阻塞式的。也就是说,如果我们等待的情况一直未出现,后续的代码将不会执行。<br>// 在某些情况下,我们只需要在情况出现时进行一些操作,即使情况不出现也不应该影响整体的运行。这时,我们可以使用监听事件来实现。
  69. await page.RunAndWaitForRequestAsync(async () => {
  70.     await page.GotoAsync("https://stackoverflow.com/",
  71.         new PageGotoOptions{ WaitUntil = WaitUntilState.Commit});
  72. },
  73. request => {
  74.     Console.WriteLine(request.Url);
  75.     //return request.Url.Contains("jquery.min.js");
  76.     return request.Url.Contains("stacks.min.js");
  77. });
  78. await page.RunAndWaitForResponseAsync(async () => {
  79.     await page.ClickAsync("text='Login'"); },
  80.     response => response.Url.Contains("users/login")
  81.     );
  82. // 当页面发起的请求失败时触发
  83. page.RequestFailed += (sender, request) => {
  84.     Console.WriteLine($"请求{request.Url}发生错误{request.Failure}");
  85. };
  86. // 当页面发起的请求完成时触发
  87. page.RequestFinished += (sender, request) => {
  88.     Console.WriteLine($"请求{request.Url}发生错111111误{request.Failure}");
  89. };
  90. await page.GotoAsync("https://baidu.com/");
  91. // Close:当页面关闭时触发
  92. // Console:当控制台输出时触发
  93. // Crash:当页面崩溃时触发。例如,试图分配太多内存,浏览器页面可能会崩溃。
  94. // Dialog:当 JavaScript 对话框出现时触发。例如,alert、prompt、confirm等。
  95. // DOMContentLoaded:当页面的 DOMContentLoaded 事件触发时触发
  96. // Download:当下载开始时触发
  97. // FileChooser:当文件选择对话框出现时触发
  98. // FrameAttached:当 frame 连接到页面时触发
  99. // FrameDetached:当 frame 与页面分离时触发
  100. // FrameNavigated:当 frame 导航到一个新的 url 时触发
  101. // Load: 当页面的 load 事件触发时触发
  102. // PageError:当页面内发生未捕获异常时触发
  103. // Popup:当页面弹出新的窗口时触发
  104. // Request:当页面发起一个新的请求时触发
  105. // RequestFailed:当页面发起的请求失败时触发
  106. // RequestFinished:当页面发起的请求完成时触发
  107. // Response:当页面收到一个新的响应时触发
  108. // 输入搜索关键字
  109. await page.TypeAsync("input[name='q1']", "关键字");
  110. // 点击page按钮跳转到page1
  111. var page1 = await page.RunAndWaitForPopupAsync(async () =>
  112. {
  113.     // 点击搜索
  114.     await page.ClickAsync(".advanced-search-btn");
  115. });
  116. // 检查文本框内容
  117. var handleInput = await page1.WaitForSelectorAsync("#kw");
  118. var text = await handleInput.GetAttributeAsync("value");
  119. // 输入操作
  120. await page.Locator("#kw").FillAsync("1212121");
  121. // 点击操作
  122. await page.Locator("#kw").ClickAsync();
  123. // 单选(选中,已选中状态下无效)
  124. await page.Locator(".check1").SetCheckedAsync(true);
  125. await page.Locator(".Volvo").CheckAsync();
  126. // 复选框(选中,已选中状态下无效)
  127. await page.Locator("#checkbox [type='checkbox']:nth-child(7)").CheckAsync();
  128. await page.Locator("#checkbox [type='checkbox']:nth-child(7)").SetCheckedAsync(true);
  129. // 下拉框操作
  130. // 选择下拉框中的选项
  131. await page.SelectOptionAsync("select[name='country']", "Canada");
  132. // 通过value值选择
  133. await page.Locator("[name='select']").SelectOptionAsync("opel");
  134. // 通过可见文本选择
  135. await page.Locator("[name='select']").SelectOptionAsync(new SelectOptionValue { Label = "blue" });
  136. // 多个选定项目
  137. await page.GetByLabel("Choose multiple colors").SelectOptionAsync(new[] { "blue", "green", "red" });
  138. // 常规单击
  139. await page.Locator("#mouse2").ClickAsync();
  140. // 单击
  141. await page.GetByRole(AriaRole.Button).ClickAsync();
  142. // 双击
  143. await page.GetByText("Item").DblClickAsync();
  144. // 右击
  145. await page.GetByText("Item").ClickAsync(new() { Button = MouseButton.Right });
  146. // Shift + click
  147. await page.GetByText("Item").ClickAsync(new() { Modifiers = new[] { KeyboardModifier.Shift } });
  148. // Ctrl + click or Windows and Linux
  149. // Meta + click on macOS
  150. await page.GetByText("Item").ClickAsync(new() { Modifiers = new[] { KeyboardModifier.ControlOrMeta } });
  151. // Hover over element
  152. await page.GetByText("Item").HoverAsync();
  153. // Click the top left corner
  154. await page.GetByText("Item").ClickAsync(new() { Position = new Position { X = 0, Y = 0 } });
  155. //上传一个文件
  156. await page.Locator("#load").SetInputFilesAsync("demo.md");
  157. // 上传多个文件
  158. await page.Locator("#load").SetInputFilesAsync(new[] { "file1.txt", "file12.txt" });
  159. // 上传文件 找到文件上传输入框
  160. var fileInput = await page.QuerySelectorAsync("input[type='file']");
  161. string filePath = "path/to/your/file.txt"; // 你要上传的文件路径
  162. await fileInput.SetInputFilesAsync(filePath);
  163. // 提取页面标题
  164. string title = await page.TitleAsync();
  165. title = await page.InnerTextAsync("title");
  166. Console.WriteLine("Page title: " + title);
  167. // 提取页面 URL
  168. string url = page.Url;
  169. Console.WriteLine("Page URL: " + url);
  170. // 提取特定元素的文本内容
  171. var elementText = await page.EvaluateAsync<string>("document.querySelector('h1').textContent");
  172. Console.WriteLine("Header text: " + elementText);
  173. // 提取页面中的链接
  174. var links = await page.QuerySelectorAllAsync("a");
  175. foreach (var link in links)
  176. {
  177.     var href = await link.GetAttributeAsync("href");
  178.     Console.WriteLine("Link: " + href);
  179. }
  180. // 等待表格加载完毕
  181. await page.WaitForSelectorAsync("table");
  182. // 获取表格内容
  183. var tableHtml = await page.InnerHTMLAsync("table");
  184. // 使用正则表达式提取表格数据
  185. var regex = new Regex(@"<tr>(.*?)</tr>");
  186. var matches = regex.Matches(tableHtml);
  187. foreach (Match match in matches)
  188. {
  189.     // 这里可以根据表格结构和需要自行解析数据
  190.     var rowHtml = match.Groups[1].Value;
  191.     Console.WriteLine("Row HTML: " + rowHtml);
  192. }
  193. // 等待页面加载完成
  194. await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
  195. // 等待页面跳转
  196. await page.WaitForNavigationAsync();
  197. // RunAndWaitForFileChooserAsync 方法可以帮助我们在执行操作的同时等待文件选择器的出现。
  198. await page.GotoAsync("https://image.baidu.com/");
  199. await page.RunAndWaitForFileChooserAsync(async () =>
  200. {
  201.     await page.ClickAsync("id=sttb");
  202.     await page.ClickAsync("id=uploadImg");
  203. }, new PageRunAndWaitForFileChooserOptions
  204. {
  205.     Predicate = (fileChooser) =>
  206.     {
  207.         return !fileChooser.IsMultiple;
  208.     }
  209. });
  210. // RunAndWaitForNavigationAsync 方法可以帮助我们执行操作并等待页面导航完成
  211. await page.GotoAsync("https://stackoverflow.com/");
  212. await page.RunAndWaitForNavigationAsync(async () =>
  213. {
  214.     await page.ClickAsync("text='Log in'");
  215. }, new PageRunAndWaitForNavigationOptions
  216. {
  217.     UrlFunc = (url) =>
  218.     {
  219.         return url.Contains("users/login");
  220.     },
  221.     WaitUntil = WaitUntilState.Commit
  222. });
  223. // JavaScript互操作
  224. await page.ExposeFunctionAsync("sha256", (string input) =>  
  225. {
  226.     return Convert.ToBase64String(
  227.         SHA256.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(input)));
  228. });
  229. await page.SetContentAsync(@"  
  230.                             <button onclick='onClick()'>Click me</button>  
  231.                             "
  232.                             );
  233. await page.ClickAsync("button");
  234. // Locator(定位器)
  235. // 按 id 查找
  236. page.Locator("#su");
  237. page.Locator("id=su");
  238. // 按文本查找
  239. page.Locator("text=hao123");
  240. page.Locator("'hao123'");
  241. page.Locator("text=/^ha\\w+23$/i");
  242. // 按 CSS 查找
  243. page.Locator("input[value='百度一下']");
  244. page.Locator("input:text('百度')");
  245. //按 XPath 查找
  246. page.Locator("//*[@id="su"]");
  247. // BrowserContext(浏览器上下文)
  248. var browserContext1 = await browser.NewContextAsync();
  249. var cookie1 = await GetCookie(browserContext1);
  250. Console.WriteLine(cookie1);
  251. var browserContext2 = await browser.NewContextAsync();
  252. var cookie2 = await GetCookie(browserContext2);
  253. Console.WriteLine(cookie2);
  254. static async Task<string> GetCookie(IBrowserContext browserContext)
  255. {
  256.     var page = await browserContext.NewPageAsync();
  257.     await page.GotoAsync("https://www.baidu.com");
  258.     var cookies = await browserContext.CookiesAsync();
  259.     return cookies.First(p => p.Name == "BAIDUID").Value;
  260. }
  261. // Frame(框架)
  262. foreach (var frame in page.Frames)
  263.     Console.WriteLine($"{frame.Url.Split('/').Last()}");
  264. Console.WriteLine("");
  265. Console.WriteLine("显示 Frame 嵌套树:");
  266. DumpFrameTree(page.MainFrame, string.Empty);
  267. static void DumpFrameTree(IFrame frame, string indent)
  268. {
  269.     Console.WriteLine($"{indent}{frame.Url.Split('/').Last()}");
  270.     foreach (var child in frame.ChildFrames)
  271.         DumpFrameTree(child, indent + "    ");
  272. }
复制代码
 
设置playwright环境的默认目录:
  1. Environment.SetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ms-playwright"));
  2. //初始化playwright环境,chromium, chrome, chrome-beta, msedge, msedge-beta, msedge-dev, firefox, webkit 可选
  3. Microsoft.Playwright.Program.Main(new[] { "install", "chromium" });
复制代码
 

来源:https://www.cnblogs.com/sanday/p/18283994
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具