Редактирование дерева на месте во время итерации в lxml - PullRequest
2 голосов
/ 27 мая 2011

Я использую lxml для анализа html и редактирования его для создания нового документа. По сути, я пытаюсь использовать его в некотором роде, как в Javascript DOM - я знаю, что это не совсем то, что нужно, но до сих пор многое из этого хорошо работает.

В настоящее время я использую iterdescendants (), чтобы получить итеративный список элементов, а затем по очереди разбираюсь с каждым.

Однако, если элемент отбрасывается во время итерации, его дочерние элементы все еще рассматриваются, поскольку отбрасывание не влияет на итерацию, как вы ожидаете. Чтобы получить желаемый результат, этот хак работает:

from lxml.html import fromstring, tostring
import urllib2
import re

html = '''
<html>
<head>
</head>

<body>
    <div>
        <p class="unwanted">This content should go</p>
        <p class="fine">This content should stay</p>
    </div>

    <div id = "second" class="unwanted">
        <p class = "alreadydead">This content should not be looked at</p>
        <p class = "alreadydead">Nor should this</>
        <div class="alreadydead">
            <p class="alreadydead">Still dead</p>
        </div>
    </div>

    <div>
        <p class="yeswanted">This content should also stay</p>
    </div>
</body>

for element in allElements:
   s = "%s%s" % (element.get('class', ''), element.get('id', ''))        
   if re.compile('unwanted').search(s):
       for i in range(len(element.findall('.//*'))):
           allElements.next()
       element.drop_tree()

print tostring(page.body)

Это выводит:

<body>
    <div>

        <p class="yeswanted">This content should stay</p>
    </div>



    <div>
        <p class="yeswanted">This content should also stay</p>
    </div>
</body>

Это похоже на неприятный хак - есть ли более разумный способ добиться этого с помощью библиотеки?

1 Ответ

5 голосов
/ 01 июня 2011

Для упрощения вещей вы можете использовать поддержку lxml для регулярных выражений в XPath , чтобы находить и уничтожать ненужные узлы без необходимости перебирать всех потомков.

Это дает тот же результат, что и ваш скрипт:

EXSLT_NS = 'http://exslt.org/regular-expressions'
XPATH = r"//*[re:test(@class, '\bunwanted\b') or re:test(@id, '\bunwanted\b')]"

tree = lxml.html.fromstring(html)
for node in tree.xpath(XPATH, namespaces={'re': EXSLT_NS}):
    node.drop_tree()
print lxml.html.tostring(tree.body)
...