1. 使用 HtmlAgilityPack (推荐):这是一个非常强大和灵活的 HTML 解析库,它不像正则表达式那样脆弱,能够正确处理格式不规范的 HTML,并且提供了类似 XPath 的查询方式,可以精确地定位和提取你需要的元素,这是处理复杂网页结构的首选方案。

    vb.net 抓取网页中的表格
    (图片来源网络,侵删)
  2. 使用 WebBrowser 控件:这种方法模拟了用户在浏览器中的操作,它会加载整个网页,包括执行其中的 JavaScript 脚本,然后你可以像操作普通 Windows 窗体控件一样去访问 DOM 元素,这种方法适用于那些数据是动态加载(通过 JavaScript)的网页,但实现起来相对复杂。

下面我将详细介绍这两种方法,并提供完整的代码示例。


使用 HtmlAgilityPack (最常用、最推荐)

这种方法的核心思想是:下载网页的 HTML 源代码 -> 使用 HtmlAgilityPack 将其解析成一个可导航的文档树 -> 使用 XPath 定位到表格 -> 遍历表格的行和列,提取数据。

步骤 1: 安装 HtmlAgilityPack

如果你使用的是 Visual Studio,可以通过 NuGet 包管理器轻松安装。

vb.net 抓取网页中的表格
(图片来源网络,侵删)
  1. 在“解决方案资源管理器”中右键点击你的项目。
  2. 选择“管理 NuGet 程序包...”。
  3. 在“浏览”选项卡中搜索 HtmlAgilityPack
  4. 点击“安装”。

步骤 2: 编写 VB.NET 代码

以下是一个完整的示例,它从一个公开的测试网站抓取一个表格,并将数据显示在 DataGridView 控件中。

示例目标网页:我们使用一个经典的测试表格页面 http://www.w3schools.com/html/html_tables.asp 上的第一个表格。

VB.NET 代码示例

Imports System.Net
Imports System.IO
Imports HtmlAgilityPack
Public Class Form1
    Private Async Sub btnFetchTable_Click(sender As Object, e As EventArgs) Handles btnFetchTable.Click
        ' 禁用按钮,防止重复点击
        btnFetchTable.Enabled = False
        btnFetchTable.Text = "抓取中..."
        ' 使用异步方法来避免界面卡顿
        Await Task.Run(Sub()
                           Try
                               ' 1. 定义目标网页 URL
                               Dim url As String = "https://www.w3schools.com/html/html_tables.asp"
                               ' 2. 创建 WebClient 并设置 User-Agent,模拟浏览器访问
                               Using client As New WebClient()
                                   client.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3")
                                   ' 3. 下载网页 HTML 源代码
                                   Dim html As String = client.DownloadString(url)
                                   ' 4. 创建 HtmlDocument 对象并加载 HTML
                                   Dim doc As New HtmlDocument()
                                   doc.LoadHtml(html)
                                   ' 5. 使用 XPath 定位到目标表格
                                   '    通过分析网页,我们可以找到第一个表格的 XPath
                                   Dim tableNode As HtmlNode = doc.DocumentNode.SelectSingleNode("//div[@class='w3-example']/table")
                                   If tableNode IsNot Nothing Then
                                       ' 6. 解析表格数据
                                       Dim tableData As New DataTable()
                                       ' 获取表头
                                       Dim headerRow As HtmlNode = tableNode.SelectSingleNode("tr")
                                       If headerRow IsNot Nothing Then
                                           For Each headerCell As HtmlNode In headerRow.SelectNodes("th|td")
                                               tableData.Columns.Add(headerCell.InnerText.Trim())
                                           Next
                                       End If
                                       ' 获取表体数据
                                       Dim dataRows As HtmlNodeCollection = tableNode.SelectNodes("tr[position()>1]")
                                       If dataRows IsNot Nothing Then
                                           For Each dataRow As HtmlNode In dataRows
                                               Dim rowValues As New List(Of String)()
                                               For Each dataCell As HtmlNode In dataRow.SelectNodes("td|th")
                                                   rowValues.Add(dataCell.InnerText.Trim())
                                               Next
                                               If rowValues.Count = tableData.Columns.Count Then
                                                   tableData.Rows.Add(rowValues.ToArray())
                                               End If
                                           Next
                                       End If
                                       ' 7. 在 UI 线程上更新 DataGridView
                                       Me.Invoke(Sub()
                                                     DataGridView1.DataSource = tableData
                                                     DataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells)
                                                 End Sub)
                                   Else
                                       Me.Invoke(Sub()
                                                     MessageBox.Show("未找到目标表格,请检查 XPath 是否正确。")
                                                 End Sub)
                                   End If
                               End Using
                           Catch ex As Exception
                               ' 在 UI 线程上显示错误信息
                               Me.Invoke(Sub()
                                             MessageBox.Show("发生错误: " & ex.Message)
                                         End Sub)
                           Finally
                               ' 恢复按钮状态
                               Me.Invoke(Sub()
                                             btnFetchTable.Enabled = True
                                             btnFetchTable.Text = "抓取表格"
                                         End Sub)
                           End Try
                       End Sub)
    End Sub
