如何用C#与Html Agility Pack解析网页表格并提取指定字段?
解决方案
兄弟,你碰到的doc里找不到目标表格的问题,多半是网站拦截了默认WebClient的请求(比如检查请求头里的User-Agent),返回的内容不是完整的页面。先把请求部分修复好,再用LINQ解析表格数据就没问题了。
1. 完善WebClient请求,拿到完整页面
默认的WebClient没设置模拟浏览器的请求头,很多网站会把它当成爬虫,返回简化甚至空白的内容。我们给它加上必要的请求头:
using System.Net; using HtmlAgilityPack; using (WebClient webClient = new WebClient()) { // 模拟Chrome浏览器的请求头,让网站认为是正常用户访问 webClient.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"); webClient.Headers.Add(HttpRequestHeader.Accept, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"); webClient.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-US,en;q=0.5"); string page = webClient.DownloadString("http://www.freeproxylists.net/?c=&pt=&pr=HTTP&a%5B%5D=1&a%5B%5D=2&u=40"); HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument(); doc.LoadHtml(page); // 接下来解析表格 }
2. 用LINQ解析表格为嵌套列表
这个网站的代理数据在class="DataGrid"的表格里,表头正好对应你需要的字段。我们用LINQ跳过表头行,提取每行的单元格内容:
// 定位目标表格 var targetTable = doc.DocumentNode.SelectSingleNode("//table[@class='DataGrid']"); if (targetTable == null) { MessageBox.Show("没找到目标代理表格,请检查请求是否正常"); return; } // 用LINQ将表格行转为嵌套列表 var proxyDataList = targetTable.SelectNodes(".//tr") .Skip(1) // 跳过第一行表头 .Where(row => row.SelectNodes(".//td").Count >= 8) // 确保每行有足够的单元格,避免索引越界 .Select(row => { var cells = row.SelectNodes(".//td"); return new List<string> { cells[0].InnerText.Trim(), // IP Address cells[1].InnerText.Trim(), // Port cells[2].InnerText.Trim(), // Protocol cells[3].InnerText.Trim(), // Anonymity cells[4].InnerText.Trim(), // Country cells[5].InnerText.Trim(), // Region cells[6].InnerText.Trim(), // City cells[7].InnerText.Trim() // Uptime }; }) .ToList(); // 测试输出,验证数据是否正确 foreach (var proxy in proxyDataList) { Console.WriteLine($"IP: {proxy[0]} | Port: {proxy[1]} | 匿名度: {proxy[3]}"); }
额外小贴士
- 如果还是拿不到表格,那可能网站用了JS动态加载数据,这时候就得换Selenium这类工具模拟浏览器加载页面了。不过目前这个网站的第一页数据是静态的,加对请求头就能解决。
- 别频繁请求网站,容易被封IP,记得加个请求间隔。
- 其实用实体类存储数据比嵌套列表更方便维护,比如定义个
ProxyInfo类:
public class ProxyInfo { public string IpAddress { get; set; } public string Port { get; set; } public string Protocol { get; set; } public string Anonymity { get; set; } public string Country { get; set; } public string Region { get; set; } public string City { get; set; } public string Uptime { get; set; } }
然后LINQ里返回new ProxyInfo { IpAddress = cells[0].InnerText.Trim(), ... },代码可读性会高很多。
内容的提问来源于stack exchange,提问作者Willy
相关产品推荐
相关产品推荐

