有没有办法使用 C# 中的 Windows 窗体应用程序获取突出显示文本的 Xpath 位置
本文关键字:获取 显示 文本 位置 Xpath 应用程序 窗体 Windows 中的 有没有 | 更新日期: 2023-09-27 18:30:47
我正在尝试使用Windows表单应用程序创建一个网络抓取工具。是否有 API 或方法来显示所选文本的确切 xpath 位置?到目前为止,我已经编写了代码,允许我在 Web 浏览器控件中突出显示导航网站上的文本,并使用 ContextMenuStrip 将此突出显示的文本输出到富文本框中。
我在下面编写的代码是:
private void getSelectedTextToolStripMenuItem_Click(object sender, EventArgs e)
{
IHTMLDocument2 htmlDocument = webBrowser1.Document.DomDocument as IHTMLDocument2;
IHTMLSelectionObject currentSelection = htmlDocument.selection;
if (currentSelection != null)
{
IHTMLTxtRange range = currentSelection.createRange() as IHTMLTxtRange;
if (range != null)
{
richTextBox1.Text = range.htmlText;
}
该按钮将导航到以下网站:
private void button1_Click(object sender, EventArgs e)
{
this.webBrowser1.Navigate("https://uk.finance.yahoo.com/q?s=%5EFTSE");
webBrowser1.DocumentCompleted +=
webBrowser1_DocumentCompleted;
}
到目前为止,它完全符合我想要它做的事情。但是,我现在希望获得突出显示的任何内容的 xpath 位置,而不仅仅是输出文本内容。这个想法是,如果我想提取实时数据(即雅虎财经网页上的市场数据),网站上的数据会不断变化,所以我有兴趣在 html 页面结构中获得位置。关于这是否可能以及我应该遵循哪些步骤的任何想法?
这是可能的,但您必须自己构建 XPath,方法是从所选元素向上移动层次结构,执行以下操作:
private void getSelectedXPathToolStripMenuItem_Click(object sender, EventArgs e)
{
var doc = (IHTMLDocument2)webBrowser1.Document.DomDocument;
IHTMLElement selectedElement = null;
var sel = doc.selection;
if (sel.type == "Text")
selectedElement = ((IHTMLTxtRange)sel.createRange()).parentElement();
else if (sel.type == "Control")
selectedElement = ((IHTMLControlRange)sel.createRange()).commonParentElement();
var node = (IHTMLDOMNode)selectedElement;
MessageBox.Show(GetXPath(node, true));
}
string GetXPath(IHTMLDOMNode node, bool stopAtId)
{
var path = new Stack<string>();
while (node != null && node as IHTMLDocument2 == null)
{
var index = 0;
// find previous siblings with the same tag name
var prev = node.previousSibling;
while (prev != null)
{
if (prev.nodeType == 1 && prev.nodeName == node.nodeName)
index++;
prev = prev.previousSibling;
}
var showIndex = index > 0;
// if there were none, find if there are any next siblings with the same tag name
var next = node.nextSibling;
while (next != null)
{
if (next.nodeType == 1 && next.nodeName == node.nodeName)
{
showIndex = true;
break;
}
next = next.nextSibling;
}
var id = ((IHTMLDOMAttribute2)((IHTMLAttributeCollection2)node.attributes).getNamedItem("id")).value;
if (id != string.Empty)
{
showIndex = false;
}
var part = node.nodeName + (showIndex ? string.Format("[{0}]", index + 1) : string.Empty) + (id != string.Empty ? string.Format("[@id = '{0}']", id) : string.Empty);
if (id != string.Empty && stopAtId)
part = "/" + part;
path.Push(part);
if (id != string.Empty && stopAtId)
break;
node = node.parentNode;
}
return "/" + string.Join("/", path);
}
在此示例中,我创建了一个名为 getSelectedXPathToolStripMenuItem_Click
的新方法,该方法对应于上下文菜单上的新菜单项,以在消息框中的选择处显示 XPath。 显然,如果需要,您可以将其更改为将其放入 RTB 中。
主要工作是在 GetXPath
方法中完成的,该方法执行 DOM 遍历。它检查以前的同级节点,以确定节点的索引,如果它是具有该名称的第一个同级节点,则也会检查下一个同级,以查看是否应包含索引 (1)。
它还接受一个名为 stopAtId
的布尔参数,顾名思义,当节点设置了 id
属性时,它将停止遍历 DOM。 这可能很有用,因为您始终可以通过 id 轻松找到元素,而无需了解它的祖先等。