【问题标题】:HtmlAgilityPack: How to check if an element is visible?HtmlAgilityPack:如何检查元素是否可见?
【发布时间】:2013-02-08 16:16:26
【问题描述】:

我正在做一些 HTML 解析,我正在使用 HtmlAgilityPack,我正在尝试检查如果在浏览器中呈现 html,节点元素是否可见。

通过可见,我可能对检查 displayvisibility 样式值感到满意。 (除非我还有其他需要担心的事情?)。

那么,我该怎么做呢?有没有简单的方法?我可以使用一些 XPath 魔法吗? (目前我对 XPath 的了解不多)。

我曾考虑过手动解析样式值,但宁愿将其保存为最后的手段。还是这是我唯一的选择?

仅供参考,我正在使用的对象是这样的:

HtmlAgilityPack.HtmlNode node = GetNode();

【问题讨论】:

  • 这不太可行。可见性可以由级联样式(和 X/Y 定位)决定,为此您基本上需要一个完整的 DOM/CSS 解析器和实现(即浏览器)来计算。 (此外,Javascript 也可以操纵可见性)
  • @KirkWoll:好点。但是,Javascript 在这里不是一个因素,而 Html 实际上是通过将 XSLT 应用于 XML 文件而生成的。但我听到你说的关于 css 文件的内容,可能需要一两把扳手
  • @musefan 不是一件容易的事(一点也不)。这里有很多因素需要考虑。例如,它可能位于隐藏容器内(如您所说),或者元素的位置可能是负数(因此它不会出现在屏幕上)。一些爬虫[需要引用]这样做是为了避免作弊等。

标签: c# html-agility-pack


【解决方案1】:

好的,所以我已经设法做到了,至少满足我的需要。但是请注意,正如其他 cmets 所说,这不允许您检查元素是否对最终用户可见(在屏幕上)。

我采取的方法简单检查了一些基本规则:如果元素的样式属性包含display:nonevisibility:hidden,则元素“不可见”,或者祖先元素具有相同的样式规则。

考虑到这一点,下面是我的代码,可以为我完成这项工作:

private static bool IsNodeVisible(HtmlAgilityPack.HtmlNode node)
{
    var attribute = node.Attributes["style"];

    bool thisVisible = false;

    if (attribute == null || CheckStyleVisibility(attribute.Value))
        thisVisible = true;

    if (thisVisible && node.ParentNode != null)
        return IsNodeVisible(node.ParentNode);

    return thisVisible;
}

private static bool CheckStyleVisibility(string style)
{
    if (string.IsNullOrWhiteSpace(style))
        return true;

    var keys = ParseHtmlStyleString(style);

    if (keys.Keys.Contains("display"))
    {
        string display = keys["display"];
        if (display != null && display == "none")
            return false;
    }

    if (keys.Keys.Contains("visibility"))
    {
        string visibility = keys["visibility"];
        if (visibility != null && visibility == "hidden")
            return false;
    }

    return true;
}

public static Dictionary<string, string> ParseHtmlStyleString(string style)
{
    Dictionary<string, string> result = new Dictionary<string, string>();

    style = style.Replace(" ", "").ToLowerInvariant();

    string[] settings = style.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

    foreach (string s in settings)
    {
        if (!s.Contains(':'))
            continue;
        string[] data = s.Split(':');
        result.Add(data[0], data[1]);
    }

    return result;
}

这个入口点是IsNodeVisible,它将检查传递给它的HtmlNode 的可见性。

【讨论】:

  • 它的父级也可能不可见 = 使不可见
  • @MonsterMMORPG:我不确定你想说什么,但我的代码确实检查了所有父/祖先节点的可见性
  • 是的,我后来看到了。但是,当它具有隐藏对象的类时,这仍然不起作用:)
  • 没错,当时我的需求非常基本。我想你也可以解析 CSS 文件并搜索任何匹配的类。虽然这是一个很大的开销......但是你必须做你必须做的事情......即使你有半复杂的 CSS 选择器,也很难做到正确
猜你喜欢
  • 2017-01-01
  • 2012-07-08
  • 2014-04-22
  • 2020-08-06
  • 2012-04-21
  • 2011-02-08
  • 2010-10-03
  • 2023-03-04
  • 1970-01-01
相关资源
最近更新 更多