仅使用 Xpath 提取 <br> 标签内部分文本的文本
Posted
技术标签:
【中文标题】仅使用 Xpath 提取 <br> 标签内部分文本的文本【英文标题】:Extract text where a part of text inside <br> tag using only Xpath 【发布时间】:2021-10-21 01:04:03 【问题描述】:我只想从这里抓取字符串:
<br>
5 Brown Circle<br>
Alabaster,
AL
35007
我需要深入了解如何从 html doc 之后的上述部分中提取文本:
<tr class="prem-tr" id="10425" role="row">
<td>
<h4><a class="prem-result-link" href="/Search/Details/10425">Graham & Associates, CPAs</a></h4>
<a href="tel:+(205) 663-6673">(205) 663-6673</a>
<br>
5 Brown Circle<br>
Alabaster,
AL
35007
<div class="row result-btmRow">
<div class="col-sm-4">
<span class="result-dist"><small>Distance: 0.00 miles</small></span>
</div><!-- col6 -->
<div class="col-sm-8 result-actions">
<a id="WebsiteURL" class="visit-site" href="http://grahamandassociates.net" target="_blank">Visit Website</a>
<a class="send-email" href="/Search/Details/10425">Send a Message</a>
</div><!-- /col6 -->
</div><!-- /row -->
</td>
</tr>
预期输出:5 Brown Circle, Alabaster, AL 35007
仅使用 xpath 以及解释。
或
在 css 选择器中,它工作正常。谁能解释下面的代码?谢谢
" ".join([" ".join(el.root.strip().split()) for el in sel.css("td::text") if el.root.strip()])
【问题讨论】:
展示你的尝试 看看elementTree 【参考方案1】:我不会说这是一个很好的解决方案,但如果要求只使用 XPath 1.0...
normalize-space(translate(concat(//td/text()[4], //td/text()[5]),"\xa0", ""))
稍微分解一下并在 iPython 中使用 lxml.etree
进行演示:
td
的所有子文本节点都可以用//td/text()
选择。这不包括姓名和电话号码,因为它们是后代而不是孩子。
In [73]: root.xpath('//td/text()')
Out[73]:
['\n ',
'\n\n ',
'\n ',
'\n\n 5 Brown Circle',
'\n\n Alabaster,\n\n AL \xa0\xa0\n\n 35007\n\n ',
'\n ']
理想情况下,我们可以连接所有这些字符串并使用normalize-space()
规范化空格,但这很尴尬,因为在XPath 1.0 中,我们只有concat()
可供我们使用,它只需要两个参数。在 Python 中使用join()
处理这个问题会更好,但是因为我们感兴趣的只有两个文本节点,所以我们可以使用concat()
来连接集合中的第四个和第五个文本节点,以获得纯 XPath 解决方案。
In [74]: root.xpath('concat(//td/text()[4], //td/text()[5])')
Out[74]: '\n\n 5 Brown Circle\n\n Alabaster,\n\n AL \xa0\xa0\n\n 35007\n\n '
现在我们可以申请normalize-space()
来清理空白。
In [75]: root.xpath('normalize-space(concat(//td/text()[4], //td/text()[5]))')
Out[75]: '5 Brown Circle Alabaster, AL \xa0\xa0 35007' '
差不多了。现在我们只需要在规范化空格之前用translate()
去掉不间断的空格字符。
In [79]: root.xpath('normalize-space(translate(concat(//td/text()[4], //td/text()[5]),"\xa0", ""))')
Out[79]: '5 Brown Circle Alabaster, AL 35007'
请注意,因为这是 Python,所以我们必须使用 \xa0
而不是 &nbsp;
或 &#160;
来表示不间断空格字符。
【讨论】:
为什么我们在这里使用翻译方法?你能解释一下吗? 当然可以。translate()
在字符串中搜索单个字符的实例并将它们替换为其他单个字符。如果未指定字符,则仅删除原始字符。所以在这里,translate()
用于擦除不间断的空格字符(原始的&nbsp;
),以便结果中的空格符合您的要求。 (normalize-space()
处理大多数空格,但不能处理不间断的空格字符。)
好吧,你已经连接了 text 。你能详细说明一下哪个部分表示 html 文档中的文本吗?
谢谢。它工作正常,但我不只理解串联 4 和 5 。你能告诉我你是怎么做到的吗?
姓名和电话号码是孙子,不是直子。伟大的!解释。这次。我已经明白了一切。非常感谢。【参考方案2】:
&nbsp
实体和未关闭的<br>
标记的处理可能会因您使用的 XPath 处理器而异,但以下将产生所请求的确切结果:
//td/text()[string-length(normalize-space(.)) > 0]/normalize-space(translate(.,' ',''))
在哪里
//td
选择所有 td 节点(示例中只有一个),
/text()
选择作为td
的直接子级的所有文本节点,
谓词[string-length(normalize-space(.)) > 0]
消除了在去除前导/尾随空格后为零长度字符串的任何文本节点,
/normalize-space(translate(.,'&#160;',''))
将 nbsp
字符替换为空字符,并消除剩余文本节点的前导/尾随空格。
【讨论】:
太棒了!但是有个小问题:这里的(.)是什么意思,为什么我们用 去掉 作为替换。&nbsp
实体是实际字符,您没有在预期的输出中显示它们。 ' ' 只是数字参考(参见***.com/questions/3274315/…)。在 XPath 中,点指的是上下文项。例如,在表达式text()[string-length(normalize-space(.)) > 0]
中,点指的是应用谓词的 text() 节点。
不工作怎么办?您收到什么错误或意外输出?
我更多地尝试了我的答案,并注意到它实际上返回了两个文本节点而不是一个。如果您的 XPath 处理器支持具有 string-join() 函数的 XPath 版本,则可以将其作为一个字符串返回,但您的确切空白要求可能难以实现。以上是关于仅使用 Xpath 提取 <br> 标签内部分文本的文本的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Response.xpath 中排除特定标签(<br>)?