End Class

代码解释:

  1. Imports:引入了必要的命名空间。
  2. 异步操作 (Async/Await):网络请求和 HTML 解析可能会比较耗时,放在 Task.Run 中可以防止在抓取过程中你的应用程序界面(UI)失去响应。
  3. WebClient:用于从指定 URL 下载网页内容,设置 User-Agent 可以避免被一些网站识别为爬虫而拒绝访问。
  4. HtmlDocumentHtmlAgilityPack 的核心类,用于加载和解析 HTML。
  5. SelectSingleNode / SelectNodes:这是最关键的部分,它们使用 XPath 表达式来查找节点。
    • //div[@class='w3-example']/table:这个 XPath 的意思是“在文档的任何位置,找到一个 class 属性为 w3-examplediv 元素,然后在这个 div 内部找到第一个 table 元素”,这是定位特定表格的强大方法。
    • tr[position()>1]:选择表格中所有第二个及之后的行(tr 元素),即跳过表头行。
    • th|td:选择所有的表头单元格 (th) 或普通数据单元格 (td)。
  6. DataTable:我们将解析出的数据存储在 DataTable 中,因为它可以非常方便地绑定到 DataGridView 控件。
  7. Me.Invoke:因为后台线程不能直接操作 UI 控件,所以必须使用 Invoke 方法,将更新界面的代码切换到主 UI 线程上执行。

使用 WebBrowser 控件

这种方法模拟了浏览器行为,特别适合那些数据是通过 JavaScript 动态加载的网站。

vb.net 抓取网页中的表格
(图片来源网络,侵删)

步骤 1: 添加 WebBrowser 控件

  1. 打开你的 Windows 窗体设计器。
  2. 从“工具箱”中拖拽一个 WebBrowser 控件到窗体上(可以命名为 WebBrowser1)。
  3. 再拖拽一个 Button 控件(命名为 btnLoadAndParse)和一个 DataGridView 控件。

步骤 2: 编写 VB.NET 代码

