【问题标题】:HtmlAgilitypack enumerate all classesHtmlAgilitypack 枚举所有类
【发布时间】:2016-10-15 17:31:45
【问题描述】:

我一直在处理 html 并且总是使用 Regex 来获得我的结果。不过,每次我寻求帮助时,每个人都建议使用 HTML 解析器,例如 HTMLAgilitypack。

我刚刚尝试过,伙计,目前这对我来说太多了。 这就是我尝试枚举 html 代码跨度的方式

private static string _InetReadEx(string sUrl)
    {
        try
        {
            HtmlWeb website = new HtmlWeb();
            HtmlDocument htmlDoc = website.Load(sUrl);

            var allElementsWithClassFloat = htmlDoc.DocumentNode.SelectNodes("//div[contains(@class,'pid')]");
            for (int i = 0; i < allElementsWithClassFloat.Count; i++)
            {
                Console.WriteLine(allElementsWithClassFloat[i].InnerText);
            }

            return aRet;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

我收到错误Expression must evaluate to a node-set

我已上传 HTML 文件 here,因为它太大,无法添加到帖子中 我需要枚举所有包含“pid”的类。

【问题讨论】:

  • 您可以通过删除 HttpWebRequest 来缩短代码,因为 HtmlAgilityPack 可以加载 html 文件。如果您想获取所有名称为divclass attr 等于pid 的标签,请使用"//div[@class='pid']"
  • @WiktorStribiżew 我的对象引用未设置为引发的对象异常的实例。
  • @WiktorStribiżew 感谢您的提示。我修改了方法。希望做对了。
  • 这是因为该文件不包含任何div 标记,其class 属性值包含pid。请制定您需要从该文件中提取的内容。此外,为了避免使用try..catch 和这些异常,您应该检查对象是否不为空。 var allElementsWithClassFloat = htmlDoc.DocumentNode.... 然后if (allElementsWithClassFloat != null) { /*Process*/ }
  • 那么你需要"//*[contains(@class,'pid')]"。另外,如果你不需要空值,不要忘记添加if (!string.IsNullOrWhiteSpace(allElementsWithClassFloat[i].InnerText)),如果你不需要dupes,你也可以检查if (!aRet.Contains(allElementsWithClassFloat[i].InnerText))

标签: c# html regex parsing enums


【解决方案1】:

我认为你需要类似的东西

private static List<string> _InetReadEx(string sUrl)    // Returns string list
{
    var aRet = new List<string>();                      // string list var
    try
    {
        var website = new HtmlAgilityPack.HtmlWeb();    // Init the object
        var htmlDoc = website.Load(sUrl);               // Load doc from URL

        var allElementsWithClassFloat = htmlDoc.DocumentNode.SelectNodes("//*[contains(@class,'pid')]"); // Get all nodes with class value containing pid
        if (allElementsWithClassFloat != null)          // If nodes found
        {
            for (int i = 0; i < allElementsWithClassFloat.Count; i++)
            {
                if (!string.IsNullOrWhiteSpace(allElementsWithClassFloat[i].InnerText) && // if not blank/null
                    !aRet.Contains(allElementsWithClassFloat[i].InnerText)) // if not already present
                {
                    aRet.Add(allElementsWithClassFloat[i].InnerText);  // Add to result
                    Console.WriteLine(allElementsWithClassFloat[i].InnerText); // Demo line
                }
            }
        }
        return aRet;
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

XPath 是//*[contains(@class,'pid')]:

  • //* - 获取所有元素节点...
  • [contains( - 包含...
  • @class,'pid' - pid class 属性值内的子字符串
  • )] - contains 条件的结束

【讨论】:

  • 解释得很好。非常感谢您的帮助。但我有个问题。您建议删除 HttpWebRequest 因为 HtmlAgilityPack 可以做我想做的事。我确实删除了它。但是,我将有一个无限循环,我将在几毫秒内获取信息。使用 HtmlAgilityPack 直接链接有一个 HTTP 连接,每隔 hounderds 毫秒请求一次 html 页面,然后用 HtmlAgilityPack 解析它会更好吗?
  • 我没有测试使用 HAP 连续加载多个文档的性能。我认为这无关紧要,因为底层文件获取依赖于相同的 HttpWebRequest 类。您可以传递标头、设置编码等,与使用 HttpWebRequest 的方式相同。
  • 完美。非常感谢
【解决方案2】:

可能是您的 XPath 中的逗号 (,) 和右括号 ())?我觉得不对。

应该是"//div[@class='pid']",尽管这是完全匹配的。如果要在类属性值的任意位置选择包含'pid'的任何元素,可以使用"//div[contains(@class,'pid')]"

坚持使用 HtmlAgilityPack - 我经常使用它,因为网络上的大多数 HTML 都是垃圾,甚至不是有效的 XML!

【讨论】:

  • 实际上,你应该用空格填充类并搜索它以避免找到部分匹配... class="stupid" 现在也会匹配。例如。 //div[contains(concat(' ',@class,' '),' pid ')]
  • 对象引用未设置为引发对象错误的实例
  • 在哪一行?!哪个对象是空的?!您将不得不在某个时候帮助自己。
猜你喜欢
  • 1970-01-01
  • 2015-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多