2011-08-11 20 views
12

estoy usando la biblioteca lxml.html a analizar un documento HTML.Python: La inyección de contenido HTML en una etiqueta usando `lxml.html`

que encuentra una etiqueta específica, que llamo content_tag, y quiero cambiar su contenido (es decir, el texto entre <div> y </div>,) y el nuevo contenido es una cadena con un poco de html en ella, dicen que es 'Hello <b>world!</b>'.

¿Cómo puedo hacer eso? Probé content_tag.text = 'Hello <b>world!</b>' pero luego se escapa todas las etiquetas HTML, reemplazando < con &lt; etc.

quiero para inyectar el texto sin escapar nada de HTML. ¿Cómo puedo hacer eso?

+0

La forma _nice_, ya que está realmente tratando de modificar la estructura DOM, sería añadir un nuevo nodo hijo de 'world'. – katrielalex

+0

¿Cómo hago eso? –

Respuesta

8

Ésta es una manera:

#!/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> 

Consulte también: http://lxml.de/lxmlhtml.html#creating-html-with-the-e-factory

Editar: Por lo tanto, debería haber confesado antes de que yo no soy tan familiarizados con lxml. Miré los documentos y la fuente brevemente, pero no encontré una solución limpia. Tal vez, alguien más familiar pasará y nos pondrá a ambos en línea recta.

Mientras tanto, esto parece funcionar, pero no está bien probado:

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) 

de nuevo Edit: y esta versión elimina texto y los niños

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) 
+0

De esa manera no funciona para mí por 2 razones: (1) No quiero reemplazar una etiqueta, quiero reemplazar el contenido de una etiqueta y (2) El segmento de html que quiero para inyectar ya está en forma de texto, no quiero construirlo con 'E'. –

+0

@Ram Rachum: respuesta actualizada, espero que sea útil. – Marty

0

Suponiendo content_tag no lo hace tiene cualquier subelemento, puede hacer:

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

... 

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

¿No help-- Mi texto HTML no se conoce de antemano y no puede construir como una estructura HTML en el código. –

+0

Ahh, pero no especificó que en su pregunta (el "no se sabe de antemano" parte). – sayap

+0

La respuesta editada de mwalsh se ve bien y debería funcionar para html arbitrario. – sayap

0

Después de juguetear alrededor, me encontré con esta solución:

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 
Cuestiones relacionadas