WebView2 通過 PuppeteerSharp 實現爬取 王者 壁紙 (案例版)

来源:https://www.cnblogs.com/kesshei/archive/2022/08/10/16570947.html
-Advertisement-
Play Games

此案例是《.Net WebView2 項目,實現 嵌入 WEB 頁面 Chromium內核》文的續集。 主要是針對WebView2的一些微軟自己封裝的不熟悉的API,有一些人已經對 PuppeteerSharp很熟悉了,那麼,直接用 PuppeteerSharp的話,那就降低了學習成本,那還是很有必 ...


此案例是《.Net WebView2 項目,實現 嵌入 WEB 頁面 Chromium內核》文的續集。

主要是針對WebView2的一些微軟自己封裝的不熟悉的API,有一些人已經對 PuppeteerSharp很熟悉了,那麼,直接用 PuppeteerSharp的話,那就降低了學習成本,那還是很有必須要的。

之前自己也RPA獲取過聯盟的高清原畫,現在就獲取下王者的高清壁紙。

王者壁紙自動化獲取邏輯分析

其實它的邏輯很簡單, 就是王者的官網,打開後,在右下角就看到了皮膚頁面部分。

這個時候,點擊更多,就會打開全部英雄詳情的頁面。

這個時候,單點任意一個英雄,就會新開一個頁面,這個英雄自己的頁面,可以看到具體的皮膚信息了。

這裡可以看到有6個皮膚,那麼,到這裡我就可以獲取這6個皮膚作為高清王者的皮膚了。

那麼,讓程式自動化操作,並把這些信息處理保存好,就是我們要做到的事情。

新建一個WPF項目

新建一個 WPF 項目,要添加 Nuget 包

Install-Package Microsoft.Web.WebView2 -Version 1.0.1293.44
Install-Package PuppeteerSharp -Version 7.1.0
Install-Package HtmlAgilityPack -Version 1.11.43

MainWindow.xaml

界面大致樣子和佈局

<DockPanel>
    <StackPanel DockPanel.Dock="Top" Orientation="Horizontal" HorizontalAlignment="Right">
        <Label Name = "loginfo" Content="未採集"/>
        <Button Name="start" DockPanel.Dock="Right" Width="150" Content="開始採集" Click="start_Click"/>
    </StackPanel>
    <wpf:WebView2 Name = "webView2"/>
</DockPanel>

右上角一個提示信息,一個採集的按鈕,佈局很是簡單

如何啟用 PuppeteerSharp

其實都是基於谷歌的DevTools協議來的,所以,只要WebView2開啟了Debugging埠即可。

var result = await CoreWebView2Environment.CreateAsync(null, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "cache"),
    new CoreWebView2EnvironmentOptions($"--remote-debugging-port={Port}"));
await webView2.EnsureCoreWebView2Async(result);

通過WebVeiw2的游覽器啟動參數 : --remote-debugging-port=6666 來開啟DevTools協議的支持。

PuppeteerSharpHelper

public class PuppeteerSharpHelper
{
    /// <summary>
    /// 獲取游覽器對象
    /// </summary>
    public static Task<Browser> GetBrowser(int port, int height, int width)
    {
        return Puppeteer.ConnectAsync(new ConnectOptions { DefaultViewport = new ViewPortOptions() { Height = height, Width = width }, BrowserWSEndpoint = WSEndpointResponse.GetWebSocketDebuggerUrl(port) });
    }
    internal class WSEndpointResponse
    {
        public string WebSocketDebuggerUrl { get; set; }
        public static string GetWebSocketDebuggerUrl(int port)
        {
            string data;
            using (var client = new HttpClient())
            {
                data = client.GetStringAsync($"http://127.0.0.1:{port}/json/version").Result;
            }
            return JsonConvert.DeserializeObject<WSEndpointResponse>(data).WebSocketDebuggerUrl;
        }
    }
}

所用到的王者實體信息

/// <summary>
/// 英雄的信息
/// </summary>
public class HeroInfo
{
    public string Name { get; set; }
    public string Url { get; set; }
    public string TargetUrl()
    {
        return $"https://pvp.qq.com/web201605/{Url}";
    }
    public List<HeroSkin> HeroSkins { get; set; }
}
/// <summary>
/// 英雄皮膚
/// </summary>
public class HeroSkin
{
    public HeroSkin(string name, string url)
    {
        this.Name = name;
        this.Url = "https:" + url;
    }
    public string Name { get; set; }
    public string Url { get; set; }
}

RPA的核心代碼

