Подтвердить что ты не робот

Python: ввод содержимого HTML в тег с использованием `lxml.html`

Я использую библиотеку lxml.html для анализа HTML-документа.

Я нашел конкретный тег, который я вызываю content_tag, и я хочу изменить его содержимое (т.е. текст между <div> и </div>), а новый контент - это строка с некоторым html в ней, скажем, 'Hello <b>world!</b>'.

Как мне это сделать? Я попробовал content_tag.text = 'Hello <b>world!</b>', но затем он ускользнул от всех тэгов html, заменив < на &lt; и т.д.

Я хочу вставить текст без экранирования HTML. Как я могу это сделать?

4b9b3361

Ответ 1

Это один из способов:

#!/usr/bin/env python2.6
from lxml.html import fromstring, tostring
from lxml.html import builder as E
fragment = """\
<div id="outer">
  <div id="inner">This is div.</div>
</div>"""

div = fromstring(fragment)
print tostring(div)
# <div id="outer">
#   <div id="inner">This is div.</div>
# </div>
div.replace(div.get_element_by_id('inner'), E.DIV('Hello ', E.B('world!')))
print tostring(div)
# <div id="outer">
#   <div>Hello <b>world!</b></div></div>

Смотрите также: http://lxml.de/lxmlhtml.html#creating-html-with-the-e-factory

Изменить: Итак, я должен был раньше признаться, что я не так хорошо знаком с lxml. Я кратко посмотрел на документы и источник, но не нашел чистого решения. Возможно, кто-то более знакомый остановится и поставит нас обоих прямо.

В то же время, похоже, это работает, но не проверено хорошо:

import lxml.html
content_tag = lxml.html.fromstring('<div>Goodbye.</div>')
content_tag.text = '' # assumes only text to start
for elem in lxml.html.fragments_fromstring('Hello <b>world!</b>'):
    if type(elem) == str: #but, only the first?
        content_tag.text += elem
    else:
        content_tag.append(elem)
print lxml.html.tostring(content_tag)

Изменить еще раз:, и эта версия удаляет текст и дочерние элементы

somehtml = 'Hello <b>world!</b>'
# purge element contents
content_tag.text = ''
for child in content_tag.getchildren():
    content_tag.remove(child)

fragments = lxml.html.fragments_fromstring(somehtml)
if type(fragments[0]) == str:
    content_tag.text = fragments.pop(0)
content_tag.extend(fragments)

Ответ 2

Предполагая, что у content_tag нет подэлемента, вы можете просто сделать:

from lxml import html
from lxml.html.builder import B

...

content_tag.text = 'Hello '
content_tag.append(B('world!'))
print html.tostring(content_tag)

Ответ 3

После того, как я возился, я нашел это решение:

fragments = lxml.html.fragments_fromstring(<string with tags to inject>)
last = None

for frag in fragments:
  if isinstance(frag, lxml.etree._Element):
    content_tag.append(frag)
    last = frag
  else:
    if last:
      last.tail = frag
    else:
      content_tag.text = frag