XPath捕获<li>的特定文本值,但不捕获其子元素

时间:2018-01-08 08:20:09

标签: python html selenium xpath

我有网络抓取这种棘手的情况。我想要捕获一些在DOM中非常复杂地存储的特定文本值。我是XPath的新手已经完成了其基础知识和其他一些问题,但无法解决这个问题。 我将使用2张图片来解释这个。

要捕获的数据:

data to capture

以下是其HTML结构:

<h3>Alias names of NEUROD2 Gene</h3>
<div class="some-col-name-8">
    <ul class="list-unstyled list-spacious">
        <li>
            <span id="aliasMainName">Neuronal Differentiation 2</span>
            <sup>...</sup>
            <sup>...</sup>
            .
            .
            <sup></sup>
        </li>
        <li>
            "
            Text11   "
            <sup></sup>
            <sup></sup>
            </li>
        <li>...</li>
        <li>
            <span class="hilite">NeuroD</span>
            "-Related Factor"
            <sup>...</sup>
            <sup>
                <a class="usp we-we-link" target="_blank" href="http:www.uniprot.org/uniprot/23423" title="Uniprot">
                </a>
            </sup>
        </li>
        <li>...</li>

因此,您可以在上面看到 li 标记的动态数字之间存在的文字。这里需要的文字没有上标数字。

那就是我想跳过它的孩子 sup 标签。 就像 NeuroD相关因子&amp; NeuroD2 在上图中,我想要 NeuroD相关因子&amp; NeuroD2 作为一个文本,不是NeuroD与“相关因子”和“2”分开

我用过: //*[@id="some_id"]/div[1]/div[1]/div[1]/div/ul/li/*

哪个只提供 li 的孩子,这解决了 sup 标签的跳过,但它也省略了像这样的元素 - 相关字段 2 。在 NeuroD

如何解决XPath这样的问题。 请高度赞赏任何建议。

3 个答案:

答案 0 :(得分:2)

我想你是在谈论这个页面http://www.genecards.org/cgi-bin/carddisp.pl?gene=NEUROD2

在纯XPath中,您将应用类似

的内容
//li//text()[not(ancestor::sup)]

从每个li忽略来自sup的文字中获取文字...但Selenium不支持此语法。

作为最后的手段,您可以应用少量黑客来隐藏sup个节点,并只获取每个li所需的文字:

driver.execute_script("""document.querySelectorAll("#aliases_descriptions sup").forEach(function(i) 
                        {i.setAttribute("style", "visibility: hidden");});""")
required_text_nodes = [li.text for li in driver.find_elements_by_xpath('//section[@id="aliases_descriptions"]//h3[.="Aliases for NEUROD2 Gene"]/following-sibling::div//li')]

print(required_text_nodes)的输出:

['Neuronal Differentiation 2', 'Class A Basic Helix-Loop-Helix Protein 1', 'Neurogenic Differentiation 2', 'NeuroD-Related Factor', 'BHLHa1', 'NDRF', 'Neurogenic Basic-Helix-Loop-Helix Protein', 'Neurogenic Differentiation Factor 2', 'NeuroD2']

P.S。获得文本后,您可以再次显示sup个节点:

driver.execute_script("""document.querySelectorAll("#aliases_descriptions sup").forEach(function(i) 
                            {i.setAttribute("style", "visibility: visible");});""")

答案 1 :(得分:0)

AFAIK,没有直接的方法来使用XPath,我可能是错的。但是你可以使用几个循环来完成所需的操作。您可以使用以下逻辑: -

  1. 获取所有li
  2. 的列表
  3. 获取li的文字,这将是sup标记所需的文字+文字
  4. 获取当前li的所有孩子并循环播放这些孩子以获取sup代码的文字。
  5. 在li。的早期文本中替换现在的文字。
  6. 我从未使用过python,我的语法可能有问题,但这就是我认为的方式 -

    listParent = driver.find_element_by_xpath('//*[@id]')  # Id of parent of the list.
    list = listParent.find_elements_by_xpath('//li')
    for li in list:
        data = li.text
        sups = li.find_elements_by_xpath('.//sup')
        text=''
        for sup in sups
            text = text + sup.text
    
    requiredText = string.replace(data, text, "")
    

答案 2 :(得分:0)

您可以使用以下xpath排除sup标记。

//*[@id="some_id"]/div[1]/div[1]/div[1]/div/ul/li/node()[not(local-name()="sup"]

只是xpath,

//ul/li/node()[not(local-name()="sup"]

它还返回包含文本节点的所有节点。但是selenium不支持文本节点作为java中的返回类型。我们可以借助javascript。以下代码可能有效。

  System.setProperty("webdriver.chrome.driver", "C:\\Projects\\SeleniumDrivers\\chromedriver.exe");

    driver = new ChromeDriver();

    JavascriptExecutor jse = (JavascriptExecutor)driver;
    driver.get("file:///C:/Projects/testing2.html");
    String value="";
    String script;
    List<WebElement> lstElements=driver.findElements(By.xpath("//ul/li"));
    for(int i=1;i<=lstElements.size();i++){
        script="var iterator=document.evaluate('//ul/li["+i+"]/node()[not(local-name()=\"sup\")]', document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);"+
                " var text='';"+
                "try {"+
                     "var thisNode = iterator.iterateNext();"+
                     "while (thisNode) {"+
                        "text=text.concat(thisNode.textContent);"+
                        "thisNode = iterator.iterateNext();"+
                      "}"+  
                 "}"+
                 "catch (e) {"+
                       " dump('Error: Document tree modified during iteration ' + e );"+
                "} return text;";
        value = (String)jse.executeScript(script);
        System.out.println(value);
    }

    driver.quit();

您可以更改python的脚本。它应该工作