Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Selenium 如何使用';通过xpath查找元素;在for循环中_Selenium_Xpath_Beautifulsoup - Fatal编程技术网

Selenium 如何使用';通过xpath查找元素;在for循环中

Selenium 如何使用';通过xpath查找元素;在for循环中,selenium,xpath,beautifulsoup,Selenium,Xpath,Beautifulsoup,我对以下几点有些(或非常)困惑: from selenium.webdriver import Chrome driver = Chrome() html_content = """ <html> <head></head> <body> <div class='first'> Text 1 </div> <div c

我对以下几点有些(或非常)困惑:

from selenium.webdriver import Chrome
driver = Chrome()

html_content = """
<html>
     <head></head>
     <body>
         <div class='first'>
             Text 1
         </div>
         <div class="second">
             Text 2
                 <span class='third'> Text 3 
                 </span>              
         </div>
         <div class='first'>
             Text 4
         </div>
         <my_tag class="second">
             Text 5
                 <span class='third'> Text 6
                 </span>              
         </my_tag>
     </body>
</html>
"""
driver.get("data:text/html;charset=utf-8,{html_content}".format(html_content=html_content))
我可以这样得到
span
的文本:

el = driver.find_elements_by_xpath("*//span")
for i in el:
   print(i.text)
其输出为:

Text 3
Text 6
但是,当我尝试使用以下命令获取父级(并且仅获取父级)文本时:

elp = driver.find_elements_by_xpath("*//span/..")
for i in elp:
   print(i.text)
输出为:

Text 2 Text 3
Text 5 Text 6
xpath表达式
*//span/.
//span/./text()
通常(但并非总是,取决于使用的xpath测试站点)计算结果为:

Text 2
Text 5
这就是我的
for
循环所需要的

因此产生了混乱。所以我想我要找的是一个
for
循环,它在伪代码中看起来像:

 el = driver.find_elements_by_xpath("*//span")
 for i in el:
    print(i.text)
    print(i.parent.text) #trying this in real life raises an error....

i、 text将不起作用,在java中我曾经写过类似这样的东西

 ele.get(i).findElement("here path to parent may be parent::div ").getText();

可能有几种方法可以做到这一点。这里有一条路

elp = driver.find_elements_by_css_selector("span.third")
for i in elp:
    print(i.text)
    s = i.find_element_by_xpath("./..").get_attribute("innerHTML")
    print(s.split('<')[0].strip())

下面是将仅从父节点检索文本的python方法

def get_text_exclude_children(element):
    return driver.execute_script(
        """
        var parent = arguments[0];
        var child = parent.firstChild;
        var textValue = "";
        while(child) {
            if (child.nodeType === Node.TEXT_NODE)
                    textValue += child.textContent;
                    child = child.nextSibling;
        }
        return textValue;""",
        element).strip()
以下是如何在您的案例中使用该方法:

elements = driver.find_elements_by_css_selector("span.third")
for eleNum in range(len(elements)):
    print(driver.find_element_by_xpath("(//span[@class='third'])[" + str(eleNum+1) +"]").text)
    print(get_text_exclude_children(driver.find_element_by_xpath("(//span[@class='third'])[" + str(eleNum+1) +"]/parent::*")))
以下是输出:

我知道我已经接受了@JeffC的答案,但在研究这个问题的过程中,我发生了一些事情。这很可能是过火了,但这是一个有趣的方法,为了后代,我想我也可以把它贴在这里

这个想法涉及到使用BeautifulSoup。原因是BS有两种从树中删除节点的方法。其中一个在这里很有用(据我所知,Selenium没有相应的方法)是
decompose()
(.我们可以使用
decompose())
通过删除标记及其内容,禁止打印父级
文本的第二部分,该部分包含在
span
标记中。因此,我们导入BS并从@JeffC的答案开始:

from bs4 import BeautifulSoup
elp = driver.find_elements_by_css_selector("span.third")

for i in elp:
    print(i.text)
    s = i.find_element_by_xpath("./..").get_attribute("innerHTML")
在这里切换到bs4

    content = BeautifulSoup(s, 'html.parser')
    content.find('span').decompose()
    print(content.text)
没有字符串操作、正则表达式之类的输出是…:

Text 3   
      Text 2

Text 6
      Text 5

这个问题是针对python的。Sugest是一个代码转换编辑,selenium适用于几乎每种语言,因此逻辑是相同的,如果答案在任何方面都有用,就不需要对其进行否决。@Valga不,meta上已经详细讨论过了。不要用另一种语言回答问题。如果答案如此简单,回答者应该花费更多的时间是时候将其转换为所需的语言了。@JeffC Selenium支持52种语言绑定。用52种语言存储每一个问题都会浪费空间、时间和多余的精力。正如Valga提到的,底层逻辑很重要。但是没有关于这一点的规范性元讨论。请停止捏造东西你自己做,不要误导新的贡献者。@DebanjanB还说,支持的语言只有6种。有些语言有不止一个框架,但只有6种语言。我不知道你从哪里得到了52种。即使你把所有的框架都算进去,也只有14种。这看起来很有希望,但似乎“向上导航”“一个级别”不起作用,因为输出与
elp=driver完全相同。通过\u xpath(“*//span/”)查找\u元素
问题中的陈述:
文本3,文本2,文本3,文本6,文本5,文本6
。我们需要找到一种方法来禁止打印
文本的第二部分。
。是的。你是对的。我忘了父元素也包含子元素。你有什么原因不想抓取父元素并拆分子元素吗e 2由newline完成?这会容易得多。当然,我们可以在这里进行字符串操作,但到现在(考虑到我给出的所有问题),这已成为一个原则问题(事实上)为了找到一个更有机的方法来实现这一点,如果存在的话。我修复了答案。尝试一下。我解析了父对象的innerHTML以分离出子对象。我在本地对其进行了测试,但您需要在实际系统上对其进行测试以确保其正常工作。好的,它确实有效!谢谢。我刚刚想到-有没有方法使用
unwrap()
到达那里?有趣的方法,但是
返回self.driver.execute\u script
引发的
NameError:name'self'没有定义
。我的错,忘了删除
self
。更新了答案,只删除了self。所以你现在应该可以很好地执行该方法了。现在我遇到了这个奇怪的错误(以前从未见过):
StaleElementReferenceException:Message:stale element reference:element未附加到页面文档
。我刷新了所有内容并重试,但错误依然存在。嗯,更新了代码以使用索引而不是元素来指向父级。希望您能很好地进行此更改:-)至少这次的错误更容易识别:)
NoSuchElementException:Message:没有这样的元素:无法定位元素:{“方法”:“xpath”,“选择器”:“(//span[@class='third']]][0]”}
。用于正确作业的正确工具。。。很多时候,不止一种工具可用。有时知道使用哪一个是最难弄清楚的。
    content = BeautifulSoup(s, 'html.parser')
    content.find('span').decompose()
    print(content.text)
Text 3   
      Text 2

Text 6
      Text 5