Автор оригинала: Guest Contributor.
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.x.y
.
К настоящему времени у вас должна быть копия библиотеки xml, установленной на вашем локальном компьютере. Давайте теперь запачкаем руки и посмотрим, какие классные вещи можно сделать с помощью этой библиотеки.
Функциональность
Чтобы иметь возможность использовать библиотеку 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)элемента и укажите свой атрибут в виде attributeName='attribute value'
.
Давайте попробуем запустить код, который мы написали выше, чтобы получить лучшее представление об этих функциях:
# Use pretty_print=True to indent the HTML output print (et.tostring(root, pretty_print=True).decode("utf-8"))
Выход:
Существует еще один способ создания и организации элементов в иерархическом порядке. Давайте исследуем и это:
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"))
Выход:
Здесь мы видим, что new Attribute="attribute Value"
действительно был добавлен к корневому элементу.
Теперь давайте попробуем получить значения атрибутов, которые мы задали в приведенном выше коде. Здесь мы обращаемся к дочернему элементу с помощью индексации массива на элементе 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"))
Выход:
This is an HTML fileThis is the head of that fileThis is the title of that file This is the body of that file and would contain paragraphs etc
Проверьте, есть ли у элемента дочерние элементы
Далее, есть две очень важные вещи, которые мы должны иметь возможность проверить, поскольку это требуется во многих приложениях веб-скребка для обработки исключений. Во-первых, мы хотели бы проверить, есть ли у элемента дочерние элементы, а во-вторых, является ли узел элементом .
Давайте сделаем это для узлов, которые мы создали выше:
if len(root) > 0: print("True") else: print("False")
Приведенный выше код выведет “True”, так как корневой узел действительно имеет дочерние узлы. Однако если мы проверим то же самое для дочерних узлов корня, как в приведенном ниже коде, то результат будет “Ложным”.
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
Метод is element
полезен для определения того, есть ли у вас действительный объект Element
и, следовательно, можете ли вы продолжить его обход с помощью методов, которые мы показали здесь.
Проверьте, есть ли у элемента родитель
Только что мы показали, как перейти вниз по иерархии, то есть как проверить, есть ли у элемента дочерние элементы или нет, а теперь в этом разделе мы попробуем перейти вверх по иерархии, то есть как проверить и получить родителя дочернего узла.
print(root.getparent()) print(root[0].getparent()) print(root[1].getparent())
Первая строка не должна возвращать ничего (она же None
), так как сам корневой узел не имеет никакого родителя. Два других должны указывать на корневой элемент, то есть HTML-тег. Давайте проверим результат, чтобы увидеть, является ли он тем, что мы ожидаем:
Выход:
None
Извлечение Элементов Братьев И Сестер
В этом разделе мы узнаем, как пройти боком в иерархии, которая извлекает братьев и сестер элемента в дереве.
Обход дерева вбок очень похож на вертикальное перемещение. Для последнего мы использовали функции 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
Выход:
Здесь вы можете видеть, что root[1].getnext()
извлек тег “body”, так как это был следующий элемент, и root[1].getprevious()
извлек тег “head”.
Аналогично, если бы мы использовали функцию getprevious
в root, она вернула бы None
, а если бы мы использовали функцию getnext
в root[2], она также вернула бы None
.
Синтаксический анализ XML из строки
Далее, если у нас есть XML-или HTML-файл и мы хотим разобрать необработанную строку, чтобы получить или манипулировать необходимой информацией, мы можем сделать это, следуя приведенному ниже примеру:
root = et.XML('This is an HTML fileThis is the head of that fileThis is the title of that file This is the body of that file and would contain paragraphs etc') root[1].text = "The title text has changed!" print(et.tostring(root, xml_declaration=True).decode('utf-8'))
Выход:
This is an HTML fileThis is the head of that fileThe title text has changed! This is the body of that file and would contain paragraphs etc
Как вы можете видеть, мы успешно изменили некоторый текст в HTML-документе. Объявление XML doctype также было добавлено автоматически из-за параметра xml_declaration
, который мы передали функции tostring
.
Поиск элементов
Последнее, что мы собираемся обсудить, довольно удобно при разборе XML-и HTML-файлов. Мы будем проверять способы, с помощью которых мы можем увидеть, имеет ли элемент какой-либо конкретный тип дочерних элементов, и если да, то что они содержат.
Это имеет много практических применений, таких как поиск всех элементов ссылок на конкретной веб-странице.
print(root.find('a')) # No 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 как вертикально, так и сбоку. В конце мы также обсудили способы поиска элементов в нашем дереве, а также получения от них информации.