Hướng dẫn fizzler systems htmlagilitypack - hệ thống fizzler htmlagilitypack

Fizzler là một bộ chọn phân tích chọn lọc W3C và khung chọn chung cho phân cấp tài liệu. Gói này cho phép Fizzler trên HTMLagilityPack, thêm QuerySelector và QuerySelectorall (từ các bộ chọn API cấp 1) cho các đối tượng HTMLNode.

Sản phẩmPhiên bản
.MẠNG LƯỚI net5.0net5.0-windowsnet6.0net6.0-androidnet6.0-iosnet6.0-maccatalystnet6.0-macosnet6.0-tvosnet6.0-windows net5.0-windows net6.0 net6.0-android net6.0-ios net6.0-maccatalyst net6.0-macos net6.0-tvos net6.0-windows
.NET Core netcoreapp1.0netcoreapp1.1netcoreapp2.0netcoreapp2.1netcoreapp2.2netcoreapp3.0netcoreapp3.1 netcoreapp1.1 netcoreapp2.0 netcoreapp2.1 netcoreapp2.2 netcoreapp3.0 netcoreapp3.1
.NET tiêu chuẩn netstandard1.3netstandard1.4netstandard1.5netstandard1.6netstandard2.0netstandard2.1 netstandard1.4 netstandard1.5 netstandard1.6 netstandard2.0 netstandard2.1
.Nền tảng NET net46net461net462net463net47net471net472net48 net461 net462 net463 net47 net471 net472 net48
Monoandroid Monoandroid
Monomac Monomac
Đơn điệu đơn điệu
Tizen tizen30tizen40tizen60 tizen40 tizen60
Nền tảng Windows Universal uapuap10.0 uap10.0
Xamarin.ios Xamarinios
Xamarin.Mac Xamarinmac
Xamarin.tvos Xamarintvos
Xamarin.Watchos Xamarinwatchos

  • .Netstandard 1.3

    • Fizzler (> = 1.2.0)(>= 1.2.0)
    • Htmlagilitypack (> = 1.5.1)(>= 1.5.1)
    • Netstandard.l Library (> = 1.6.1)(>= 1.6.1)
  • .Netstandard 2.0

    • Fizzler (> = 1.2.0)(>= 1.2.0)
    • Htmlagilitypack (> = 1.5.1)(>= 1.5.1)

Netstandard.l Library (> = 1.6.1) (27)

.Netstandard 2.0

Gói Nuget (27) Hiển thị 5 gói nuget hàng đầu phụ thuộc vào fizzler.systems.htmlagilitypack:
Bưu kiện

Tải xuống

Xtract
F# Gói quét màn hình.

52,4k

Kolodev.gds.qa.Accelerator
Kolodev Ltd. Tăng tốc QA. Gói này chứa các bộ tăng tốc giải pháp cho các nhóm thử nghiệm, cho phép selenium, khả năng truy cập, kiểm tra trình duyệt chéo và nhiều hơn nữa.

39,0k

fion.modelerp.core
Mô hình hóa

37,7k

Wikiled.news.Monitoring
Thư viện cơ sở giám sát tin tức

18.3k

JMOVIES.IMDB

Thư viện nhà cung cấp dữ liệu IMDB của JMOVIES - Hiện đang hỗ trợ quét màn hình theo yêu cầu từ IMDB để nhận chi tiết phim và người. (5)

12.3k

Kho lưu trữ GitHub (5) Hiển thị 5 kho lưu trữ github phổ biến hàng đầu phụ thuộc vào fizzler.systems.htmlagilitypack:
Kho

Sao

514
Wabbajack-tools/wabbajack

Một trình cài đặt modlist tự động cho các trò chơi khác nhau.

501
Aguafrommars/TheIdServer

OpenID/Connect, máy chủ liên kết OAuth2 và WS dựa trên Duende IdentityServer với UI quản trị viên của nó

266
aprilyush/easycms

EasyCMS 基于 asp.net Core 的 快速 开发 框架 框架 框架 框架 内容 内容 管理 系统 系统 系统 系统 系统 系统

197
Clean-Reader/CleanReader.Desktop

