c# - Essential Objects WebView 如何在 HTML-tree 中导航?
问题描述
我正在使用基本对象库来读取网站。
我之前使用 windows 表单 webbrowser 完成了此操作,但这次该网站无法使用 windows forms webbrowser,因此我不得不更改为 EO webView。
纪录片太差了,我找不到答案。
在windows forms webbrowser中,你有一个HtmlElementCollection,它原则上是一个HtmlElement列表。在这些元素上,您可以读出属性或创建 InvokeMember("Click") 并浏览子/父元素。
EO WebView 中这个 HtmlElementCollection / HtmlElement 的等价物是什么?如何浏览 HTML 树?
顺便说一句:我将它与 C# 一起使用。
解决方案
本质上,您必须依赖执行 JavaScript 的能力。
您可以通过以下几种方式访问文档 JavaScript 对象:
JSObject document = (JSObject)_webView.EvalScript("document");
//or: Document document = _webView.GetDOMWindow().document;
GetDOMWindow()
返回一个EO.WebBrowser.DOM.Document
实例;该类型派生自JSObject
并提供了一些额外的属性(例如,有一个body
属性可以让您获得 type 的 BODY 元素EO.WebBrowser.DOM.Element
)。
但总的来说,这些提供的 API 并没有丰富多少。
您可以像这样使用 JSObject:
// access a property on the JavaScript object:
jsObj["children"]
// access an element of an array-like JavaScript object:
var children = (JSObject)jsObj["children"];
var first = (JSObject)children[0];
// (note that you have to cast; all these have the `object` return type)
// access an attribute on the associated DOM element
jsObj.InvokeFunction("getAttribute", "class")
// etc.
这有点繁琐,但是您可以编写一些扩展方法来让您的生活更轻松(但是,请参阅下面的性能说明):
public static class JSObjectExtensions
{
public static string GetTagName(this JSObject jsObj)
{
return (jsObj["tagName"] as string ?? string.Empty).ToUpper();
}
public static string GetID(this JSObject jsObj)
{
return jsObj["id"] as string ?? string.Empty;
}
public static string GetAttribute(this JSObject jsObj, string attribute)
{
return jsObj.InvokeFunction("getAttribute", attribute) as string ?? string.Empty;
}
public static JSObject GetParent(this JSObject jsObj)
{
return jsObj["parentElement"] as JSObject;
}
public static IEnumerable<JSObject> GetChildren(this JSObject jsObj)
{
var childrenCollection = (JSObject)jsObj["children"];
int childObjectCount = (int)childrenCollection["length"];
for (int i = 0; i < childObjectCount; i++)
{
yield return (JSObject)childrenCollection[i];
}
}
// Add a few more if necessary
}
然后你可以做这样的事情:
private void TraverseElementTree(JSObject root, Action<JSObject> action)
{
action(root);
foreach(var child in root.GetChildren())
TraverseElementTree(child, action);
}
以下是如何使用此方法的示例:
TraverseElementTree(document, (currentElement) =>
{
string tagName = currentElement.GetTagName();
string id = currentElement.GetID();
if (tagName == "TD" && id.StartsWith("codetab"))
{
string elementClass = currentElement.GetAttribute("class");
// do something...
}
});
但是,再一次,这有点繁琐——虽然这似乎工作得相当好,但您需要进行一些试验以找到任何可能导致错误的棘手部分,并弄清楚如何修改该方法以使其更稳定。
性能说明
另一种选择是使用 JavaScript 进行大部分元素处理,只返回需要在 C# 代码中使用的值。根据逻辑的复杂程度,在某些情况下这可能会更有效,因为它会导致单个浏览器引擎往返,因此如果性能成为问题,则需要考虑。(请参阅此处的性能部分。)
推荐阅读
- c# - 绑定代理数据未绑定
- php - 使用日期和时间更改 PHP 时间戳,时间为 00:00:00
- python - 创建后,我可以指定或获取 Abjad (v3.2) 输出 PDF 文件的路径或名称吗?
- python - Matplotlib 和 Pandas 改变负值的颜色
- javascript - 无限滚动脚本无法识别 Jquery 事件
- r - 动画时间序列给出了带有深绿色绘图填充颜色的奇怪的中间 PNG
- mysql - MySQL中的HANDLER是如何实现的?
- haskell - 如何从目录中读取所有文件名?
- database - 如何使用 Eventbrite 的 API 将我的所有活动数据、与会者等加载到 Google 表格中?
- javascript - 如何仅使用纯 Javascript 创建像 Grammaly 这样的工具提示?