【问题标题】:Retrieving tail text from html从 html 中检索尾部文本
【发布时间】:2016-09-20 18:45:01
【问题描述】:

Python 2.7 使用 lxml

我有一些令人讨厌的 html,看起来像这样:

<td>
<b>"John"
</b>
<br>
"123 Main st.
"
<br>
"New York
"
<b>
"Sally"
</b>
<br>
"101 California St.
"
<br>
"San Francisco
"
</td>

所以基本上它是一个包含大量内容的单个 td。我正在尝试编译名称及其地址的列表或字典。

到目前为止,我所做的是获得一个名称使用tree.xpath('//td/b') 的节点列表。因此,假设我目前在 John 的 b 节点上。

我正在尝试为当前节点之后但在下一个 b 节点 (Sally) 之前的所有内容获取 whatever.xpath('string()')。我尝试了一堆不同的 xpath 查询,但似乎无法做到这一点。特别是,每当我在没有[] 括号的表达式中使用and 运算符时,它都会返回一个布尔值,而不是满足条件的所有节点的列表。有人可以帮忙吗?

【问题讨论】:

  • 既然过滤符合表达式的元素是括号的事情,你为什么不想拥有它们(假设你的and正在为你的表达式添加条件,这是为了什么)?您能否展示您尝试过的内容,具体包括您尝试使用and 的方式?
  • ...您当前的答案就目前而言还不错,但它们不太可能帮助在标题中提出相同问题的人(尝试将多个条件应用于 XPath询问);如果您添加了更多信息,则应该可以回答名义问题。相反,如果您对此不感兴趣,则可以考虑编辑问题标题以更好地反映您真正关心的内容。
  • 我还建议将标题更改为“从 HTML 中检索尾部文本”之类的内容,因为这是问题的核心!

标签: python xpath lxml


【解决方案1】:

这应该可行:

from lxml import etree

p = etree.HTMLParser()
html = open(r'./test.html','r')
data = html.read()
tree = etree.fromstring(data, p)

my_dict = {}

for b in tree.iter('b'):
    br = b.getnext().tail.replace('\n', '')
    my_dict[b.text.replace('\n', '')] = br

print my_dict

此代码打印:

{'"John"': '"123 Main st."', '"Sally"': '"101 California St."'}

(你可能想去掉引号!)

您可以使用 lxml 的解析器之一来轻松导航 HTML,而不是使用 xpath。解析器会将 HTML 文档转换为“etree”,您可以使用提供的方法对其进行导航。 lxml 模块提供了一个名为iter() 的方法,它允许您传入标签名称并接收树中具有该名称的所有元素。在您的情况下,如果您使用它来获取所有 &lt;b&gt; 元素,则可以手动导航到 &lt;br&gt; 元素并检索其尾部文本,其中包含您需要的信息。您可以在 lxml.etree tutorial. 的“元素包含文本”标题中找到相关信息

【讨论】:

  • 不知何故,我从来没有听说过 tail 处理休息时间,但这太棒了!谢谢!
  • 没有问题,老实说我自己才知道的!由于我每天在工作中都使用 XML,这对我来说也是一次很好的学习经历。
【解决方案2】:

从每个 td 的角度来看,什么不使用 getchildren 函数。例如:

from lxml import html

s = """
<td>
<b>"John"
</b>
<br>
"123 Main st.
"
<br>
"New York
"
<b>
"Sally"
</b>
<br>
"101 California St.
"
<br>
"San Francisco
"
</td>
"""

records = []
cur_record = -1
cur_field = 1

FIELD_NAME = 0
FIELD_STREET = 1
FIELD_CITY = 2

doc = html.fromstring(s)
td = doc.xpath('//td')[0]
for child in td.getchildren():
    if child.tag == 'b':
        cur_record += 1
        record = dict()
        record['name'] = child.text.strip()
        records.append(record)
        cur_field = 1
    elif child.tag == 'br':
        if cur_field == FIELD_STREET:
            records[cur_record]['street'] = child.tail.strip()
            cur_field += 1
        elif cur_field == FIELD_CITY:
            records[cur_record]['city'] = child.tail.strip()

结果是:

records = [
           {'city': '"New York\n"', 'name': '"John"\n', 'street': '"123 Main st.\n"'},
           {'city': '"San Francisco\n"', 'name': '\n"Sally"\n', 'street': '"101 California St.\n"'}
          ]

请注意,如果您想获取某些非关闭 html 标记的文本,则应使用 tag.tail,例如,&lt;br&gt;

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-26
    • 2015-05-08
    • 2011-10-31
    • 2011-11-07
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多