Playwright for .NET使用

来源:https://www.cnblogs.com/sanday/p/18283994
-Advertisement-
Play Games

1.簡單使用實例 1.1 添加log4net.dll的引用。 在NuGet程式包中搜索log4net並添加,此次我所用版本為2.0.17。如下圖: 1.2 添加配置文件 右鍵項目,添加新建項,搜索選擇應用程式配置文件,命名為log4net.config,步驟如下圖: 1.2.1 log4net.co ...


安裝全局工具:

# 安裝全局工具
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錄製操作自動生成代碼腳本:

cd D:\Playwright\ConsoleApp1\ConsoleApp1
playwright codege‍n

 

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");
// 查找頁面元素 可匹配到 <div class="title-text-n4df3g8">美食</div>
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地址或表達式來過濾等待的請求或響應,從而實現更加精細的控制。方法都是阻塞式的。也就是說,如果我們等待的情況一直未出現,後續的代碼將不會執行。
// 在某些情況下,我們只需要在情況出現時進行一些操作,即使情況不出現也不應該影響整體的運行。這時,我們可以使用監聽事件來實現。
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(@"<script> async function onClick() { document.querySelector('div').textContent = await window.sha256('PLAYWRIGHT'); } </script> <button onclick='onClick()'>Click me</button> <div></div>" ); 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);
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 什麼是監視器(Monitor)? 在Java中,監視器(Monitor)是用來實現線程同步的一種機制。每個Java對象都有一個與之關聯的監視器,線程可以通過synchronized關鍵字來獲取和釋放對象的監視器。監視器的主要作用是確保在同一時刻只有一個線程可以執行同步塊或同步方法,從而實現線程的互斥 ...
  • ★ 背景說明 在Django REST framework (DRF) 前後端分離項目中,解決CSRF問題通常有以下幾種方法: 1. 禁用CSRF驗證,但這會降低安全性。(不推薦) 2. 使用csrftoken cookie 3. 在前端每次 POST、PUT 或 DELETE 請求前先發起一個GE ...
  • 數字簽名作為PDF文檔中的重要安全機制,不僅能夠驗證文件的來源,還能確保文件內容在傳輸過程中未被篡改。然而,如何正確驗證PDF文件的數字簽名,是確保文件完整性和可信度的關鍵。本文將詳細介紹如何使用免費.NET控制項通過C#驗證PDF簽名的有效性以及驗證PDF文檔是否被修改。 C# 驗證PDF數字簽名有 ...
  • 一、WTM是什麼 WalkingTec.Mvvm框架(簡稱WTM)最早開發與2013年,基於Asp.net MVC3 和 最早的Entity Framework, 當初主要是為瞭解決公司內部開發效率低,代碼風格不統一的問題。2017年9月,將代碼移植到了.Net Core上,併進行了深度優化和重構, ...
  • 實現了一個支持長短按得按鈕組件,單擊可以觸發Click事件,長按可以觸發LongPressed事件,長按鬆開時觸發LongClick事件。還可以和自定義外觀相結合,實現自定義的按鈕外形。 ...
  • WPF的按鈕提供了Template模板,可以通過修改Template模板中的內容對按鈕的樣式進行自定義。結合資源字典,可以將自定義資源在xaml視窗、自定義控制項或者整個App當中調用 ...
  • 在 Visual Studio 中,至少可以創建三種不同類型的類庫: 類庫(.NET Framework) 類庫(.NET 標準) 類庫 (.NET Core) 雖然第一種是我們多年來一直在使用的,但一直感到困惑的一個主要問題是何時使用 .NET Standard 和 .NET Core 類庫類型。 ...
  • 之前也分享過 Swashbuckle.AspNetCore 的使用,不過版本比較老了,本次演示用的示例版本為 .net core 8.0,從安裝使用開始,到根據命名空間分組顯示,十分的有用 ...
一周排行
    -Advertisement-
    Play Games
  • 通過WPF的按鈕、文本輸入框實現了一個簡單的SpinBox數字輸入用戶組件並可以通過數據綁定數值和步長。本文中介紹了通過Xaml代碼實現自定義組件的佈局,依賴屬性的定義和使用等知識點。 ...
  • 以前,我看到一個朋友在對一個系統做初始化的時候,通過一組魔幻般的按鍵,調出來一個隱藏的系統設置界面,這個界面在常規的菜單或者工具欄是看不到的,因為它是一個後臺設置的關鍵界面,不公開,同時避免常規用戶的誤操作,它是作為一個超級管理員的入口功能,這個是很不錯的思路。其實Winform做這樣的處理也是很容... ...
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他的程式每次關閉時就會自動崩潰,一直找不到原因讓我幫忙看一下怎麼回事,這位朋友應該是第二次找我了,分析了下 dump 還是挺經典的,拿出來給大家分享一下吧。 二:WinDbg 分析 1. 為什麼會崩潰 找崩潰原因比較簡單,用 !analyze -v 命 ...
  • 在一些報表模塊中,需要我們根據用戶操作的名稱,來動態根據人員姓名,更新報表的簽名圖片,也就是電子手寫簽名效果,本篇隨筆介紹一下使用FastReport報表動態更新人員簽名圖片。 ...
  • 最新內容優先發佈於個人博客:小虎技術分享站,隨後逐步搬運到博客園。 創作不易,如果覺得有用請在Github上為博主點亮一顆小星星吧! 博主開始學習編程於11年前,年少時還只會使用cin 和cout ,給單片機點點燈。那時候,類似async/await 和future/promise 模型的認知還不是 ...
  • 之前在阿裡雲ECS 99元/年的活動實例上搭建了一個測試用的MINIO服務,以前都是直接當基礎設施來使用的,這次準備自己學一下S3相容API相關的對象存儲開發,因此有了這個小工具。目前僅包含上傳功能,後續計劃開發一個類似圖床的對象存儲應用。 ...
  • 目錄簡介快速入門安裝 NuGet 包實體類User資料庫類DbFactory增刪改查InsertSelectUpdateDelete總結 簡介 NPoco 是 PetaPoco 的一個分支,具有一些額外的功能,截至現在 github 星數 839。NPoco 中文資料沒多少,我是被博客園群友推薦的, ...
  • 前言 前面使用 Admin.Core 的代碼生成器生成了通用代碼生成器的基礎模塊 分組,模板,項目,項目模型,項目欄位的基礎功能,本篇繼續完善,實現最核心的模板生成功能,並提供生成預覽及代碼文件壓縮下載 準備 首先清楚幾個模塊的關係,如何使用,簡單畫一個流程圖 前面完成了基礎的模板組,模板管理,項目 ...
  • 假設需要實現一個圖標和文本結合的按鈕 ,普通做法是 直接重寫該按鈕的模板; 如果想作為通用的呢? 兩種做法: 附加屬性 自定義控制項 推薦使用附加屬性的形式 第一種:附加屬性 創建Button的附加屬性 ButtonExtensions 1 public static class ButtonExte ...
  • 在C#中,委托是一種引用類型的數據類型,允許我們封裝方法的引用。通過使用委托,我們可以將方法作為參數傳遞給其他方法,或者將多個方法組合在一起,從而實現更靈活的編程模式。委托類似於函數指針,但提供了類型安全和垃圾回收等現代語言特性。 基本概念 定義委托 定義委托需要指定它所代表的方法的原型,包括返回類 ...