lxml - это библиотека Python, которая позволяет легко обрабатывать файлы XML и HTML, а также может использоваться для парсинга веб-страниц. Существует множество стандартных анализаторов XML, но для достижения лучших результатов разработчики иногда предпочитают писать свои собственные анализаторы XML и HTML. Именно тогда в игру вступает библиотека lxml. Ключевые преимущества этой библиотеки заключаются в том, что она проста в использовании, чрезвычайно быстра при синтаксическом анализе больших документов, очень хорошо документирована и обеспечивает легкое преобразование данных в типы данных Python, что упрощает манипулирование файлами.
В этом руководстве мы глубоко погрузимся в библиотеку Python lxml, начав с того, как настроить ее для различных операционных систем, а затем обсудим ее преимущества и широкий спектр предлагаемых функций.
Монтаж
Есть несколько способов установить lxml в вашу систему. Мы рассмотрим некоторые из них ниже.
Использование Pip
Pip - это менеджер пакетов Python, который используется для простой загрузки и установки библиотек Python в вашу локальную систему, т.е. он также загружает и устанавливает все зависимости для пакета, который вы устанавливаете.
Если в вашей системе установлен pip, просто выполните следующую команду в терминале или командной строке:
$ pip install lxml
Использование apt-get
Если вы используете MacOS или Linux, вы можете установить lxml, выполнив эту команду в своем терминале:
$ sudo apt-get install python-lxml
Использование easy_install
Вероятно, вы не дойдете до этой части, но если ни одна из
вышеперечисленных команд по какой-то причине у вас не работает,
попробуйте использовать easy_install
:
$ easy_install lxml
Примечание. Если вы хотите установить какую-либо конкретную версию lxml,
вы можете просто указать ее при запуске команды в командной строке или в
терминале, например, lxml==3.xy
К настоящему времени у вас должна быть установлена копия библиотеки lxml на вашем локальном компьютере. Давайте теперь запачкаем руки и посмотрим, какие классные вещи можно делать с помощью этой библиотеки.
Функциональность
Чтобы иметь возможность использовать библиотеку lxml в своей программе, вам сначала необходимо ее импортировать. Вы можете сделать это с помощью следующей команды:
from lxml import etree as et
Это импортирует etree
, представляющий интерес, из библиотеки lxml.
Создание документов HTML / XML
Используя etree
, мы можем создавать элементы XML / HTML и их
подэлементы, что очень полезно, если мы пытаемся писать или
манипулировать файлом HTML или XML. Попробуем создать базовую структуру
HTML-файла с помощью etree
:
root = et.Element('html', version="5.0")
# Pass the parent node, name of the child node,
# and any number of optional attributes
et.SubElement(root, 'head')
et.SubElement(root, 'title', bgcolor="red", fontsize='22')
et.SubElement(root, 'body', fontsize="15")
В приведенном выше коде вам необходимо знать, что для Element
требуется как минимум один параметр, а для SubElement
требуется как
минимум два. Это связано с тем, что Element
требует только имени
создаваемого элемента, тогда как SubElement
требует создания имени как
корневого узла, так и дочернего узла.
Также важно знать, что обе эти функции имеют только нижнюю границу
количества аргументов, которые они могут принимать, но не имеют верхней
границы, потому что вы можете связать с ними столько атрибутов, сколько
захотите. Чтобы добавить атрибут к элементу, просто добавьте
дополнительный параметр к функции (Sub) Element и укажите свой атрибут в
форме attributeName='attribute value'
.
Давайте попробуем запустить код, который мы написали выше, чтобы лучше понять эти функции:
# Use pretty_print=True to indent the HTML output
print (et.tostring(root, pretty_print=True).decode("utf-8"))
Выход:
<html version="5.0">
<head/>
<title bgcolor="red" fontsize="22"/>
<body fontsize="15"/>
</html>
Есть еще один способ создания и организации ваших элементов в иерархическом порядке. Давайте также исследуем это:
root = et.Element('html')
root.append(et.SubElement('head'))
root.append(et.SubElement('body'))
Поэтому в этом случае всякий раз, когда мы создаем новый элемент, мы просто добавляем его к корневому / родительскому узлу.
Анализ документов HTML / XML
До сих пор мы рассматривали только создание новых элементов, присвоение им атрибутов и т. Д. Давайте теперь рассмотрим пример, в котором у нас уже есть файл HTML или XML, и мы хотим проанализировать его, чтобы извлечь определенную информацию. Предполагая, что у нас есть файл HTML, который мы создали в первом примере, давайте попробуем получить имя тега одного конкретного элемента, а затем распечатать имена тегов всех элементов.
print(root.tag)
Выход:
html
Теперь, чтобы перебрать все дочерние элементы в root
узле и
распечатать их теги:
for e in root:
print(e.tag)
Выход:
head
title
body
Работа с атрибутами
Давайте теперь посмотрим, как мы связываем атрибуты с существующими элементами, а также как получить значение определенного атрибута для данного элемента.
Используя тот же root
элемент, что и раньше, попробуйте следующий код:
root.set('newAttribute', 'attributeValue')
# Print root again to see if the new attribute has been added
print(et.tostring(root, pretty_print=True).decode("utf-8"))
Выход:
<html version="5.0" newAttribute="attributeValue">
<head/>
<title bgcolor="red" fontsize="22"/>
<body fontsize="15"/>
</html>
Здесь мы видим, что newAttribute="attributeValue"
действительно был
добавлен к корневому элементу.
Давайте теперь попробуем получить значения атрибутов, которые мы
установили в приведенном выше коде. Здесь мы получаем доступ к дочернему
элементу, используя индексирование массива по root
элементу, а затем
используем метод get()
для получения атрибута:
print(root.get('newAttribute'))
print(root[1].get('alpha')) # root[1] accesses the `title` element
print(root[1].get('bgcolor'))
Выход:
attributeValue
None
red
Получение текста из элементов
Теперь, когда мы ознакомились с основными функциями etree
, давайте
попробуем сделать еще несколько интересных вещей с нашими файлами HTML и
XML. Почти всегда в этих файлах между тегами есть текст. Итак, давайте
посмотрим, как мы можем добавить текст к нашим элементам:
# Copying the code from the very first example
root = et.Element('html', version="5.0")
et.SubElement(root, 'head')
et.SubElement(root, 'title', bgcolor="red", fontsize="22")
et.SubElement(root, 'body', fontsize="15")
# Add text to the Elements and SubElements
root.text = "This is an HTML file"
root[0].text = "This is the head of that file"
root[1].text = "This is the title of that file"
root[2].text = "This is the body of that file and would contain paragraphs etc"
print(et.tostring(root, pretty_print=True).decode("utf-8"))
Выход:
<html version="5.0">This is an HTML file<head>This is the head of that file</head><title bgcolor="red" fontsize="22">This is the title of that file</title><body fontsize="15">This is the body of that file and would contain paragraphs etc</body></html>
Проверить, есть ли у элемента дочерние элементы
Далее, есть две очень важные вещи, которые мы должны иметь возможность
проверить, поскольку это требуется во многих приложениях для очистки
веб-страниц для обработки исключений. Во-первых, мы хотели бы проверить,
есть ли у элемента дочерние элементы, а во-вторых, является ли узел
Element
.
Сделаем это для узлов, которые мы создали выше:
if len(root) > 0:
print("True")
else:
print("False")
Приведенный выше код выведет «True», поскольку у корневого узла есть дочерние узлы. Однако, если мы проверим то же самое для дочерних узлов корневого узла, как в приведенном ниже коде, на выходе будет «False».
for i in range(len(root)):
if (len(root[i]) > 0):
print("True")
else:
print("False")
Выход:
False
False
False
Теперь давайте сделаем то же самое, чтобы увидеть, является ли каждый из
узлов Element
или нет:
for i in range(len(root)):
print(et.iselement(root[i]))
Выход:
True
True
True
Метод iselement
полезен для определения того, есть ли у вас
действительный Element
и, следовательно, можно ли продолжить его
обход, используя методы, которые мы показали здесь.
Проверьте, есть ли у элемента родительский элемент
Только что мы показали, как спуститься по иерархии, то есть как проверить, есть ли у элемента дочерние элементы или нет, и теперь в этом разделе мы попытаемся подняться вверх по иерархии, то есть как проверить и получить родительский элемент дочернего узла. .
print(root.getparent())
print(root[0].getparent())
print(root[1].getparent())
Первая строка не должна возвращать ничего (иначе None
), поскольку сам
корневой узел не имеет родителя. Два других должны указывать на корневой
элемент, то есть на HTML-тег. Давайте проверим вывод, чтобы убедиться,
что он соответствует нашим ожиданиям:
Выход:
None
<Element html at 0x1103c9688>
<Element html at 0x1103c9688>
Получение братьев и сестер элемента
В этом разделе мы узнаем, как перемещаться в боковом направлении по иерархии, которая извлекает братьев и сестер элемента в дереве.
Боковое перемещение по дереву очень похоже на перемещение по нему по
вертикали. Для последнего мы использовали getparent
и длину элемента,
для первого мы будем использовать функции getnext
и getprevious
.
Давайте попробуем их на ранее созданных узлах, чтобы увидеть, как они
работают:
# root[1] is the `title` tag
print(root[1].getnext()) # The tag after the `title` tag
print(root[1].getprevious()) # The tag before the `title` tag
Выход:
<Element body at 0x10b5a75c8>
<Element head at 0x10b5a76c8>
Здесь вы можете видеть, что root[1].getnext()
извлек тег «body»,
поскольку это был следующий элемент, а root[1].getprevious()
извлек
тег «head».
Точно так же, если бы мы использовали getprevious
для root, она
вернула бы None
, а если бы мы использовали getnext
для root [2],
она также вернула бы None
.
Разбор XML из строки
Двигаясь дальше, если у нас есть файл XML или HTML, и мы хотим проанализировать необработанную строку, чтобы получить или обработать требуемую информацию, мы можем сделать это, следуя приведенному ниже примеру:
root = et.XML('<html version="5.0">This is an HTML file<head>This is the head of that file</head><title bgcolor="red" fontsize="22">This is the title of that file</title><body fontsize="15">This is the body of that file and would contain paragraphs etc</body></html>')
root[1].text = "The title text has changed!"
print(et.tostring(root, xml_declaration=True).decode('utf-8'))
Выход:
<?xml version='1.0' encoding='ASCII'?>
<html version="5.0">This is an HTML file<head>This is the head of that file</head><title bgcolor="red" fontsize="22">The title text has changed!</title><body fontsize="15">This is the body of that file and would contain paragraphs etc</body></html>
Как видите, мы успешно изменили текст в HTML-документе. Объявление XML
doctype также было автоматически добавлено из-за xml_declaration
который мы передали функции tostring
Поиск элементов
Последнее, что мы собираемся обсудить, очень удобно при синтаксическом
анализе файлов XML и HTML. Мы будем проверять способы, с помощью которых
мы можем увидеть, имеет ли Element
какой-либо конкретный тип дочерних
элементов, и если он имеет то, что они содержат.
У этого есть много практических вариантов использования, таких как поиск всех элементов ссылки на определенной веб-странице.
print(root.find('a')) # No <a> tags exist, so this will be `None`
print(root.find('head').tag)
print(root.findtext('title')) # Directly retrieve the the title tag's text
Выход:
None
head
This is the title of that file
Заключение
В приведенном выше руководстве мы начали с базового введения в то, что такое библиотека lxml и для чего она используется. После этого мы узнали, как установить его в различных средах, таких как Windows, Linux и т. Д. Двигаясь дальше, мы исследовали различные функции, которые могли бы помочь нам перемещаться по дереву HTML / XML как в вертикальном, так и в боковом направлении. В конце мы также обсудили способы поиска элементов в нашем дереве, а также получения информации из них.