5月 15, 2024

Skype 訊息監視程式 - 讀取網頁元素


前篇 [preview] Skype 訊息監視程式

原本的預定是製作一個 XML的讀寫檔功能,目的是為了能夠紀錄要監控的對話視窗,但中間插入了一個想法是先把對話群組列出來,這樣到時候在設定畫面的時候就可以比較方便的做新增。

而在製作功能時遇到了一些關於 WebView 的問題,在以前的版本 C# 有內建 WebBrowser 的功能,但在目前的版本則是要自己裝套件,而我使用的是 Microsoft.Web.WebView2.Core 的版本核心。

但這個核心實際使用起來其實提供的東西不多(微軟 ...),而我的目的只是單純的想要 parse html 而已,在以前的 WebBrowser 記得就有內建 DOM 的功能庫可以使用,但在 WebView2 中卻好像沒有這個東西,也只能另尋他法

單就這個問題卡了大約一兩天,後來大概找了一下 Google,有找到別人提供的一些方法,其中一個是使用 HtmlAgilityPack 這個套件,可以透過 NuGet 下載安裝,所以就以這個當工具來試試。

他的使用方式不算複雜,網站裡面也都有說明。

最主要先使用到 WebView2 的 ExecuteScriptAsync 功能,把整個網站的 Body 內容取出來

var htmlCode = await browser.CoreWebView2.ExecuteScriptAsync("document.body.innerHTML");

但這邊有遇到一個問題,正常來說取得的結果是正確的標籤,但不曉得為什麼左 tag 會拿到 \u003C,所以內容會變成 \u003Cdiv>,隨意找了一下發現用 Unescape 就能處理。

htmlCode = Regex.Unescape(htmlCode);
htmlCode = htmlCode.Remove(0, 1);
htmlCode = htmlCode.Remove(htmlCode.Length - 1, 1);

接著,就可以使用 HtmlAgilityPack 中的 HtmlDocument 將整個 Html 包進來,這時候會變成類似 XmlNode 的物件,最後再使用 SelectNode 等方法就可以開始處理整段需求

透過這個方式後來有把對話的群組名稱全都抓到了,但 Skype 的網頁版畫面的元素並不是有指定的命名或者 id ,大多數爬網頁其實也會遇到同樣的問題,只要網頁結構改變就會抓不到需要改版,所以針對這問題就不著墨處理了

新加入的程式片段大概如下

    var htmlCode = await browser.CoreWebView2.ExecuteScriptAsync("document.body.innerHTML");
    if (htmlCode == null)
    {
        addInfoMessage("Get Html Code Error");
        return;
    }
    htmlCode = Regex.Unescape(htmlCode);
    htmlCode = htmlCode.Remove(0, 1);
    htmlCode = htmlCode.Remove(htmlCode.Length - 1, 1);
    HtmlAgilityPack.HtmlDocument htmlDocument = new();
    htmlDocument.LoadHtml(htmlCode);
    HtmlNodeCollection listitemNodes = htmlDocument.DocumentNode.SelectNodes("//div[@role=\"listitem\"]");
    if (listitemNodes != null)
    {
        foreach (var node in listitemNodes)
        {
            try
            {
                HtmlNode picNode = node.ChildNodes[0].ChildNodes[0].ChildNodes[0];
                if (!picNode.Attributes.Contains("title") || String.IsNullOrEmpty(picNode.Attributes["title"].Value))
                {
                    HtmlNode nameNode = node.ChildNodes[0].ChildNodes[0].ChildNodes[0].ChildNodes[1].ChildNodes[0].ChildNodes[0];
                    if (nameNode.Attributes.Contains("data-text-as-pseudo-element"))
                    {
                        string chatName = nameNode.Attributes["data-text-as-pseudo-element"].Value;
                        if (!String.IsNullOrEmpty(chatName))
                        {
                            chatList.Add(chatName);
                        }
                    }
                }
                else
                {
                    string groupName = picNode.GetAttributeValue("title", "");
                    if (!String.IsNullOrEmpty(groupName))
                    {
                        groupList.Add(groupName);
                    }
                }
            }        
       }
    }

最後附上努力更新的 Github

沒有留言:

張貼留言