2

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

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

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

谢谢,

4

2 回答 2

0

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

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,哦,我的。

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

期待评论,指导,答案谢谢。

于 2013-05-31T23:22:31.957 回答
0

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

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

如果您想绑定到特定属性,例如backgroundColor它们可以直接在IHTMLCSSStyleDeclaration,IHTMLCSSStyleDeclaration2等上使用。或者,您可以通过名称访问特定属性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 中——这只是因为它们没有在项目中被引用,因此编译器没有嵌入所需的定义。

于 2018-07-26T14:13:38.070 回答