Parse Html jQuery like CSS/HTML selector in C#
前言
在2010年左右,.net技術如果想parse解析Html網頁,只有Html Agility Pack這個選擇
HtmlAgilityPack由於是以XML角度看待Html,抓取網頁標籤資料使用XPath+Linq的寫法
對於習慣寫前端jQuery的人來說相當不好上手
如今事隔多年,.net解析Html網頁的第三方套件百家爭鳴,在nuget官網上看得我眼花撩亂XD
陸續出現採用CSS Selector的寫法來解析網頁的套件也不少,終於可以在後端使用類似jQuery CSS Selector方式來抓取網頁標籤資料
今天要介紹的一款就是號稱解析效能很好和HtmlAgilityPack有得拼的AngleSharp
實作
從Nuget即可安裝,第一個就是

專案環境必須是.net Framework 4以上,3.5以下的話,從Nuget會安裝失敗
以抓取奇摩電影海報圖為例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
/*引用命名空間*/
using AngleSharp;
using AngleSharp.Dom;
namespace ConsoleApp2Test
{
    class Program
    {
        static void Main(string[] args)
        { 
            IConfiguration config = Configuration.Default.WithDefaultLoader();
            string url = "https://tw.movies.yahoo.com"; 
            IDocument doc =   BrowsingContext.New(config).OpenAsync(url).Result;
           
            /*CSS Selector寫法*/
            IHtmlCollection<IElement> imgs = doc.QuerySelectorAll("div.movie_foto img:first-child");//取得圖片
            foreach (IElement img in imgs)
            {
                Console.WriteLine(img.GetAttribute("src"));
            }
            Console.ReadKey();
        }
    }
}
執行結果:

個人覺得寫法比起HtmlAgilityPack,要來的簡潔好懂多了
再看看其他官方AngleSharp examples,也支援JavaScript engine
整體而言,真是不錯的套件,後續看好它的發展
2019-10-20補充
如果需要把讀取出來的HTML代碼做修改可以參考以下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/*引用命名空間*/
using AngleSharp;
using AngleSharp.Dom;
namespace ConsoleApp1_Selector
{
    class Program
    {
        static void Main(string[] args)
        {
            //html代碼
            var source = @"
                            <!DOCTYPE html>
                            <html>
                              <meta charset=utf-8>
                              <meta name=viewport content=""initial-scale=1, width=device-width"">
                              <title>Test Page</title>
                              <style>
                                *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px} 
                              </style>
                            <div>
                                   <!--第一張圖沒有alt-->
                                   <img src=""Content/1.jpg"" />
                                   <br/>
                                   <!--第二張圖alt沒給值也沒有等號-->
                                   <img alt src=""Content/2.jpg"" /> 
                                   <br/>
                                    <img alt="""" src=""Content/3.jpg"" /> 
                                   <br/>
                                    <img alt='' src='Content/4.jpg' /> 
                                      <br/>
                                    <img alt=  src=Content/5.jpg /> 
                                    <br/>
                                    <img alt=test src=Content/6.jpg > 
                            </div>";
             
            IDocument document = BrowsingContext.New(Configuration.Default.WithDefaultLoader())
                                .OpenAsync(req => req.Content(source)).Result;
            IEnumerable<IElement> imgs=  document.QuerySelectorAll("img");//取得所有img
            int i = 1;
            foreach (IElement img in imgs)
            {
                img.SetAttribute("alt", "alt_" + i);//設定img的alt屬性
                i++;
            }
            //將修改後的html代碼輸出
            Console.WriteLine(document.ToHtml());
            Console.ReadKey();
        }
    }
}
※留意最後輸出的 document.ToHtml() 或是 document.DocumentElement.OuterHtml; 兩者稍有不同,請自行嘗試~
請參考:https://anglesharp.github.io/docs/Examples.html 的 Getting Single Elements
執行結果

經過我的實測,以下HTML Element解析出來會失敗
1. < img />:角括號後接續空白
2. <img alt= src="Test.jpg" />:AngleSharp看不懂 alt= src
總之HTML結構確保愈完整愈好
參考文章
How to parse HTML in .NET – Pavel Nasovich's Blog