Lxml - как обернуть все вхождения конкретного текста в тег - PullRequest
1 голос
/ 08 марта 2019

Рассмотрим следующий HTML:

<div>
      Some foo text foo
      <p> text inside paragraph foo and also foo and <b> nested foo</b> and foo </p>
      foo is also here and can occur many times foo foo
      <p> here <a>foo</a> already appears inside a link so it is not changed</p>
      foo, yeah!
</div>

Мне нужно обернуть все вхождения 'foo' в интерактивную ссылку (элемент <a>), кроме случаев, которые уже находятся внутри <a>, поэтомуожидаемый результат:

<div>
      Some <a>foo</a> text <a>foo</a>
      <p> text inside paragraph <a>foo</a> and also <a>foo</a> and <b> nested <a>foo</a></b> and <a>foo</a> </p>
      <a>foo</a> is also here and can occur many times <a>foo</a> <a>foo</a>
      <p> here <a> foo </a> appears inside a link so it is not changed</p>
      <a>foo</a>, yeah!
    </div>

Есть ли простой способ сделать это с помощью lxml?Первоначально замена необработанной подстроки имела для меня больше смысла, но есть требование, что некоторые вхождения нельзя изменять, если они находятся внутри определенных элементов HTML.

Ответы [ 2 ]

0 голосов
/ 11 марта 2019

Это должно привести вас туда, куда я думаю, вы идете:

x_list = x.split(' ')
for word in range (len(x_list)):
    if 'foo' in x_list[word]:
       if x_list[word] != '<a>foo</a>':
               x_list[word]='<a>foo</a>'
new_x = ' '.join(x_list)
print(new_x.strip('\n'))

Выход:

<div>
  Some <a>foo</a> text <a>foo</a>      <p> text inside paragraph <a>foo</a> and also <a>foo</a> and <b> nested <a>foo</a> and <a>foo</a> </p>
  <a>foo</a> is also here and can occur many times <a>foo</a> <a>foo</a>      <p> here <a>foo</a> already appears inside a link so it is not changed</p>
  <a>foo</a> yeah!

0 голосов
/ 08 марта 2019

ОК, BeautifulSoup для этой цели выглядит намного лучше, чем raw lxml

Этот код работает довольно хорошо:

from bs4 import BeautifulSoup

x = """<div>
      Some foo text foo
      <p> text inside paragraph foo and also foo and <b> nested foo</b> and foo </p>
      foo is also here and can occur many times foo foo
      <p> here <a>foo</a> already appears inside a link so it is not changed</p>
      foo, yeah!
</div>"""

s = BeautifulSoup(x, 'html.parser')
print(s)

for text_node in list(s.strings):
      if not text_node.parent.name=='a':
            text_node.replace_with(BeautifulSoup(text_node.string.replace('foo', '<a>foo</a>'), 'html.parser'))

print(s)

Редактировать: важно использовать html.parser.Передача "lxml" при создании фрагмента HTML замены не работает должным образом (оборачивает фрагмент HTML в тег html)

...