使用 Ứng dụng Windows SDK 构建 桌面版 干净 阅读 阅读 阅读

111

Đây là bài tutorial thứ 2 trên blog. Hiện nay, nhu cầu thu thập dữ liệu ngày càng tăng. Với một số trang như lớn như facebook, google, steam ta có thể sử dụng API do họ cung cấp để lấy dữ liệu. Trong nhiều trường hợp khác, ta thường trích xuất dự liệu bằng tay (Mở trang web lên, copy dữ liệu vào file word, excel v…v), việc này vừa cực, vừa mất nhiều thời gian và công sức

Đặt tình huống cụ thể, bạn muốn làm một ứng dụng đọc báo, lấy thông tin từ chuyên mục “Đọc báo giùm bạn” trên webtretho.com. Đây là một trang forum khá to, và dĩ nhiên là không có API để lấy dữ liệu. Ở đây, ta không thể lấy dữ liệu bằng tay được. Giải pháp duy nhất cho chuyện này là viết một phần mềm trích xuất dữ liệu từ bản thân trang webtretho.

Mình sẽ hướng dẫn các bạn trích xuất bằng thư viện HTMLAgilityPack và Fizzler. HTMLAgilityPack là một thư viện parse HTML khá mạnh, lý do nó phổ biến là vì nó “chơi” được với hầu hết html, cả valid và unvalid (Trong thực tế thì số lượng website có HTML unvalid nhiều vô số kể, các thư viện khác sẽ dễ bị lỗi, HTMLAgilityPack thì không). Kiến thức ở bài này sẽ khá hữu dụng nếu sau này bạn cần trích xuất thông tin từ website khác. Bạn có thể google thêm với từ khóa: web crawler.sẽ khá hữu dụng nếu sau này bạn cần trích xuất thông tin từ website khác. Bạn có thể google thêm với từ khóa: web crawler.sẽ khá hữu dụng nếu sau này bạn cần trích xuất thông tin từ website khác. Bạn có thể google thêm với từ khóa: web crawler.

Cùng bắt tay vào làm nhé.

Bước 1: Tạo project mới , ở đây mình tạo một project console cho đơn giản.: Tạo project mới , ở đây mình tạo một project console cho đơn giản.: Tạo project mới , ở đây mình tạo một project console cho đơn giản.

Bước 2: Vào Tools -> Library Package Manager -> Package Manager Console. Đánh câu lệnh sau để cài đặt thư viện:: Vào Tools -> Library Package Manager -> Package Manager Console. Đánh câu lệnh sau để cài đặt thư viện:: Vào Tools -> Library Package Manager -> Package Manager Console. Đánh câu lệnh sau để cài đặt thư viện:

Install-Package Fizzler.Systems.HtmlAgilityPack

Sau khi cài đặt, nếu bạn thấy có đủ 3 reference như hình dưới là ok nhé.

Bước 3: Xem xét HTML của trang cần trích xuất. Ở đây, chúng ta sẽ trích xuất tên, link tới các topic trong diễn đàn, cũng như lấy số lượng view của topic đó.: Xem xét HTML của trang cần trích xuất. Ở đây, chúng ta sẽ trích xuất tên, link tới các topic trong diễn đàn, cũng như lấy số lượng view của topic đó.: Xem xét HTML của trang cần trích xuất. Ở đây, chúng ta sẽ trích xuất tên, link tới các topic trong diễn đàn, cũng như lấy số lượng view của topic đó.

Sử dụng Developer Tool của chrome, ta sẽ thấy mỗi topic là 1 tag li, nằm trong 1 tag ul, có id là “threads.” Ta sẽ trích xuất dữ liệu từ những thẻ này. (Kinh nghiệm của mình là bạn nên chọn tag dựa theo id, nằm gần dữ liệu mình cần lấy nhất. Vì mỗi tag trong html chỉ có 1 id duy nhất, không bị trùng, ta dễ chọn tag và lọc hơn).Kinh nghiệm của mình là bạn nên chọn tag dựa theo id, nằm gần dữ liệu mình cần lấy nhất. Vì mỗi tag trong html chỉ có 1 id duy nhất, không bị trùng, ta dễ chọn tag và lọc hơn).Kinh nghiệm của mình là bạn nên chọn tag dựa theo id, nằm gần dữ liệu mình cần lấy nhất. Vì mỗi tag trong html chỉ có 1 id duy nhất, không bị trùng, ta dễ chọn tag và lọc hơn).

