【问题标题】:Is there a way of obtaining the Xpath position of highlighted text using Windows Form Application in C#?有没有办法在 C# 中使用 Windows 窗体应用程序获取突出显示文本的 Xpath 位置?
【发布时间】:2016-01-18 16:33:46
【问题描述】:

我正在尝试使用 Windows 窗体应用程序创建一个网络爬虫工具。是否有 API 或方法来显示所选文本的确切 xpath 位置?到目前为止,我编写的代码允许我在 webbrowser 控件中突出显示导航网站上的文本,并使用 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 页面结构中的位置.关于这是否可行以及我应该遵循哪些步骤的任何想法?

【问题讨论】:

    标签: c# visual-studio xpath web-scraping webbrowser-control


    【解决方案1】:

    这是可能的,但是您必须自己构建 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 轻松找到一个元素,而无需了解它的祖先等任何信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-24
      • 1970-01-01
      • 2013-01-10
      相关资源
      最近更新 更多