C#爬取動態網頁上的資訊:B站主頁

二次元攻城狮發表於2024-09-27

目錄
  • 簡介
  • 獲取 HTML 文件
  • 解析 HTML 文件
  • 測試
  • 參考文章

簡介

動態內容網站使用 JavaScript 指令碼動態檢索和渲染資料,爬取資訊時需要模擬瀏覽器行為,否則獲取到的原始碼基本是空的。爬取步驟如下:

  • 使用 Selenium 獲取渲染後的 HTML 文件
  • 使用 HtmlAgilityPack 解析 HTML 文件

新建專案,安裝需要的庫:

  • Selenium.WebDriver
  • HtmlAgilityPack

獲取 HTML 文件

需要注意的主要是以下2點:

  • 設定瀏覽器啟動引數:無頭模式、禁用GPU加速、設定啟動時視窗大小
  • 等待頁面動態載入完成:等待5秒鐘,設定一個合適的時間即可
private static string GetHtml(string url)
{
    ChromeOptions options = new ChromeOptions();
    // 不顯示瀏覽器
    options.AddArgument("--headless");
    // GPU加速可能會導致Chrome出現黑屏及CPU佔用率過高
    options.AddArgument("--nogpu");
    // 設定chrome啟動時size大小
    options.AddArgument("--window-size=10,10");

    using (var driver = new ChromeDriver(options))
    {
        try
        {
            driver.Manage().Window.Minimize();
            driver.Navigate().GoToUrl(url);
            // 等待頁面動態載入完成
            Thread.Sleep(5000);
            // 返回頁面原始碼
            return driver.PageSource;
        }
        catch (NoSuchElementException)
        {
            Console.WriteLine("找不到該元素");
            return string.Empty;
        }
    }
}

解析 HTML 文件

這裡以B站為例,爬取B站UP主主頁上的影片資訊,如影片的標題、連結、封面。
先定義一個類來儲存資訊:

class VideoInfo
{
    public string Title { get; set; }
    public string Href { get; set; }
    public string ImgUrl { get; set; }
}

定義解析函式,返回影片資訊列表:

private static List<VideoInfo> GetVideoInfos(string url)
{
    List<VideoInfo> videoInfos = new List<VideoInfo>();

    // 載入文件
    var html = GetHtml(url);
    var htmlDoc = new HtmlDocument();
    htmlDoc.LoadHtml(html);

    // 解析文件,先定位到影片列表標籤
    var xpath = "/html/body/div[2]/div[4]/div/div/div[1]/div[2]/div/div";
    var htmlNodes = htmlDoc.DocumentNode.SelectNodes(xpath);

    // 迴圈解析它的子節點影片資訊
    foreach (var node in htmlNodes)
    {
        var titleNode = node.SelectSingleNode("a[2]");
        var imgNode = node.SelectSingleNode("a[1]/div[1]/picture/source[1]");

        var title = titleNode.InnerText;
        var href = titleNode.Attributes["href"].Value.Trim('/');
        var imgUrl = imgNode.Attributes["srcset"].Value.Split('@')[0].Trim('/');

        videoInfos.Add(new VideoInfo
        {
            Title = title,
            Href = href,
            ImgUrl = imgUrl
        });
    }
    return videoInfos;
}

影片列表標籤的 XPath 路徑是透過瀏覽器除錯工具,在指定標籤上右鍵 複製完整的XPath 得到:
image

分析程式碼中的 node 節點時,html文字格式可能很亂,可以透過線上 HTML 程式碼格式化 工具格式後再進行分析。

測試

以B站UP主 星瞳_Official 為例,爬取影片資訊:

static void Main(string[] args)
{
    var url = @"https://space.bilibili.com/401315430";
    var videoInfos = GetVideoInfos(url);
    foreach (var videoInfo in videoInfos)
    {
        Console.WriteLine(videoInfo.Title);
        Console.WriteLine(videoInfo.Href);
        Console.WriteLine(videoInfo.ImgUrl);
        Console.WriteLine();
    }
    Console.ReadKey();
}

結果如下:

等一下,好妹妹
www.bilibili.com/video/BV1uyxLeJEM9
i0.hdslb.com/bfs/archive/46a15065d1b6722a04696ffaaa2235287ceaa452.jpg

一口一個?你的超甜辣椒
www.bilibili.com/video/BV1AQsDeiEn1
i0.hdslb.com/bfs/archive/d93d47d67323ee284483e963ffed34fb9884cf61.jpg

這裡只是演示爬取動態頁面的方法,如果想獲取B站UP主的影片資訊,建議直接使用 API 請求資料

參考文章

  • 使用 C#語言進行網頁抓取的終極指南
  • C# 寫個小爬蟲,實現爬取js載入後的網頁
  • Html Agility Pack 文件
  • [ 長期更新 ] C# Selenium 常用操作程式碼

相關文章