WebView2 通過 PuppeteerSharp 實現爬取 王者 桌布 (案例版)

2022-08-10 12:07:32

此案例是《.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 同名)