private async void start_Click(object sender, RoutedEventArgs e)
{
    var herolistPath = await Currentpage.EvaluateExpressionAsync<string>("document.querySelector('body > div.wrapper > div.main > div:nth-child(3) > div.skin_center.fl > div.item_header > a').href");

    await Currentpage.GoToAsync(herolistPath, WaitUntilNavigation.DOMContentLoaded);
    loginfo.Content = "開始獲取內容";
    var herolist = await Currentpage.EvaluateExpressionAsync<string>("document.querySelector('body > div.wrapper > div > div > div.herolist-box > div.herolist-content > ul').innerHTML");
    var heros = GetHeroInfos(herolist);
    loginfo.Content = $"獲取全部英雄信息共:{heros.Count}條";
    foreach (var item in heros)
    {
        await Currentpage.GoToAsync(item.TargetUrl(), WaitUntilNavigation.DOMContentLoaded);
        Thread.Sleep(100);
        var skins = await Currentpage.EvaluateExpressionAsync<string>("document.querySelector('body > div.wrapper > div.zk-con1.zk-con > div > div > div.pic-pf > ul').innerHTML");
        item.HeroSkins = GetHeroSkins(skins);
    }
    loginfo.Content = "開始下載資源";
    var count = 0;
    //開始執行下載
    foreach (var item in heros)
    {
        count++;
        loginfo.Content = $"資源一共:{heros.Count}條,正在下載第{count}條,還剩下:{heros.Count - count}";
        var HearoPath = System.IO.Path.Combine(ImagesPath, item.Name);
        if (!System.IO.Directory.Exists(HearoPath))
        {
            System.IO.Directory.CreateDirectory(HearoPath);
        }
        foreach (var skin in item.HeroSkins)
        {
            await WebHelper.DownloadFile(skin.Url, System.IO.Path.Combine(HearoPath, $"{skin.Name}.jpg"));
        }
    }
    loginfo.Content = "獲取完畢,等待查看!";
}

效果如下:

需要點擊獲取按鈕,就會執行自動化獲取操作,然後把獲取的內容存儲到當前項目bin目錄images目錄下。

下麵就是下載完後的效果。


整整齊齊,很完整,都是我喜歡的英雄和買不起的皮膚。


而且,獲取到的包含了皮膚的名稱

總結

基於WebView2,技術又深一層次的展開,一個好的技術,必定用到合適的場景上才是最合適的。

代碼地址

https://github.com/kesshei/WangZheRongYao.git

https://gitee.com/kesshei/WangZheRongYao.git

一鍵三連呦!,感謝大佬的支持,您的支持就是我的動力!

版權

