2011-08-11 5 views
12

Używam biblioteki lxml.html do parsowania dokumentu HTML.Python: Wstrzykiwanie treści HTML do tagu za pomocą `lxml.html`

I znajduje konkretny tag, który ja nazywam content_tag i chcę, aby zmienić jej treść (czyli tekst pomiędzy <div> i </div>,) i nowej zawartości jest ciągiem z jakimś html w nim, mówią, że to 'Hello <b>world!</b>'.

Jak to zrobić? Próbowałem content_tag.text = 'Hello <b>world!</b>' ale potem ucieka wszystkie tagi html, zastępując < z &lt; itp

Chcę wprowadzić tekst bez ucieczce kodu HTML. Jak mogę to zrobić?

+0

Sposób, w jaki naprawdę próbujesz zmodyfikować strukturę DOM, byłby dodanie nowego węzła dla 'świata'. – katrielalex

+0

Jak to zrobić? –

Odpowiedz

8

Jest to jeden sposób:

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

Zobacz także: http://lxml.de/lxmlhtml.html#creating-html-with-the-e-factory

Edit: Więc powinienem przyznał wcześniej, że nie jestem wszystkim, co zna lxml. Spojrzałem krótko na dokumenty i źródła, ale nie znalazłem czystego rozwiązania. Być może ktoś bardziej znajomy zatrzyma się i wyprostuje nas oboje.

W międzyczasie, to wydaje się działać, ale nie jest dobrze przetestowany:

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) 

Edycja ponownie: a ta wersja usuwa tekst i dzieci

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

Ten sposób nie działa dla mnie z 2 powodów: (1) Nie chcę zastępować tagu, chcę zastąpić treść tagu i (2) Segment HTML, który chcę wstrzyknąć, już jest tekstowy, nie chcę budować go za pomocą 'E'. –

+0

@Ram Rachum: zaktualizowana odpowiedź, mam nadzieję, że jest pomocna. – Marty

0

Zakładając content_tag nie masz dowolne podelementy, możesz po prostu zrobić:

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

Nie pomaga - mój tekst HTML nie jest wcześniej znany i nie mogę go skonstruować jako struktury HTML w kodzie. –

+0

Ahh, ale nie określiłeś tego w swoim pytaniu (część "nie jest znana wcześniej"). – sayap

+0

Edytowana odpowiedź mwalsh wygląda dobrze i powinna działać dla dowolnego html. – sayap

0

Po majstrowaniu wokół, znalazłem to rozwiązanie:

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