【问题标题】:How to get all applied CSS Style info from mshtml element via C#如何通过 C# 从 mshtml 元素获取所有应用的 CSS 样式信息
【发布时间】:2018-07-26 22:13:38
【问题描述】:

我正在开发一个需要解析网页并转换为另一种格式的 C# 应用程序。无需深入了解输出格式和用例等。我的问题是获取任何给定元素的计算 CSS,在这种情况下是大多数元素。我正在处理内联样式、CSS 和格式化元素(如 <strong>,<em>,<u> 等)的组合。

我目前正在将网页加载到 mshtml 并使用 IHTMLElement2 接口访问 currentStyle 对象。事实证明这太慢了。我已经对其进行了分析,并且花费了大量时间通过调用 currentStyle.XXX 来获取样式规则的值。由于我需要查询多个属性,即每个元素重复的背景颜色、字体系列、字体大小、文本对齐、文本装饰等,我正在执行数千次 COM 调用,并且需要几分钟的时间文档。所有现代浏览器都在几分之一秒内做到这一点。我想这是杀死我的 COM 互操作?

有没有更好的方法? 我想一次性获得所有适用于元素的计算样式规则。 有人知道如何使用 IHTMLElementAppliedStyles 吗?它做我正在寻找的东西吗?你从哪里得到它的实例?旁注:我正在引用 HTML 对象库来获取 mshtml,但它似乎不是 IE9/10 版本???并非所有接口都可用,即 IHTMLDocument7

谢谢,

【问题讨论】:

    标签: c# html css


    【解决方案1】:

    我一直在努力,并有一些更新......

    a) 我在代码中有一个错误,它会返回树以将 80% 或 1.2em 之类的相对值解析为 pt 等绝对值之类的绝对值,该修复导致速度大幅提升。它对我来说仍然有点太慢,对于相当于 3 页的 word 文档(包括表格和有序列表等)来说,它需要 20~30 秒。

    b) 我为缓存 CSS 值的 IHTMLElement2 添加了一个 C# 包装类,因此我至少只需通过 COM 互操作每个 Dom 节点读取一次它们。这有点帮助,所以对于相同的 3 页 word doc 等效 html,我现在缩短到 8 到 10 秒。

    c) 我正在考虑为 IHTMLElement 创建一个 C++ 包装器,它将所有 CSS 值加载到一个数组中,并通过单个 COM 互操作调用传递整个数组,但到目前为止,C++ 和 COM 包装器看起来像是一条陡峭的学习曲线: MFC, ATL, COM, oh my.

    d) 因为我没有 C++ 经验并且包装器的想法看起来非常具有挑战性,我正在考虑构建一个 C# css 解析器和解析器,所以我可以转储 mshtml 并使用 htmlagilitypack + 我的 css 解析器/解析器。也是一项大工作。

    期待cmets,指导,解答 谢谢。

    【讨论】:

      【解决方案2】:

      (对于最初的提问者来说可能为时已晚,但希望对后来出现的人有用。)

      使用IHTMLWindow7::getComputedStyle(IHTMLDOMNode node) 会返回一个实时的IHTMLCSSStyleDeclaration 对象,该对象会在考虑所有规则和内联样式(包括浏览器默认样式(例如赋予<strong> 较重的字体重量)后给出完全计算的样式。

      如果您想绑定到特定属性,例如backgroundColor,可以直接在IHTMLCSSStyleDeclarationIHTMLCSSStyleDeclaration2 等上使用它们。或者,您可以使用IHTMLCSSStyleDeclaration::getPropertyValue(string name) 按名称访问特定属性。要获取元素上定义的所有名称的列表,请使用 lengthitem 属性。

      需要注意的是IHTMLWindow7IHTMLCSSStyleDeclaration* 接口未在mshtml 的主互操作程序集中声明,因此默认情况下它们不能以强绑定方式使用。因此,您既可以动态访问它们,也可以创建一个自定义互操作程序集来提供对它们的访问。

      为 mshtml 创建自定义互操作程序集 (IA) 并不难,但默认情况下,.NET 成员定义通常并不理想,而且程序集很大。如果您不介意,请在您的 PC 上找到 mshtml.tlb 并从 VS 开发人员提示符下运行它:

      tlbimp mshtml.tlb /out:"custommshtml.dll" /namespace:"custommshtml" /transform:dispret /asmversion:"1.0.0.0" /tlbreference:"C:\Windows\System32\stdole2.tlb" /nologo /silence:3001 /silence:3002
      

      这会为您安装的 IE 版本生成一个 IA。您会收到一些警告,只要您不打算使用这些成员,就可以忽略这些警告。根据需要进行调整,但不要使用mshtml作为命名空间——这会让事情非常混乱。

      在您的项目中,引用您的 IA 而不是 mshtml。您需要调整 using 语句和诸如此类的东西以使用不同的命名空间。根据原始 DOM 对象的来源,您可能会发现它们在 mshtml 命名空间中有一个类型。没关系;您仍然可以使用自定义界面。此外,在调试即时窗口期间,可能会声称某些方法/属性不存在,即使它们出现在 IntelliSense 中——这只是因为它们没有在项目中被引用,因此编译器没有嵌入所需的定义。

      【讨论】:

      • 谢谢 Emdot,是的,为时已晚,但如果我们有机会重构,这些信息对我来说仍然很有价值。
      猜你喜欢
      • 2022-09-22
      • 2011-07-14
      • 2018-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-01
      • 2020-05-07
      • 1970-01-01
      相关资源
      最近更新 更多