目錄
- 簡介
- 獲取 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 得到:
分析程式碼中的 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 常用操作程式碼