C#如何从WebBrowser控件选中内容提取HTML表格或解析表格数据
问题背景
使用WinForms的WebBrowser控件加载SEC财报表格页面(如指定的EDGAR页面),需实现用户选中表格数据后,解析并展示到DataGridView中。目前通过纯文本提取选中内容,但纯文本结构丢失,解析难度大且易出错,需解决两个核心需求:
- 获取选中内容的原始HTML,替代纯文本
- 更可靠的选中表格数据解析方案
现有纯文本提取代码
private string GetSelectedText() { dynamic document = webBrowser1.Document.DomDocument; dynamic selection = document.selection; dynamic text = selection.createRange().text; return (string)text; }
解决方案
方案一:获取WebBrowser选中内容的HTML
利用IE DOM API直接获取选中区域的HTML,保留表格的结构标签(<table>/<tr>/<td>等),代码如下:
private string GetSelectedHtml() { if (webBrowser1.Document == null) return string.Empty; dynamic document = webBrowser1.Document.DomDocument; dynamic selection = document.selection; if (selection == null || selection.type != "Text") return string.Empty; dynamic range = selection.createRange(); return range.htmlText; // 提取选中区域的完整HTML }
方案二:基于HTML的表格解析优化方案
拿到选中的HTML后,使用HtmlAgilityPack(NuGet可直接安装)解析表格结构,转换为DataTable后绑定到DataGridView,步骤如下:
1. 解析HTML到DataTable
private DataTable ParseSelectedHtmlToDataTable(string selectedHtml) { DataTable dt = new DataTable(); HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(selectedHtml); // 定位选中区域内的表格(支持多表格,此处取第一个,可按需调整) HtmlNode table = doc.DocumentNode.SelectSingleNode("//table"); if (table == null) return dt; // 提取表头 HtmlNodeCollection headerRows = table.SelectNodes(".//tr[th]"); if (headerRows != null && headerRows.Count > 0) { foreach (HtmlNode th in headerRows[0].SelectNodes(".//th")) { dt.Columns.Add(HtmlEntity.DeEntitize(th.InnerText.Trim())); } } // 无表头时自动生成列名 else if (dt.Columns.Count == 0) { HtmlNodeCollection firstDataCells = table.SelectNodes(".//tr[td]")[0].SelectNodes(".//td"); for (int i = 0; i < firstDataCells.Count; i++) { dt.Columns.Add($"列_{i+1}"); } } // 提取数据行 HtmlNodeCollection dataRows = table.SelectNodes(".//tr[td]"); if (dataRows != null) { foreach (HtmlNode row in dataRows) { HtmlNodeCollection cells = row.SelectNodes(".//td"); if (cells != null && cells.Count == dt.Columns.Count) { DataRow dr = dt.NewRow(); for (int i = 0; i < cells.Count; i++) { dr[i] = HtmlEntity.DeEntitize(cells[i].InnerText.Trim()); } dt.Rows.Add(dr); } } } return dt; }
2. 绑定到DataGridView
private void btnParse_Click(object sender, EventArgs e) { string selectedHtml = GetSelectedHtml(); if (string.IsNullOrEmpty(selectedHtml)) { MessageBox.Show("请先选中表格内容"); return; } DataTable dt = ParseSelectedHtmlToDataTable(selectedHtml); dgv.DataSource = dt; dgv.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); // 自动调整列宽 }
3. SEC财报表格特殊处理(合并单元格)
SEC财报常存在colspan/rowspan合并单元格,可添加如下简化处理逻辑:
// 解析数据行时加入合并单元格处理 foreach (HtmlNode row in dataRows) { DataRow dr = dt.NewRow(); HtmlNodeCollection cells = row.SelectNodes(".//td"); if (cells == null) continue; int colIndex = 0; foreach (HtmlNode cell in cells) { // 处理列合并 int colspan = int.TryParse(cell.GetAttributeValue("colspan", "1"), out int c) ? c : 1; // 处理行合并(需额外存储跨多行的内容,可通过字典记录) int rowspan = int.TryParse(cell.GetAttributeValue("rowspan", "1"), out int r) ? r : 1; string cellText = HtmlEntity.DeEntitize(cell.InnerText.Trim()); for (int i = 0; i < colspan; i++) { if (colIndex + i < dt.Columns.Count) { dr[colIndex + i] = cellText; // 若rowspan>1,可将内容存入临时字典,后续行填充时读取 // rowspanDict.Add((currentRowIndex + 1, colIndex + i), cellText); } } colIndex += colspan; } dt.Rows.Add(dr); }
内容的提问来源于stack exchange,提问作者Sankar
相关产品推荐
相关产品推荐