藍創精英團隊(公眾號同名,CSDN 同名,CNBlogs 同名)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • “強引用、軟引用、弱引用、虛引用有什麼區別?” 這個問題難倒了很多資深Java工程師,不是因為這個問題本身有多難。 而是確實它是一個比較小眾的知識點。 大家好,我是Mic,一個工作了14年的Java程式員。 今天給大家分享一下這道面試題的標準回答。 文字版本我整理到了一個15W字的面試文檔裡面,大家 ...
  • 多商戶商城系統,也稱為B2B2C(BBC)平臺電商模式多商家商城系統。可以快速幫助企業搭建類似拼多多/京東/天貓/淘寶的綜合商城。 多商戶商城系統支持商家入駐加盟,同時滿足平臺自營、旗艦店等多種經營方式。平臺可以通過收取商家入駐費,訂單交易服務費,提現手續費,簡訊通道費等多手段方式,實現整體盈利。 ...
  • 在Spring Security中可以同時存在多個過濾器鏈,一個WebSecurityConfigurerAdapter的實例就可以配置一條過濾器鏈。 我們來看如下一個案例: @Configuration public class SecurityConfig { @Bean UserDetails ...
  • 2 併發容器線程安全應對之道 引言 在前面,我們學習了hashmap 大家都知道HashMap不是線程安全(put、刪除、修改、遞增、擴容都無鎖)的 所以在處理併發的時候會出現問題 接下來我們看下J.U.C包裡面提供的一個線程安全並且高效Map(ConcurrentHashMap) 看一下,他到底是 ...
  • 前言:Maui終於在昨天(2022年8月9日)推送出來了。今兒就迫不及待來把玩一下先。 A、我本地已有VS2022,不過版本比較老,此處選擇更新。工具 -> 獲取功能和更新裡面,可以獲取到新版本更新。 B、最新版本是17.3.0,我本地只有17.1.1,選擇 更新。 C、讓網路飛一會兒。 1、更新完 ...
  • 依賴註入容器之所以能夠提供應用程式所需的服務對象,是因為服務註冊為容器提供了創建服務對象的描述信息,而這個服務註冊的描述信息是被封裝在一個由ServiceDescriptor類型表示的對象中,該對象主要存儲在IServiceCollection類型的集合中,其中每個ServiceDescriptor ...
  • 老闆加薪!看我做的WPF Loading!!! 控制項名:RingLoading 作者:WPFDevelopersOrg 原文鏈接: https://github.com/WPFDevelopersOrg/WPFDevelopers 框架使用大於等於.NET40; Visual Studio 2022 ...
  • 基於.NetCore的積木化服務框架(Gitee地址),主要將常規解決方案進行進一步的抽象下沉形成相關基礎可選框架單元(在Framework 目錄),併在此基礎上實現常規系統模塊(在Modules 目錄),如用戶管理,許可權管理等。 當前項目,目的是為了提供一個思路,而不是模板。除了 Framewor ...
一周排行
    -Advertisement-
    Play Games
  • 1.部署歷史 猿友們好,作為初來實習的我,已經遭受社會的“毒打”,所以請容許我在下麵環節適當吐槽,3Q! 傳統部署 ​ 回顧以往在伺服器部署webapi項目(非獨立發佈),dotnet環境、守護進程兩個逃都逃不掉,正常情況下還得來個nginx代理。不僅僅這仨,可能牽扯到yum或npm。node等都要 ...
  • 隨著技術的進步,跨平臺開發已經成為了標配,在此大背景下,ASP.NET Core也應運而生。本文主要基於ASP.NET Core+Element+Sql Server開發一個校園圖書管理系統為例,簡述基於MVC三層架構開發的常見知識點,前一篇文章,已經簡單介紹瞭如何搭建開發框架,和登錄功能實現,本篇... ...
  • 這道題只要會自定義cmp恰當地進行排序,其他部分沒有什麼大問題。 上代碼: 1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,s,h1,h2,cnt; 4 struct apple{ 5 int height,ns;//height為蘋 ...
  • 這篇文章主要描述RPC的路由策略,包括為什麼需要請求隔離,為什麼不在註冊中心中實現請求隔離以及不同粒度的路由策略。 ...
  • 簡介: 中介者模式,屬於行為型的設計模式。用一個中介對象來封裝一系列的對象交互。中介者是各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變他們之間的交互。 適用場景: 如果平行對象間的依賴複雜,可以使用中介者解耦。 優點: 符合迪米特法則,減少成員間的依賴。 缺點: 不適用於系統出現對 ...
  • 【前置內容】Spring 學習筆記全系列傳送門: Spring學習筆記 - 第一章 - IoC(控制反轉)、IoC容器、Bean的實例化與生命周期、DI(依賴註入) Spring學習筆記 - 第二章 - 註解開發、配置管理第三方Bean、註解管理第三方Bean、Spring 整合 MyBatis 和 ...
  • 簡介: 享元模式,屬於結構型的設計模式。運用共用技術有效地支持大量細粒度的對象。 適用場景: 具有相同抽象但是細節不同的場景中。 優點: 把公共的部分分離為抽象,細節依賴於抽象,符合依賴倒轉原則。 缺點: 增加複雜性。 代碼: //用戶類 class User { private $name; fu ...
  • 這次設計一個通用的多位元組SPI介面模塊,特點如下: 可以設置為1-128位元組的SPI通信模塊 可以修改CPOL、CPHA來進行不同的通信模式 可以設置輸出的時鐘 狀態轉移圖和思路與多位元組串口發送模塊一樣,這裡就不給出了,具體可看該隨筆。 一、模塊代碼 1、需要的模塊 通用8位SPI介面模塊 `tim ...
  • AOP-03 7.AOP-切入表達式 7.1切入表達式的具體使用 1.切入表達式的作用: 通過表達式的方式定義一個或多個具體的連接點。 2.語法細節: (1)切入表達式的語法格式: execution([許可權修飾符] [返回值類型] [簡單類名/全類名] [方法名]([參數列表]) 若目標類、介面與 ...
  • 測試一、虛繼承與繼承的區別 1.1 單個繼承,不帶虛函數 1>class B size(8): 1> + 1> 0 | + (base class A) 1> 0 | | _ia //4B 1> | + 1> 4 | _ib //4B 有兩個int類型數據成員,占8B,基類邏輯存在前面 1.2、單個 ...