Imports System.Threading.Tasks
Public Class Form2
    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' 禁用 WebBrowser 的右键菜单和脚本错误提示
        WebBrowser1.IsWebBrowserContextMenuEnabled = False
        WebBrowser1.ScriptErrorsSuppressed = True
    End Sub
    Private Sub btnLoadAndParse_Click(sender As Object, e As EventArgs) Handles btnLoadAndParse.Click
        ' 添加事件处理程序,当网页加载完成时执行我们的解析逻辑
        AddHandler WebBrowser1.DocumentCompleted, AddressOf WebBrowser1_DocumentCompleted
        ' 导航到目标网页
        WebBrowser1.Navigate("https://www.w3schools.com/html/html_tables.asp")
    End Sub
    Private Sub WebBrowser1_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
        ' 移除事件处理程序,防止重复添加
        RemoveHandler WebBrowser1.DocumentCompleted, AddressOf WebBrowser1_DocumentCompleted
        ' 现在可以安全地访问网页的 DOM 了
        ParseTableFromWebBrowser()
    End Sub
    Private Sub ParseTableFromWebBrowser()
        Try
            ' 获取网页的文档对象
            Dim doc As HtmlDocument = WebBrowser1.Document
            ' 在 DOM 中查找表格 (这里我们使用一个简单的选择器,实际中可能需要更复杂的定位)
            ' 通过 Name 来查找是常见做法,前提是你知道表格的 ID 或 Name
            ' 假设我们不知道,就通过索引来获取第一个表格
            If doc.All.GetElementsByTagName("table").Count > 0 Then
                Dim htmlTable As HtmlElement = doc.All.GetElementsByTagName("table")(0)
                ' 创建一个 DataTable 来存储数据
                Dim tableData As New DataTable()
                ' 解析表头
                Dim headerRow As HtmlElement = htmlTable.GetElementsByTagName("tr")(0)
                For Each headerCell As HtmlElement In headerRow.GetElementsByTagName("th")
                    tableData.Columns.Add(headerCell.InnerText.Trim())
                Next
                ' 解析表体数据
                For i As Integer = 1 To htmlTable.GetElementsByTagName("tr").Count - 1
                    Dim dataRow As HtmlElement = htmlTable.GetElementsByTagName("tr")(i)
                    Dim rowValues As New List(Of String)()
                    For Each dataCell As HtmlElement In dataRow.GetElementsByTagName("td")
                        rowValues.Add(dataCell.InnerText.Trim())
                    Next
                    ' 确保行的列数与表头匹配
                    If rowValues.Count = tableData.Columns.Count Then
                        tableData.Rows.Add(rowValues.ToArray())
                    End If
                Next
                ' 绑定数据到 DataGridView
                DataGridView1.DataSource = tableData
                DataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells)
            Else
                MessageBox.Show("未在页面中找到任何表格。")
            End If
        Catch ex As Exception
            MessageBox.Show("解析时发生错误: " & ex.Message)
        End Try
    End Sub
End Class

代码解释:

  1. WebBrowser1.Navigate:开始加载指定的网页。
  2. DocumentCompleted 事件:这个事件在网页及其所有资源(如图片、脚本)加载完毕后触发,这是执行我们解析逻辑的最佳时机。
  3. WebBrowser1.Document:获取一个代表当前已加载网页的 HtmlDocument 对象,这个对象的结构和你在 JavaScript 中访问 document 对象非常相似。
  4. GetElementsByTagName("table"):获取页面中所有的 table 元素,我们这里取第一个 (0) 作为示例。
  5. 遍历 trtd:与 HtmlAgilityPack 的逻辑类似,我们逐行逐列地读取数据并填充到 DataTable 中。

总结与对比

特性 HtmlAgilityPack WebBrowser 控件
工作原理 解析静态 HTML 源码 模拟浏览器,渲染完整页面并执行 JS
性能 ,无需加载资源,不执行 JS ,需要完整加载页面和执行 JS
适用场景 静态网页,或数据最终在 HTML 源码中可见的页面 动态网页,数据由 JavaScript 动态生成或加载
依赖 需要通过 NuGet 安装库 .NET Framework 自带控件,无需额外安装
易用性 XPath 非常强大,学习曲线稍陡 类似于 DOM 操作,对前端开发者友好
资源占用 ,会启动一个完整的浏览器进程

如何选择?

  • 首选 HtmlAgilityPack:对于 90% 的网页抓取需求,HtmlAgilityPack 都是最佳选择,它速度快、资源占用少、功能强大。
  • HtmlAgilityPack 失败时再考虑 WebBrowser:如果你发现用 HtmlAgilityPack 抓取不到数据,那很可能是数据由 JS 动态加载的,这时,你才应该使用 WebBrowser 控件来模拟真实用户访问,等待 JS 执行完毕后再抓取。

希望这个详细的教程能帮助你在 VB.NET 项目中成功抓取网页表格!