Vào sâu hơn, ta sẽ thấy link và tiêu đề được lưu trữ trong taga, có class là title, còn số lần đọc được lưu trữ trong tag b. Với những thông tin này, chúng ta đã có thể bắt đầu trích xuất dữ liệu

Bước 4: Bắt đầu parse dữ liệu. Trước khi viết code, mình xin giới thiệu 1 số object, method của HTML AgilityPack mà các bạn nên biết:: Bắt đầu parse dữ liệu. Trước khi viết code, mình xin giới thiệu 1 số object, method của HTML AgilityPack mà các bạn nên biết:: Bắt đầu parse dữ liệu. Trước khi viết code, mình xin giới thiệu 1 số object, method của HTML AgilityPack mà các bạn nên biết:

–HTMLDocument: Đây là một class chứ thông tin về một file html (encoding, innerhtml). Ta có thể load dữ liệu vào HTMLDocument từ 1 URL hoặc từ 1 file. Trong bài này mình sẽ load từ url của webtretho.

–HTMLNode: Một HTMLNode tương đương với một tag (li, ul, div, …) trong HTML. Node lớn nhất chứa toàn bộ tất cả sẽ là DocumentNode. Một số property của HTMLNode mà ta hay sử dụng:

  • Name: Tên của node (div, ul, li).
  • Attributes: Danh sách các attribute của note (Attribute là các thông tin của node như: src, href, id, class …)
  • InnerHTML, OuterHTML: Đọc tên là hiểu rồi nhỉ
  • SelectNodes(string xPath): Tìm các node con của node hiện hành, dựa trên xPath đưa vào.
  • SelectSingleNode(string xPath): Tìm node con đầu tiên của node hiện hành, dựa trên xPath đưa vào.
  • Descendants(string xPath): Trả ra danh sách các HTMLNode con của node hiện tại.

Đầu tiên, chúng ta sẽ sử dụng method SelectNode, sử dụng xPath để tìm node. Nếu bạn không rành, không nhớ hoặc không biết xPath thì đừng lo, phía dưới sẽ có cách khác dễ hơn.

            HtmlWeb htmlWeb = new HtmlWeb()
            {
                AutoDetectEncoding = false,
                OverrideEncoding = Encoding.UTF8  //Set UTF8 để hiển thị tiếng Việt
            };

            //Load trang web, nạp html vào document
            HtmlDocument document = htmlWeb.Load("http://www.webtretho.com/forum/f26/");

            //Load các tag li trong tag ul
            var threadItems = document.DocumentNode.SelectNodes("//ul[@id='threads']/li").ToList();

            var items = new List();
            foreach (var item in threadItems)
            {
                //Extract các giá trị từ các tag con của tag li
                var linkNode = item.SelectSingleNode(".//a[contains(@class,'title')]");
                var link = linkNode.Attributes["href"].Value;
                var text = linkNode.InnerText;
                var readCount = item.SelectSingleNode(".//div[@class='folTypPost']/ul/li/b").InnerText;

                items.Add(new { text, readCount, link });
            }

Kết quả thu được khá là ưng ý:

Nhiều bạn sẽ cảm thấy cách này hơi khó. Thú thật là mình cũng không rành xPath cho lắm, vì vậy mình cũng không khoái cách này, do đó chúng ta có thể dùng LINQ to Object để tìm note. Code tương tự sẽ được viết như sau:

            var threadItems = document.DocumentNode.Descendants("ul")
                            .First(node => node.Attributes.Contains("id") && node.Attributes["id"].Value == "threads")
                            .ChildNodes.Where(node => node.Name == "li").ToList();

            foreach (var item in threadItems)
            {
                var linkNode = item.Descendants("a").First(node =>
                node.Attributes.Contains("class") && node.Attributes["class"].Value.Contains("title"));
                var link = linkNode.Attributes["href"].Value;
                var text = linkNode.InnerText;
                var readCount = item.Descendants("b").First().InnerText;

                items.Add(new { text, readCount, link });
            }

Chắc bạn hơi thật vọng phải không. Code bây giờ đã dễ hiểu hơn, không cần xPath xPiếc gì. Tuy nhiên, code lại dài hơn, do ta phải dùng lambda expression và check null. Do một số node không có attribute class, ta phải check null trước để tránh bị lỗi NullPointerException. Còn cách nào hay hơn không nhỉ? Hãy kéo xuống dưới nhé, mình luôn để dành phần hay nhất ở dưới cùng.ta phải check null trước để tránh bị lỗi NullPointerException. Còn cách nào hay hơn không nhỉ? Hãy kéo xuống dưới nhé, mình luôn để dành phần hay nhất ở dưới cùng.ta phải check null trước để tránh bị lỗi NullPointerException. Còn cách nào hay hơn không nhỉ? Hãy kéo xuống dưới nhé, mình luôn để dành phần hay nhất ở dưới cùng.

Chú ý: Nếu bạn bỏ vế check null ra sau, hàm chạy sẽ bị lỗi, để hiểu nguyên nhân hãy xem lại bài viết về short-circuit của mình nhé. Nếu bạn bỏ vế check null ra sau, hàm chạy sẽ bị lỗi, để hiểu nguyên nhân hãy xem lại bài viết về short-circuit của mình nhé. Nếu bạn bỏ vế check null ra sau, hàm chạy sẽ bị lỗi, để hiểu nguyên nhân hãy xem lại bài viết về short-circuit của mình nhé.

Bước 5: Cải tiến với Fizzler: Cải tiến với Fizzler: Cải tiến với Fizzler

Cả 2 cách trên đều làm bạn “đầu váng, mắt hoa” ? Ok, mình cũng vậy :(. May mắn thay, còn một cách đơn giản hơn để select 1 node, đó là sử dụng Fizzler. Fizzler hỗ trợ CSS selector, cho phép ta sử dụng selector của CSS. Fizzler được mở rộng dựa trên HTMLAgilityPath, thêm 2 hàm sau vào HTMLNode: CSS selector, cho phép ta sử dụng selector của CSS. Fizzler được mở rộng dựa trên HTMLAgilityPath, thêm 2 hàm sau vào HTMLNode: CSS selector, cho phép ta sử dụng selector của CSS. Fizzler được mở rộng dựa trên HTMLAgilityPath, thêm 2 hàm sau vào HTMLNode:

+ QuerySelectorAll: Tìm các node con của node hiện hành, dựa trên css selector đưa vào.

+ QuerySelector: Tìm node con đầu tiền của node hiện hành, dựa trên css selector đưa vào.

Code bây giờ vô cùng đơn giản và dễ hiểu nhé

            var threadItems = document.DocumentNode.QuerySelectorAll("ul#threads > li").ToList();

            foreach (var item in threadItems)
            {
                var linkNode = item.QuerySelector("a.title");
                var link = linkNode.Attributes["href"].Value;
                var text = linkNode.InnerText;
                var readCount = item.QuerySelector("div.folTypPost > ul > li > b").InnerText;

                objs.Add(new { link, text, readCount });
            }

Bước 6: Xuất kết quả ra đâu đó. Tới đây mọi chuyện đã xong, bạn có thể lưu kết quả vào file database hoặc xuất ra file text tùy mục đích sử dụng.: Xuất kết quả ra đâu đó. Tới đây mọi chuyện đã xong, bạn có thể lưu kết quả vào file database hoặc xuất ra file text tùy mục đích sử dụng.: Xuất kết quả ra đâu đó. Tới đây mọi chuyện đã xong, bạn có thể lưu kết quả vào file database hoặc xuất ra file text tùy mục đích sử dụng.

Bạn cũng có thể áp dụng thư viện này để trích xuất 1 số trang web bán hàng: hotdeal, muachung, … Hi vọng bài viết này sẽ có ích cho sự nghiệp lập trình của các bạn.