【问题标题】:how to either return string or match empty if node/tag not found in xpath (lxml)如果在 xpath (lxml) 中找不到节点/标记,如何返回字符串或匹配空
【发布时间】:2012-02-27 17:14:12
【问题描述】:

我有以下 XPath 来匹配亚马逊页面中的作者姓名:

//div[@class='pTitle']/span[@class='small itemByline'] | //div[@class='pTitle']/span[not(text())]

此 XPath 的第一部分与它匹配得很好,但是页面中的某些项目在具有类 pTitle 的此类 div 之后没有跨度,因此没有可匹配的内容,但我想得到一个 '' 或其他东西,要知道作者没有真正找到,而只是跳过它。我想第二个 XPath 无效,因为它不起作用...

例如,以“A Ditadura”开头的 3 个标题应该为使用我正在构建的 XPath 的作者条目返回 ''。他们不是。它使上述 XPath 返回 179 个项目而不是 209 个。

目标是http://www.amazon.com/wishlist/3MCYFXCFDH4FA/ref=cm_wl_act_print_o?_encoding=UTF8&layout=standard-print&disableNav=1&visitor-view=1&items-per-page=1000

这是我的 Python 模块 https://github.com/caio1982/Amazon-Wishlist 的代码的一部分(顺便感谢到目前为止所有好的答案,感谢你们,我学会了 XPath)。

为了提供信息,我正在尝试使用 Firefox 的 XPath Checker 扩展,并使用 Python (lxml) 实现它。

听起来类似于How do I return '' for an empty node's text() in XPath?,但我不确定。

我怀疑答案可能是围绕 XPath 轴和某种 [notcontains] 限制?

EDIT1:在 Dimitre 的建议之后稍微改写一下......是否可以使用 –– 如果可以,您是否有一个工作示例 –– Becker 的使用 lxml 的 XPath 方法? p>

EDIT2:示例树和预期结果:

    <html>
        <body>
            <h1>Title</h1>
            <p>First Paragraph</p>
            <p>Second paragraph: <span>value</span></p>
            <p>Third paragraph: <span>value</span></p>
            <p>Forth paragraph:</p>
        </body>
    </html>

XPath //p/span 相应地返回第二和第三段“值”字符串。没关系,但我正在寻找 4 个结果而不是 2 个,如下所示:

    None
    value
    value
    None

我知道 //p/span 对此不起作用,因此我正在寻找一些字符串魔术、节点比较或条件等。

【问题讨论】:

    标签: python xpath amazon lxml


    【解决方案1】:

    您可以使用这样的 XPath 表达式

    concat(
    //div[@class='pTitle']/span[@class='small itemByline'],
    substring('UNKNOWN', 
              1 + 7*(boolean(//div[@class='pTitle']/span[@class='small itemByline'])
              )
           )
    

    当计算此 XPath 表达式时,如果 //div[@class='pTitle']/span[@class='small itemByline'] 存在,则生成其字符串值(与空字符串连接)。

    //div[@class='pTitle']/span[@class='small itemByline']不存在时,则结果为字符串'UNKNOWN'——空字符串与substring('UNKNOWN', 1+0连接。

    这里我们使用了这样一个事实,即在 XPath 1.0 中,每当布尔值是算术运算符的参数时,它首先被转换为数字,使用以下规则:

       number(true()) = 1
    

       number(false()) = 0
    

    更新:这是一个基于 XSLT 的验证,使用 OP 的 EDIT 2 中的 XML 文档并准确生成想要的结果(相同的 XPath 表达式(仅更新索引)是评估了 4 次,所有生成的值都被输出——每个值都在单独的行上):

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:template match="/">
      <xsl:for-each select="(//node())[not(position() > count(//p))]">
       <xsl:variable name="vPos" select="position()"/>
       <xsl:value-of select=
         "concat((//p)[position() = $vPos]/span,
                 substring('UNKNOWN',
                           1 +7*boolean((//p)[position() = $vPos]/span)
                           )
                 )
         "/>
    
         <xsl:text>&#xA;</xsl:text>
      </xsl:for-each>
     </xsl:template>
    </xsl:stylesheet>
    

    当此转换应用于最新提供的 XML 文档时

    <html>
        <body>
            <h1>Title</h1>
            <p>First Paragraph</p>
            <p>Second paragraph: 
                <span>value</span>
            </p>
            <p>Third paragraph: 
                <span>value</span>
            </p>
            <p>Forth paragraph:</p>
        </body>
    </html>
    

    XPath 表达式被计算 N (4) 次,并产生了这个计算的结果——正如我们所见,这些正是想要的结果

    UNKNOWN
    value
    value
    UNKNOWN
    

    【讨论】:

    • 非常感谢 Dimitre,但我想我在这里遗漏了一些东西。您的解释是有道理的,但是我在 Firefox 中的 XPath Checker 以及 Python 的 lxml 中都遇到了语法错误。子字符串是正确的还是 1+7* 的东西好吗?我不太明白语法,只是想法:-(
    • @caio1982:我不知道 lxml。通常有两种计算 XPath 表达式的函数。一种是选择节点——比如SelectNodes()SelectSingleNode()。如果 XPath 表达式作为参数传递,这些函数将引发错误,该参数不选择节点。我认为这就是你的情况。另一方面,有一些函数可以计算any XPath 表达式——不仅是选择节点的表达式——例如Evaluate()。你需要在lxml中找到这样一个函数并使用它。
    • 显然这个解决方案要么返回 X 要么 Y,而不是两者(即如果一个节点为空而下一个节点不是,则返回两者但具有不同的值,一个真实的和一个“异常”字符串) .或者我一定做错了......
    • @caio1982:我不明白你在上一条评论中的意思。请您改写一下好吗?
    • 对不起。据我了解并到目前为止可以对其进行测试,看来这种方法将仅返回 X 或 Y 作为结果。相反,我正在寻找一种获得这两个结果的方法:如果 XPath 匹配,则返回其字符串或节点或其他任何内容,但如果不匹配,则还返回某些内容(任意字符串,例如,'blah')。因此 XPath 将始终返回两个值,而不仅仅是其中一个(显然,就像上面的解决方案一样)。
    猜你喜欢
    • 2023-03-14
    • 2016-11-27
    • 2012-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-31
    • 2011-05-13
    相关资源
    最近更新 更多