通过在C#中使用Html Agility Pack使InnerText忽略脚本节点

时间:2018-05-20 01:09:50

标签: c# html-parsing html-agility-pack

我有以下页面,我想从表中获取代理服务器列表:

  

http://proxy-list.org/spanish/search.php?search=&country=any&type=any&port=any&ssl=any

表中的每一行都是一个ul元素。我的问题是从ul元素获取关联类是“proxy”的第一个li元素。我想获取IP和端口,所以我执行一个InnerText,但由于li元素有一个脚本子节点,它返回脚本节点的文本。

在页面结构的图像下方:

enter image description here

我使用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”栏目。

1 个答案:

答案 0 :(得分:1)

这是因为在页面加载后,这些值会被JavaScript注入到DOM中。实际上Proxy()中的值是您正在寻找的Base64表示。

在上面发布的图片中,MTQ4LjI0My4zNy4xMDE6NTMyODE=值解码为148.243.37.101:53281

您要向Agility包提供的原始解析字符串仅包含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}");
        }

我得到: enter image description here