#python #parsing #html-parsing #lxml
#python #синтаксический анализ #html-синтаксический анализ #lxml
Вопрос:
Я использую 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:
Для упрощения вы можете использовать поддержку регулярных выражений lxml в XPath, чтобы находить и уничтожать ненужные узлы без необходимости перебора всех потомков.
Это приводит к тому же результату, что и ваш скрипт:
EXSLT_NS = 'http://exslt.org/regular-expressions'
XPATH = r"//*[re:test(@class, 'bunwantedb') or re:test(@id, 'bunwantedb')]"
tree = lxml.html.fromstring(html)
for node in tree.xpath(XPATH, namespaces={'re': EXSLT_NS}):
node.drop_tree()
print lxml.html.tostring(tree.body)