【问题标题】:XPATH - how to get inner html data free from <br> tags?XPATH - 如何从 <br> 标签中获取内部 html 数据?
【发布时间】:2015-07-28 06:04:18
【问题描述】:

这个问题以前有人问过,

这是 HTML 数据

<p>
This is some important data
<br>
Even this is data
<br>
this is useful too
</p>


<othertag>
 othertag data
</othertag>
<moretag>
 moretag data
</moretag>
....
repeating n times
....

我的目标是提取&lt;p&gt;&lt;/p&gt; 内的数据,而不是被&lt;br&gt; 标签和其他数据分开

这是我的查询

//p//text() | //othertag//text() | //moretag//text()

这给了

('This is is some important data', 'even this data', 'this is useful too',
'othertag data','moretag data')

注意到上面&lt;p&gt;标签文本数据已经在输出中拆分了吗?

我希望将其格式化为正确的单位如下所示

('This is is some important data even this data this is useful too',
'othertag data','moretag data')

如果不可能, 我至少可以这样得到它吗?

('This is is some important <br> data even this data <br> this is useful too',
'othertag data','moretag data') 

我不能使用join 语句,因为很难在变量索引中选择性地加入变量列表值(没有人可以预测会有多少&lt;br&gt; 标记,因此数据可能会拆分变量次数)

我的尝试(在其他用户的帮助下)

string(//p//text()) | //othertag//text() | //moretag//text()

上述查询导致 XPATH 错误

这个也是,

import lxml.html, lxml.etree

    ns = lxml.etree.FunctionNamespace(None)

    def cat(context, a):
        return ''.join(a)
    ns['cat'] = cat

这个查询也给出了InvalidType 错误

cat(//p//text()) | //othertag//text() | //moretag//text()

我正在使用 python 2.7

【问题讨论】:

  • 您愿意使用其他库吗?您不应该尝试将 html 解析为 xml ,您应该使用为解析 html 构建的库。
  • 按照the original answer中的建议修改cat函数定义为return [''.join(a)]
  • @har07 在每种类型有多个标签时将无法按预期工作(请参阅编辑)它将所有p标签中的所有文本连接成一个字符串。我想要这样("p - text data","othertag data","moretag data","p-text data", "other tag data".....)
  • @har07 如果这不可行,我愿意妥协是否可以将内部文本数据作为一个包含&lt;br&gt; 标签的单元来获取。如果可能的话,你能建议吗?

标签: python html xml xpath


【解决方案1】:

您可以尝试使用以下自定义 XPath 函数:

演示代码:

import lxml.html, lxml.etree

source = '''your html here'''
doc = lxml.html.fromstring(source)
ns = lxml.etree.FunctionNamespace(None)

def cat(context, elements):
    return [''.join(e.xpath('.//text()')) for e in elements]
ns['concat-texts'] = cat

print repr(doc.xpath('concat-texts(//p)| //othertag//text() | //moretag//text()'))

HTML 输入示例:

source = '''
<p>
This is some important data
<br>
Even this is data
<br>
this is useful too
</p>

<p>
foo
<br>
bar
<br>
baz
</p>

<othertag>
 othertag data
</othertag>
<moretag>
 moretag data
</moretag>
'''

输出:

['\nThis is some important data\n\nEven this is data\n\nthis is useful too\n', '\nfoo\n\nbar\n\nbaz\n', '\n othertag data\n', '\n moretag data\n']

【讨论】:

  • 谢谢,你的逻辑是有道理的,但我有点收到这个错误return [''.join(e.xpath('.//text()')) for e in elements] AttributeError: 'lxml.etree._ElementUnicodeResult' object has no attribute 'xpath'
  • @wolfgang 我怀疑你是用concat-texts(//p//text()) 而不是上面建议的concat-texts(//p) 来称呼它的,不是吗?
  • 你是对的!这是一个改进,我得到它是因为("p text-data","p text-data", "othertag data", "moretag data","othertag data","moretag data") 所有p text-data 都首先被排序,然后其他数据按顺序格式化。这是我应该期待的最好结果吗?
  • @wolfgang 是的,这似乎是 XPath 能给你的最好结果。正如您提到的妥协,在大多数情况下,通过简化 XPath 并在 Python(托管编程语言)中做更多事情来完成
【解决方案2】:

如果您愿意使用其他库,那么您可以使用BeautifulSoup

演示 -

>>> s = """<p>
... This is some important data
... <br>
... Even this is data
... <br>
... this is useful too
... </p>
...
...
... <othertag>
...  othertag data
... </othertag>
... <moretag>
...  moretag data
... </moretag>"""

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup(s,'html.parser')

>>> soup.find('p').text
'\nThis is some important data\n\nEven this is data\n\nthis is useful too\n'

>>> print(soup.find('p').text)

This is some important data

Even this is data

this is useful too

【讨论】:

    【解决方案3】:

    我知道这来晚了,但有人可能会发现它仍然有用。我让它工作的方式是替换原始 html 中的 br 标签。它是一个字节对象,因此必须对其进行解码和编码,但它的作用就像一个魅力:

    from lxml import html
    import requests
    
    page = request.get("the website you are getting the html from")
    content = page.content.decode('utf-8').replace("<br>", " ").encode('utf-8')
    tree = html.fromstring(content)
    

    在此之后,//p//text()) 返回“这是一些重要的数据,即使这些数据也很有用”,这就是你想要的。

    【讨论】:

      【解决方案4】:

      您说:“我希望将其格式化为如下所示的适当单位,

      ('这是一些重要数据,即使这些数据也很有用', 'othertag data','moretag data')"

      但实际上,XPath 不进行格式化。您建议您希望返回三个字符串的序列;格式化稍后完成。

      您使用的是 Python,我假设您使用的是 XPath 1.0。在 XPath 1.0 中,不存在由三个字符串组成的序列。您可以返回三个节点(p、othertag 和 moretag 节点),然后提取这些节点的字符串值成为 Python 问题,而不是 XPath 问题。或者您可以在三个单独的调用中返回这三个字符串:例如,string(//p) 将为您提供第一个 p 元素的字符串值。

      在您的问题中,您说数据是重复的。但是你没有说哪些数据是重复的。我对您的真实源文档的外观没有清晰的了解。这可能就是为什么您的问题(包括我的问题)的答案如此不完整的原因。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-12
        • 1970-01-01
        相关资源
        最近更新 更多