Библиотека lxml в Python

lxml – это библиотека Python, которая позволяет легко обрабатывать файлы XML и HTML, а также может использоваться для очистки веб-страниц. Существует множество стандартных анализаторов XML, но для достижения лучших результатов разработчики иногда предпочитают писать свои собственные анализаторы XML и HTML. Именно тогда в игру вступает библиотека lxml. Ключевые преимущества этой библиотеки заключаются в том, что она проста в использовании, чрезвычайно быстра при синтаксическом анализе больших документов, очень хорошо документирована и обеспечивает легкое преобразование данных в типы данных Python, что упрощает манипуляции с файлами.

В этом руководстве мы глубоко погрузимся в библиотеку lxml Python, начав с того, как настроить ее для различных операционных систем, а затем обсудим ее преимущества и широкий спектр функций, которые она предлагает.

Есть несколько способов установить lxml в вашу систему. Мы рассмотрим некоторые из них ниже.

Использование Pip

Pip – это менеджер пакетов 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-файла с помощью 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 

Теперь, чтобы перебрать все дочерние элементы в корневом узле и распечатать их теги:

for e in root:
    print(e.tag)

Вывод:

head
title
body

Работа с атрибутами

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

Используя тот же корневой элемент, что и раньше, попробуйте следующий код:

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» действительно был добавлен к корневому элементу.

Давайте теперь попробуем получить значения атрибутов, которые мы установили в приведенном выше коде. Здесь мы получаем доступ к дочернему элементу, используя индексирование массива по корневому элементу, а затем используем метод 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>

Как проверить, есть ли дочерние элементы?

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

Сделаем это для узлов, которые мы создали выше:

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

Теперь давайте сделаем то же самое, чтобы увидеть, является ли каждый из узлов элементом или нет:

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. Мы будем проверять способы, с помощью которых мы можем увидеть, есть ли у элемента какой-либо конкретный тип дочерних элементов, и есть ли у него то, что они содержат.

У этого есть много практических вариантов использования, таких как поиск всех элементов ссылки на определенной веб-странице.

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 как в вертикальном, так и в боковом направлении. В конце мы также обсудили способы поиска элементов в нашем дереве, а также получения информации из них.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *