Tìm kiếm


    Crawl Data (Trích xuất dữ liệu) Website với C# Phần 1


    Giới thiệu

    Crawl Data hiểu đơn giản là chúng ta đi thu thập dữ liệu từ các nguồn khác nhau trên các trang web.

    Và với thời buổi hiện tại dữ liệu là cực kì lớn, việc thu thập dữ liệu từ đó cũng ngày càng tăng. Và việc của chúng ta là làm sao thu thập được đống dữ liệu khổng lồ đó?

    Đối với các website lớn như Shoppe, Tiki, Google,... chúng ta có thể sử dụng các API do họ cung cấp để lấy dữ liệu.

    Nhưng thử đặt ví dụ bạn vào web bán hàng cụ thể là "Web bán đồng hồ" và bạn muốn lấy thông tin các sản phẩm của web đó NHƯNG khổ cái là website này không có API? Vậy phải làm sao? Bạn sẽ mở trang web lên, copy dữ liệu vào file word, excel v…v? Cách làm này thật điên rồ và giải pháp duy nhất cho chuyện này là viết một tool trích xuất dữ liệu từ website đó.

    Vậy làm sao để viết ra một tool crawl data từ website về? Thì sau đây mình sẽ hướng dẫn các bạn làm điều đó. 

    #Source Code ở cuối bài nhé

    Các chức năng

    Về chức năng của tool sẽ có 2 chức năng là:

    • - Crawl Data từ Website
    • - Lưu thông tin đã Crawl được vào Excel

    Phần mềm cần thiết

    Kiến thức cần có

    • - Kiến thức cơ bản về C#
    • - Có kiến thức cơ bản về Web (HTML, CSS)
    • - Hiểu về CSS Selector (có thể xem TẠI ĐÂY)

    Tiến hành viết Tool

    Trang web mình sẽ Crawl đó là fridayshopping.vn một website bán đồng hồ nhé các bạn.

    B1. Tạo một project Console App với Visual Code

    dasds

    Các bước tiếp theo các bạn điền tên Project rồi cứ bấm next nhé ...

    B2. Cài các Nuget cần thiết

    Bước này chúng ta sẽ tiến hành cài đặt các Nuget Packages sau:

    • - EPPlus
    • - Fizzler.Systems.HtmlAgilityPack
    • - HtmlAgilityPack
    • - Microsoft.AspNet.WebApi.Client

    Về chức năng của từng Nuget mình sẽ nói ở phần dưới

    B3. Phân tích mã nguồn HTML của Website

    Các bạn vào đường link https://fridayshopping.vn sẽ thấy giao diện như sau:

    dá
    Các bạn chú ý phần Header thấy ở đây có các bộ lọc chính gồm lọc theo Thương Hiệu, Đồng Hồ Nam, Đồng Hồ Nữ...

    Và trong phạm vi bài này mình sẽ Crawl hết tất cả đồng hồ từ 2 mục Đồng Hồ Nam và Đồng Hồ Nữ.

    Khi nhấn vào 2 đường dẫn này chúng ta thu được 2 URL sau:

    • - Đồng Hồ Nam: https://fridayshopping.vn/kieu-dang/nam
    • - Đồng Hồ Nữ: https://fridayshopping.vn/kieu-dang/nu

    Chúng ta thấy 2 phần hiển thị danh sách các sản phẩm hoàn toàn giống nhau. Chỉ có URL của chúng là khác nhau một chút, một cái là nam một cái là nu.

    Các bạn kéo xuống cuối trang sẽ thấy phần phân trang của sản phẩm.

    321312

    Đối với Đồng Hồ Nam có 6 trang, Đồng Hồ Nữ có 5 trang.

    Thử click vào trang thứ 2 chúng ta sẽ thu về được một URL có dạng sau:

    • - Đồng Hồ Nam: https://fridayshopping.vn/kieu-dang/nam/page/2
    • - Đồng Hồ Nữ: https://fridayshopping.vn/kieu-dang/nu/page/2

    Từ đây suy ra để có thể Crawl hết các sản phẩm của shop ta sẽ Crawl ở các URL:

    • https://fridayshopping.vn/kieu-dang/nam/page/ + số trang
    • https://fridayshopping.vn/kieu-dang/nu/page/ + số trang

    Bắt đầu xem HTML của trang. Ở đây mình sẽ Crawl các thông tin của sản phẩm bao gồm: 

    • - Tên Sản Phẩm (Product Name)
    • - Giới Tính (Gender)
    • - Giá Gốc (Orgin Price)
    • - Giá Khuyến Mãi (Discount Price)
    • - Tiền Tệ (Currency)
    • - Link Sản Phẩm (Link Detail)

    Sử dụng Developer Tool của Chrome (Nhấn F12). Các bạn sẽ thấy tất cả các sản phẩm đều nằm trong thẻ div với class là shop-container => div class = products và các sản thông tin của sản phẩm nằm trong thẻ div có class là product-small

    đasa

    Và tất cả các thông tin của sản phẩm chúng ta muốn Crawl về đều nằm trong này cụ thể:

    • - Tên Sản Phẩm: div class=title-wrapper
    • - Giới Tính (Gender): không có trong HTML nhưng sẽ lấy theo parameter trên URL :D
    • - Giá Gốc (Orgin Price): div class=price-wrapper => span class=price
    • - Giá Khuyến Mãi (Discount Price): div class=price-wrapper => span class=price
    • - Tiền Tệ (Currency): mặc định là VND
    • - Link Sản Phẩm (Link Detail): div class=title-wrapper => p class=name => a

    B4Parse dữ liệu

    Trước khi code, mình xin giới thiệu 1 số object, method của các Nuget đã cài ở trên mà các bạn nên biết:

    1. HtmlAgilityPack

    Đây là Nuget chính để lấy thông tin từ Website để Crawl

    • - 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.
    • - HTMLNodeHTMLNode 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 …)
      • - InnerText: Trả về tất cả các chuỗi được hiển thị trong Node.
      • - InnerHTML: Trả về mã HTML bên trong phần tử hiện tại. Đoạn mã HTML này là chuỗi kí tự chứa tất cả phần tử bên trong, bao gồm các nút phần tử và nút văn bản.
      • OuterHTML: Trả về mã HTML của phần tử hiện tại. Nói cách khác, outerHTML = tagName + innerHTML.
      • - 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.

    2. Fizzler.Systems.HtmlAgilityPack

    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.

    Fizzler hỗ trợ CSS Selector, cho phép ta sử dụng selector của CSS để select Node cho HTMLAgilityPath. Cho các bạn nào chưa biết về CSS Selector có thể VÀO ĐÂY để đọc thêm nhé.

    3. EPPlus

    Nuget hỗ trợ đọc xuất file trong C#

    OK. Sau khi đã hiểu được phần trên (Không hiểu cũng không sao đọc code dễ hiểu hơn 😂) chúng ta vào Code chính nào:

    // URL website need to crawl
    // Đường dẫn trang web cần crawl
    const string baseUrl = "https://fridayshopping.vn";
    
    // Create new instance
    // Tạo một instance mới
    var web = new HtmlWeb()
    {
        AutoDetectEncoding = false,
        OverrideEncoding = Encoding.UTF8
    };
    
    // List gender for product
    // List giới tính cho 2 site Đồng Hồ Nữ và Đồng Hồ Nam
    var genders = new List() { "nam", "nu" };
    
    // List product crawl
    // List lưu danh sách các sản phẩm Crawl được
    var listDataExport = new List();
    
    // Loop for 2 gender 
    // Lặp List gender
    foreach (var gender in genders)
    {
        var requestUrl = baseUrl + $"/kieu-dang/{gender}";
    
        // Load HTML to document from requestUrl
        // Load trang web, nạp html vào document từ requestUrl
        var documentForGetTotalPageMale = web.Load(requestUrl);
    
        // Get total page from requestUrl
        // Lấy tổng số trang từ requestUrl
        var textTotalPage = documentForGetTotalPageMale
            .DocumentNode
            .QuerySelectorAll(".page-numbers > li")
            .ToList()
            .Where(s => !string.IsNullOrEmpty(s.InnerText))
            .ToList()
            .Last()
            .InnerText
            .RemoveBreakLineTab();
    
        int totalPage;
        int.TryParse(textTotalPage, out totalPage);
    
        // Loop each page
        // Lặp qua từng trang
        for (var i = 1; i <= totalPage; i++)
        {
            var requestPerPage = baseUrl + $"/{gender}/page/{i}";
    
            // Load HTML to document from requestPerPage
            // Load trang web, nạp html vào document từ requestPerPage
            var documentForListItem = web.Load(requestPerPage);
    
            // Get all Node Product
            // Lấy tất cả các Node chứa thông tin của sản phẩm
            var listNodeProductItem = documentForListItem
                .DocumentNode
                .QuerySelectorAll("div.shop-container " +
                                  "> div.products " +
                                  "> div.product-small " +
                                  "> div.col-inner " +
                                  "> div.product-small " +
                                  "> div.box-text")
                .ToList();
    
            // Loop for each Node
            // Lặp qua các Node
            foreach (var node in listNodeProductItem)
            {
                // Get Link Detail of Product
                // Lấy Link chi tiết của sản phẩm
                var linkDetail = node
                    .QuerySelector("div.title-wrapper > p.name > a")
                    .Attributes["href"]
                    .Value
                    .RemoveBreakLineTab();
    
                // Get Product Name
                // Lấy tên của sản phẩm
                var productName = node
                    .QuerySelector("div.title-wrapper")
                    .InnerText
                    .RemoveBreakLineTab();
    
                // Get Product Price includes Orgin Price and Discount Price
                // Lấy giá của sản phẩm bao gồm giá gốc và giá khuyển mãi
                var priceText = node
                    .QuerySelector("div.price-wrapper > span.price")
                    .InnerText
                    .RemoveBreakLineTab()
                    .ReplaceMultiToEmpty(new List() { "₫", "," });
    
                var priceList = priceText?.Split(" ").ToList();
    
                // Parse text to price and format
                var orginPrice = priceList?.Count > 0 ? double.Parse(priceList[0]).ToString("N2") : 0.ToString("N2");
                var discountPrice = priceList?.Count > 0 ? double.Parse(priceList[1]).ToString("N2") : 0.ToString("N2");
    
                // Add Product to listDataExport
                // Thêm sản phẩm vào listDataExport
                listDataExport.Add(new ProductModel()
                {
                    ProductName = productName,
                    Gender = gender.Equals("nam") ? "Nam" : "Nữ",
                    Currency = "VND",
                    DiscountPrice = discountPrice,
                    OrginPrice = orginPrice,
                    LinkDetail = linkDetail,
                    Author = "https://www.code-mega.com"
                });
            }
        }
    }
    
    // Export data to Excel
    ExportToExcel.GenerateExcel(listDataExport, savePathExcel + fileName, "Code Mega");

    Kết quả

    Và đây là kết quả được lưu lại sau khi Crawl xong. Ở đây mình lưu vào Excel, các bạn cũng có thể lưu xuống bất kì đâu bạn muốn như Database
    đá

    Vậy là xong rồi. Bạn cũng có thể sử dụng thư viện này để Crawl Data từ các trang web khác mà bạn muốn. Lưu ý là thư viện này sẽ không áp dụng được cho các web sử dụng JS để chạy Front End như React, Angular, VueJS,...

    Hi vọng bài viết này có thể giúp ích được cho các bạn!

    #Note: Phần sau mình sẽ mở rộng Tool này ra để Crawl Full thông tin của sản phẩm như Hình Ảnh, các thông tin trong trang Detail, Lưu xuống Database .... Các bạn nhớ theo dõi nhá!


    Tiểu sử
    Are you one or zero?


    Bình luận