在 C# 中使用 Html Agility Pack 获取忽略脚本节点的 InnerText
Getting InnerText ignoring script node by using Html Agility Pack in C#
我有以下页面,我想从中获取来自 table 的代理服务器列表:
http://proxy-list.org/spanish/search.php?search=&country=any&type=any&port=any&ssl=any
table 中的每一行都是一个 ul 元素。我的问题是从 ul 元素获取第一个关联 class 的 li 元素是 "proxy" 时。我想获取 IP 和端口,所以我执行了一个 InnerText,但由于 li 元素有一个脚本子节点,它 returns 脚本节点的文本。
页面结构图片如下:
我使用 Html Agility Pack 和 LINQ 尝试了以下代码:
WebClient webClient = new WebClient();
string page = webClient.DownloadString("http://proxy-list.org/spanish/search.php?search=&country=any&type=any&port=any&ssl=any");
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(page);
List<List<string>> table = doc.DocumentNode.SelectSingleNode("//div[@class='table']")
.Descendants("ul")
.Where(ul => ul.Elements("li").Count() > 1)
.Select(ul => ul.Elements("li").Select(li =>
{
string result = string.Empty;
if (li.HasClass("proxy"))
{
HtmlNode liTmp = li.Clone();
liTmp.RemoveAllChildren();
result = liTmp.InnerText.Trim();
}
else
{
result = li.InnerText.Trim();
}
return result;
}).ToList()).ToList();
我可以获得一个列表,其中每个项目都是一个包含字段(Proxy、País、Tipo、Velocidad、HTTPS/SSL)的列表,但字段代理始终为空。此外,我根本没有得到 "País" 和 "Ciudad" 列。
那是因为这些值在页面加载后由 JavaScript 注入到 DOM 中。实际上 Proxy()
中的值是您要查找的内容的 Base64 表示形式。
在您上面张贴的图像中,值 MTQ4LjI0My4zNy4xMDE6NTMyODE=
解码为 148.243.37.101:53281
您提供给敏捷包的原始解析字符串仅包含 Proxy
字段...
<div class=\ "table-wrap\">\r\n
<div class=\ "table\">\r\n
<ul>\r\n
<li class=\ "proxy\">
<script type=\ "text/javascript\">
Proxy('MTM4Ljk3LjkyLjI0OTo1MzgxNg==')
</script>
</li>\r\n
<li class=\ "https\">HTTP</li>\r\n
<li class=\ "speed\">29.5kbit</li>\r\n
<li class=\ "type\">
<strong>Elite</strong>
</li>\r\n
<li class=\ "country-city\">\r\n
<div>\r\n
<span class=\ "country\" title=\ "Brazil\">
<span class=\ "country-code\">
<span class=\ "flag br\"></span>
<span class=\ "name\">BR Brasil</span>
</span>
</span>
<!--\r\n -->
<span class=\ "city\">
<span>Rondon</span>
</span>\r\n </div>\r\n </li>\r\n </ul>\r\n
<div class=\ "clear\"></div>\r\n
使用以下代码:
HttpClient client = new HttpClient();
var docResult = client.GetStringAsync("http://proxy-list.org/spanish/search.php?search=&country=any&type=any&port=any&ssl=any").Result;
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(docResult);
Regex reg = new Regex(@"Proxy\('(?<value>.*?)'\)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
var stuff = doc.DocumentNode.SelectSingleNode("//div[@class='table']")
.Descendants("li")
.Where(x => x.HasClass("proxy"))
.Select(li =>
{
return li.InnerText;
}).ToList();
foreach (var item in stuff)
{
var match = reg.Match(item);
var proxy = Encoding.Default.GetString(System.Convert.FromBase64String(match.Groups["value"].Value));
Console.WriteLine($"{item}\t\tproxy = {proxy}");
}
我得到:
我有以下页面,我想从中获取来自 table 的代理服务器列表:
http://proxy-list.org/spanish/search.php?search=&country=any&type=any&port=any&ssl=any
table 中的每一行都是一个 ul 元素。我的问题是从 ul 元素获取第一个关联 class 的 li 元素是 "proxy" 时。我想获取 IP 和端口,所以我执行了一个 InnerText,但由于 li 元素有一个脚本子节点,它 returns 脚本节点的文本。
页面结构图片如下:
我使用 Html Agility Pack 和 LINQ 尝试了以下代码:
WebClient webClient = new WebClient();
string page = webClient.DownloadString("http://proxy-list.org/spanish/search.php?search=&country=any&type=any&port=any&ssl=any");
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(page);
List<List<string>> table = doc.DocumentNode.SelectSingleNode("//div[@class='table']")
.Descendants("ul")
.Where(ul => ul.Elements("li").Count() > 1)
.Select(ul => ul.Elements("li").Select(li =>
{
string result = string.Empty;
if (li.HasClass("proxy"))
{
HtmlNode liTmp = li.Clone();
liTmp.RemoveAllChildren();
result = liTmp.InnerText.Trim();
}
else
{
result = li.InnerText.Trim();
}
return result;
}).ToList()).ToList();
我可以获得一个列表,其中每个项目都是一个包含字段(Proxy、País、Tipo、Velocidad、HTTPS/SSL)的列表,但字段代理始终为空。此外,我根本没有得到 "País" 和 "Ciudad" 列。
那是因为这些值在页面加载后由 JavaScript 注入到 DOM 中。实际上 Proxy()
中的值是您要查找的内容的 Base64 表示形式。
在您上面张贴的图像中,值 MTQ4LjI0My4zNy4xMDE6NTMyODE=
解码为 148.243.37.101:53281
您提供给敏捷包的原始解析字符串仅包含 Proxy
字段...
<div class=\ "table-wrap\">\r\n
<div class=\ "table\">\r\n
<ul>\r\n
<li class=\ "proxy\">
<script type=\ "text/javascript\">
Proxy('MTM4Ljk3LjkyLjI0OTo1MzgxNg==')
</script>
</li>\r\n
<li class=\ "https\">HTTP</li>\r\n
<li class=\ "speed\">29.5kbit</li>\r\n
<li class=\ "type\">
<strong>Elite</strong>
</li>\r\n
<li class=\ "country-city\">\r\n
<div>\r\n
<span class=\ "country\" title=\ "Brazil\">
<span class=\ "country-code\">
<span class=\ "flag br\"></span>
<span class=\ "name\">BR Brasil</span>
</span>
</span>
<!--\r\n -->
<span class=\ "city\">
<span>Rondon</span>
</span>\r\n </div>\r\n </li>\r\n </ul>\r\n
<div class=\ "clear\"></div>\r\n
使用以下代码:
HttpClient client = new HttpClient();
var docResult = client.GetStringAsync("http://proxy-list.org/spanish/search.php?search=&country=any&type=any&port=any&ssl=any").Result;
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(docResult);
Regex reg = new Regex(@"Proxy\('(?<value>.*?)'\)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
var stuff = doc.DocumentNode.SelectSingleNode("//div[@class='table']")
.Descendants("li")
.Where(x => x.HasClass("proxy"))
.Select(li =>
{
return li.InnerText;
}).ToList();
foreach (var item in stuff)
{
var match = reg.Match(item);
var proxy = Encoding.Default.GetString(System.Convert.FromBase64String(match.Groups["value"].Value));
Console.WriteLine($"{item}\t\tproxy = {proxy}");
}
我得到: