【问题标题】:Regex replace text nodes in an html document正则表达式替换 html 文档中的文本节点
【发布时间】:2011-12-16 11:30:49
【问题描述】:

我有一个代表 html 文档的字符串。我正在尝试用一些替换 html 替换该文档中的文本,当然不包括标记和属性值。我认为这很简单,但是当您想用标记替换文本时,它非常乏味。例如,将somekeyword 替换为<a href = "link">somekeyword</a>

from lxml.html import fragments_fromstring, fromstring, tostring
from re import compile
def markup_aware_sub(pattern, repl, text):
    exp = compile(pattern)
    root = fromstring(text)

    els = [el for el in root.getiterator() if el.text]
    els = [el for el in els if el.text.strip()]
    for el in els:
        text = exp.sub(repl, el.text)
        if text == el.text:
            continue
        parent = el.getparent()
        new_el = fromstring(text)
        new_el.tag = el.tag
        for k, v in el.attrib.items():
            new_el.attrib[k] = v
        parent.replace(el, new_el)
    return tostring(root)

markup_aware_sub('keyword', '<a>blah</a>', '<div><p>Text with keyword here</p></div>')

它有效,但前提是关键字正好是两个“嵌套”。必须有比上述更好的方法,但是在谷歌上搜索了几个小时后,我找不到任何东西。

【问题讨论】:

  • 为什么不使用 html 解析器呢? Python 有一个内置的 html 解析器。
  • 你能举一个“之前”和“之后”的例子吗?假设您有&lt;body&gt;&lt;div&gt;&lt;p class="keyword"&gt;My keyword&lt;/p&gt;&lt;/div&gt;&lt;div&gt;keyword&lt;/div&gt;&lt;/body&gt;,是否应该将所有“关键字”文本替换为&lt;a&gt;blah&lt;/a&gt;,而不是属性?
  • @unni +1:一个 html 解析器将允许搜索所有 &lt;p&gt; 内容而无需质疑。关于替换关键字,您并没有真正使用正则表达式,这对性能有好处(但是问题标题有点错误)。

标签: python html regex replace lxml


【解决方案1】:

这可能是您正在寻找的解决方案:

from HTMLParser import HTMLParser

class MyParser(HTMLParser):
    def __init__(self,link, keyword):
    HTMLParser.__init__(self)
    self.__html = []
    self.link = link
    self.keyword = keyword

    def handle_data(self, data):
    text = data.strip()
    self.__html.append(text.replace(self.keyword,'<a href="'+self.link+'>'+self.keyword+'</a>'))

    def handle_starttag(self, tag, attrs):
    self.__html.append("<"+tag+">")

    def handle_endtag(self, tag):
    self.__html.append("</"+tag+">")

    def new_html(self):
    return ''.join(self.__html).strip()


parser = MyParser("blah","keyword")
parser.feed("<div><p>Text with keyword here</p></div>")
parser.close()
print parser.new_html()

这将为您提供以下输出

<div><p>Text with <a href="blah>keyword</a> here</p></div>

您的 lxml 方法的问题似乎仅在关键字只有一个嵌套时才会出现。它似乎适用于多个嵌套。所以我添加了一个 if 条件来捕获这个异常。

from lxml.html import fragments_fromstring, fromstring, tostring
from re import compile
def markup_aware_sub(pattern, repl, text):
    exp = compile(pattern)
    root = fromstring(text)
    els = [el for el in root.getiterator() if el.text]
    els = [el for el in els if el.text.strip()]

    if len(els) == 1:
      el = els[0]
      text = exp.sub(repl, el.text)
      parent = el.getparent()
      new_el = fromstring(text)
      new_el.tag = el.tag
      for k, v in el.attrib.items():
          new_el.attrib[k] = v
      return tostring(new_el)

    for el in els:
      text = exp.sub(repl, el.text)
      if text == el.text:
        continue
      parent = el.getparent()
      new_el = fromstring(text)
      new_el.tag = el.tag
      for k, v in el.attrib.items():
          new_el.attrib[k] = v
      parent.replace(el, new_el)
    return tostring(root)

print markup_aware_sub('keyword', '<a>blah</a>', '<p>Text with keyword here</p>')

不是很优雅,但似乎工作。请检查一下。

【讨论】:

  • 谢谢!但我确实更喜欢基于 lxml 的方法,而不是使用不同的 api。
  • @BjörnLindqvist 没问题。我也会寻找基于 lxml 的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-11
  • 2020-05-22
  • 2018-08-16
相关资源
最近更新 更多