Как парсить XML в Python: ElementTree, lxml, XPath, пространства имен и большие файлы
XML – это текстовый язык разметки, который используют для хранения и обмена структурированными данными. Если вы уже работали с XML, то знаете: человеку его читать довольно легко, так же как и машинам . Но программе нужны четко организованные данные, чтобы понять XML и нормально с ним работать. Именно поэтому XML-данные парсят. Многие разработчики выбирают для этого Python, потому что язык позволяет быстро и без лишней тяжести работать с XML. Его удобно использовать и для чтения конфигурационных файлов, и для аккуратной структуры данных.
В этом руководстве разберем, как парсить XML в Python. Пройдем всё: ключевые инструменты, рабочие паттерны и примеры кода.
Главное
1. XML до сих пор используют в SOAP API, RSS feeds, CRM и ERP.
2. Встроенный в Python ElementTree хорошо подходит для базового XML-парсинга.
3. lxml поддерживает XPath и отлично работает со сложными файлами.
4. Python позволяет парсить XML из файлов, строк и даже URL.
5. Перед парсингом важно понимать древовидную структуру: элементы, атрибуты и вложенные теги.
6. Потоковый и событийный парсинг помогают работать с большими XML-файлами.
7. Корректные данные о пространствах имен важны: без них запросы могут вернуть не те элементы или ничего не найти.
8. С помощью Python можно изменять XML и сохранять результат обратно на диск.
9. Для безопасной обработки ненадежного XML хорошим вариантом будет defusedxml.
Зачем использовать XML в современной разработке?
Хотя сегодня для хранения и передачи структурированных данных чаще выбирают JSON, многие API, корпоративные сервисы и конфигурационные файлы всё еще работают с XML. Вот где он по-прежнему встречается:
- Многие enterprise API возвращают XML-ответы вместо JSON.
- RSS-ридеры и новостные сайты обычно отдают XML-ленты, которые нужно разобрать и показать пользователю.
- Некоторые веб-приложения хранят настройки в XML.
- Корпоративные системы, например ERP и CRM, часто обмениваются большими XML-документами.
Python хорошо подходит для чтения XML, изменения XML-документов, их программного сохранения и извлечения нужной информации.
Быстрый старт: парсинг XML за 60 секунд через ElementTree
Прежде чем переходить к сложным примерам XML-парсинга в Python, сначала разберемся, как устроен XML, и посмотрим простой пример.
Минимум, который нужно знать о структуре XML
XML-файл содержит иерархическую структуру. Он состоит из нескольких частей:
- Элементы: основные строительные блоки, то есть теги.
- Атрибуты: дополнительные данные в формате ключ-значение внутри тегов.
- Текст: содержимое внутри элемента.
- Вложенность: элементы могут содержать дочерние элементы.
- Корневой узел: единственный верхний элемент, который содержит всё остальное.
Пример XML-документа:
| <book> <title>Python Fundamentals</title> <author>Jane Doe</author> <year>2025</year> </book> |
<book> – это корневой элемент. <title>, <author> и <year> – дочерние элементы. А Jane Doe – текст внутри <author>.
Первый парсинг: файл → корень → значение
Самый простой способ разобрать XML в Python – встроенная библиотека xml.etree.ElementTree. Вот как получить конкретное значение внутри XML:
| import xml.etree.ElementTree as ET tree = ET.parse(‘book.xml’) root = tree.getroot() print(root.find(‘title’).text) # Output: Python Fundamentals |
В этом коде:
- Мы используем ElementTree для чтения XML-файла.
- ET.parse() читает XML и создает объект.
- getroot() возвращает корневой элемент.
- root.find(‘title’) находит первый дочерний элемент.
- .text получает текст внутри title и выводит его.
XML-парсинг в Python: настройка окружения
Правильная настройка Python включает всё, что понадобится для парсинга XML: инструменты, пакеты и библиотеки.
Необходимые библиотеки
Python предлагает несколько пакетов для XML-парсинга. В этом руководстве будем использовать такие библиотеки:
xml.etree.ElementTree
Это встроенная библиотека. Ее часто выбирают, когда нужно разобрать простой XML. Она легко осваивается и поддерживает базовый поиск в стиле XPath.
XML-парсинг через lxml
lxml – сторонняя Python-библиотека для XML-парсинга. Она быстрее ElementTree и хорошо подходит для проектов, где нужен XPath или приходится работать с большими файлами.
Установить ее можно так:
| pip install lxml |
- defusedxml
Если вы парсите XML из пользовательских загрузок, defusedxml – лучший выбор. Библиотека защищает от XML-атак, например entity expansion или Billion Laughs, и может заменять стандартные библиотеки вроде ElementTree почти без изменений в коде.
Установка:
| pip install defusedxml |
Как выбрать правильный парсер
Если вы только начинаете и работаете с небольшими простыми XML-файлами, лучше всего подойдет ElementTree. Для сложных документов и продвинутого поиска удобнее lxml.
Если документы приходят от пользователей, используйте defusedxml: он защищает от типичных XML-атак.
Загрузка и парсинг XML в Python
Когда мы парсим XML с помощью Python, сначала нужно загрузить его из файла, строки или удаленного источника. Уже потом разбирать. В модулях ElementTree это делается просто. Библиотека представляет XML как дерево элементов, которое легко просматривать.
Загрузка XML из файла
Часто приходится работать с XML, который уже лежит на диске. Загрузить его можно так:
| tree = ET.parse(‘data.xml’) root = tree.getroot() |
ET.parse(‘data.xml’) находит файл, читает его и превращает в объект.
tree.getroot() возвращает корневой элемент. Через него можно обращаться к дочерним элементам.
Для очень больших файлов лучше использовать ET.iterparse(), а не загружать всё дерево целиком. Так вы сэкономите память.
Загрузка XML из строки
Вот как загрузить XML из строки::
| xml_string = ‘<root><item>Example</item></root>’ root = ET.fromstring(xml_string) |
В этом коде ET.fromstring(xml_string) берет XML-документ в виде текстовой строки и превращает его в объект, который становится корнем дерева. Вы получаете тот же тип объекта, что и при парсинге файла, поэтому по дереву можно перемещаться так же.
Этот способ удобен, когда XML приходит из других функций или из ответа API. Но перед парсингом всегда проверяйте, что строка содержит корректный XML. Иначе будут ошибки.
Загрузка XML из URL: Web API или лента
Многие API и фиды данных, например RSS или Atom, отдают XML по HTTP. Пример загрузки XML из веб-API или ленты:
| import requests response = requests.get(‘https://example.com/feed.xml’, timeout=10) if response.headers[‘Content-Type’] == ‘application/xml’: root = ET.fromstring(response.content) |
Здесь requests.get(…) скачивает содержимое по URL. Проверка заголовка Content-Type подтверждает, что сервер возвращает XML. ET.fromstring(response.content) разбирает скачанный XML в Element, по которому уже можно перемещаться.
Навигация по дереву XML
После парсинга документа и получения корневого элемента у вас есть иерархическое дерево данных. Дальше можно обращаться к его частям.
Доступ к дочерним элементам
| for child in root: print(child.tag, child.text) |
Важно понимать, что такой обход возвращает только непосредственные дочерние элементы. Более глубокие вложенные элементы при этом не просматриваются автоматически. Для поиска на большей глубине используйте .findall() или рекурсивный итератор.
Доступ к вложенным элементам
Простой способ найти вложенные элементы при XML-парсинге в Python:
| nested = root.find(‘parent/child’) if nested is not None: print(nested.text) |
Так можно получить вложенный элемент. Но метод ищет только прямую цепочку дочерних элементов в указанной последовательности.
Если элемент находится глубже, чем вы ожидали, путь не совпадет. В таких случаях используйте .findall() вместе с .// для рекурсивного поиска.
Доступ к атрибутам
| element = root.find(‘book’) print(element.get(‘id’, ‘default_id’)) |
Если нужно получить все атрибуты сразу, используйте .attrib.
Поиск конкретных элементов
ElementTree дает несколько методов, которые позволяют искать по именам тегов или простым путям без ручного обхода:
- find(): возвращает первый подходящий элемент.
- findall(): возвращает список всех подходящих элементов.
- findtext(): возвращает текст первого элемента с нужным тегом или значение по умолчанию.
- .//tag: выполняет рекурсивный поиск всех подходящих тегов на любой глубине.
Лучшие библиотеки для парсинга XML

XML-парсинг в Python: модули стандартной библиотеки
Использование xml.etree.ElementTree
Большинство разработчиков используют эту библиотеку для простого, корректно сформированного XML. Она легкая, понятная и поддерживает базовый XPath.
Использование xml.dom.minidom для DOM-парсинга XML в Python
Этот модуль разбирает весь документ в памяти. Он полезен для красивого вывода небольших XML-файлов.
Использование xml.sax для событийного XML-парсинга в Python
xml.sax обрабатывает XML как поток событий. Это хороший выбор для больших XML-файлов, когда строить полное дерево слишком дорого по памяти.
Сторонние библиотеки для XML-парсинга
Есть и много полезных сторонних библиотек.
Использование lxml для высокопроизводительного XML-парсинга
lxml – быстрая библиотека, написанная на C. Она отлично работает и с HTML, и с XML, быстро разбирает документы и поддерживает полноценные XPath-запросы, а также XSLT-преобразования для сложных данных.
Использование BeautifulSoup для терпимого XML-парсинга
BeautifulSoup широко используют для веб-скрапинга HTML. Но он также может эффективно парсить XML. Его плюс – он справляется с грязной разметкой, которая не строго следует правилам XML. Библиотека строит дерево, по которому можно перемещаться и искать элементы через find() и find_all().
Использование untangle для простого преобразования XML в объект
untangle не заставляет работать с ElementTree или деревьями узлов. Вместо этого он берет XML-документ и превращает его в обычный Python-объект. После парсинга каждый XML-тег становится частью этого объекта, а обращаться к нему можно через точечную нотацию.
Сравнение производительности: что действительно важно
Для высокой производительности XML-парсинга нужно учитывать разные вещи: размер XML-файлов, нужные функции и то, как парсер строит дерево элементов в памяти.
Для небольших файлов встроенная библиотека Python – отличный выбор. Ничего дополнительно настраивать не нужно, а дерево получается простым и удобным.
Но большие XML-документы могут занимать много памяти. Для них лучше использовать SAX-парсеры или iterparse(). Почему? Потому что эти инструменты не загружают всё сразу. Они позволяют читать и обрабатывать XML-файл кусками.
А какую библиотеку выбрать для продвинутого поиска и полноценных XPath-выражений? lxml. Здесь он подходит лучше всего.
Выбор Python-библиотеки для XML под ваш проект
- Работаете с небольшими и простыми XML-файлами? ElementTree подойдет хорошо.
- В файлах много XPath-запросов? Большинство разработчиков выберет lxml.
- XML-файлы огромные? Используйте iterparse или SAX.
- Документы приходят от третьей стороны? Лучше взять defusedxml.
- XML грязный и нестабильный? BeautifulSoup будет хорошим вариантом.
- Нужен быстрый маппинг в объекты? Можно использовать untangle.
Использование XPath для сложных запросов
Если в XML глубокая вложенность, писать много ручных циклов неудобно. И долго. XPath – небольшой язык запросов для XML, который позволяет одной строкой описать, какие именно узлы нужно найти.
XPath оперирует путевыми выражениями для обхода дерева документа. Он не выполняет последовательный обход дочерних и вложенных узлов. Достаточно одного выражения, которое будет интерпретировано парсером и вернёт нужный результат. Это делает навигацию по сложной структуре заметно проще.
Пример использования XPath:
| books = root.xpath(‘//book[author=”Jane Doe”]/title’) |
Частые XPath-шаблоны, которые вы реально будете использовать
Вот самые распространенные XPath-паттерны.
Самый базовый – //. Его ставят перед именем тега, и XPath ищет этот тег по всему документу. Например, //book найдет каждый элемент <book> в XML, где бы он ни находился.
Также часто используют фильтрацию по атрибутам. Например, выражение //*[@type=’text’] найдет все элементы, у которых атрибут type равен text. Дополнительный код писать не нужно.
Как работать с XML-пространствами имен без боли
Пространства имен в XML помогают избежать конфликтов имен, но поиск и парсинг из-за них становятся чуть сложнее. Namespace выглядит в XML примерно так: xmlns:prefix=”URI”. Он сообщает парсеру, что любой тег с этим префиксом относится к определенному пространству.
Python-библиотеки для XML, например xml.etree.ElementTree и lxml, понимают пространства имен по умолчанию. Но из-за этого при поиске элементов по имени обычно нужно указывать URI пространства имен. Иначе запрос не найдет ожидаемые узлы.
Как обнаружить пространства имен в реальных файлах
Если вы используете lxml, простой способ – посмотреть свойство nsmap. Другой вариант – проверить атрибуты xmlns в корневом элементе XML-документа.
Поиск элементов с namespace
Если вы используете Python ElementTree, элементы с пространствами имен можно искать через словарь. Нужно связать префикс с полным URI namespace, а затем использовать этот префикс в пути поиска при вызове findall() или find().
Пример поиска элемента с namespace:
| ns = {‘ns’: ‘http://example.com/ns’} root.find(‘ns:book’, namespaces=ns) |
Безопасный и эффективный парсинг огромных XML-файлов
iterparse для инкрементальной обработки
Для огромных файлов, которые не помещаются в RAM, iterparse – хороший вариант. Он позволяет обрабатывать документ по частям, поэтому расход памяти остается низким. По сути, вы работаете с каждым тегом в момент его появления в файле, и полное дерево в памяти не строится.
Когда SAX лучше, чем iterparse
SAX, или Simple API for XML, – еще один хороший парсер для больших XML-документов. Он вообще не хранит структуру XML целиком, а держит только элемент, который обрабатывается прямо сейчас. Поэтому памяти расходуется мало.
Изменение XML-данных
Изменение текста элемента
Вот как можно изменить текст элемента:
| book = root.find(‘book/title’) # Find the <title> element under the first <book> element if book is not None: book.text = “Updated Python Fundamentals” # Change the text of the <title> element |
Изменение атрибутов
| book = root.find(“book”) # Find the first <book> element if book is not None: book.set(“genre”, “Python”) # Modify the genre attribute |
Вставка новых элементов в XML
Добавление нового элемента
Вот как добавить новый элемент:
| # Create a new <book> element with an attribute id=”b3″ new_book = ET.Element(‘book’, attrib={‘id’:’b3′}) # Create a <title> child element under the new_book elementtitle = ET.SubElement(new_book, ‘title’) # Set the text inside the <title> element to “Python for Data Science” title.text = ‘Python for Data Science’ root.append(new_book) |
Вставка элементов с атрибутами
| # Create a new element new_book = ET.Element(“book”, attrib={ “id”: “bk003”, # Unique identifier for this book “author”: “Jane Doe”, # Author attribute “genre”: “Programming” # Genre attribute }) # Optionally, add a child <title> element under the new book title = ET.SubElement(new_book, “title”) title.text = “Python Advanced Concepts” # Set the text for <title> root.append(new_book) # Append the new book element to the root |
Удаление XML-элементов
Иногда нужно не записывать и изменять элементы, а удалять их. Однако большинство XML-парсеров не позволяет узлу удалить самого себя, поэтому .remove() вызывают у родительского элемента. Причина проста: XML – это дерево, и только родитель знает, как отсоединить один из своих дочерних узлов.
Удаление элементов
Когда родительский элемент известен, вызывайте parent.remove(child) и передавайте дочерний элемент, который нужно удалить.
Пример базового удаления:
| for element in root.findall(‘item’): if element.get(‘type’) == ‘obsolete’: root.remove(element) # remove by calling .remove() on parent (root) |
Сохранение изменений в XML-файлы
После парсинга и изменения XML-дерева в памяти нужно записать изменения обратно на диск. Без этого всё, что вы сделали, останется только в памяти и не появится при следующей загрузке файла.
Сохранение файла на диск
Можно вызвать tree.write(…) у ElementTree. Тогда Python запишет всё XML-дерево в файл. При записи XML всегда указывайте кодировку, например encoding=”utf-8″. Также добавляйте xml_declaration=True: это подсказывает парсерам, как интерпретировать кодировку файла.
Простой пример записи файла обратно на диск:
| tree.write(“updated.xml”, encoding=”utf-8″, xml_declaration=True) |
Красивое форматирование: необязательно
Можно использовать сырой XML-вывод, но читать его обычно неудобно. Pretty-print форматирует XML с отступами и переносами строк.
Но для больших файлов такое форматирование не рекомендуется. Оно добавляет лишние пробелы и переносы, а значит увеличивает размер файла.
Кодирование и декодирование XML
Запись XML с правильной кодировкой
С кодировкой важно не ошибиться, чтобы другие системы и парсеры тоже могли понять и прочитать ваши данные.
Точно так же, когда XML приходит из разных источников, нужно правильно определять и декодировать разные кодировки до парсинга.
Когда вы сохраняете или генерируете XML-файл в Python, лучше явно задавать кодировку. UTF-8 – самая распространенная и самая широко поддерживаемая.
Декодирование XML-данных из разных кодировок
XML-парсеры обычно определяют кодировку по XML-декларации или byte order mark, BOM, в начале файла. Если прочитать XML в неправильной кодировке, текст может стать битым или нечитаемым.
Чтобы избежать этого, лучше открывать файл в бинарном режиме ‘rb’. Тогда XML-парсер сможет сам определить правильную кодировку по XML-декларации или BOM. Либо можно вручную преобразовать сырые байты, опираясь на то, что указано в самом файле.
Маппинг XML в Python-объекты
Маппинг XML в dict или dataclass: рекомендуемый вариант
Если у вас есть XML и вы просто хотите использовать данные в коде, можно преобразовать его в структуру, похожую на словарь. В Python-словарях значения доступны по простым ключам. При таком подходе ключи отражают имена XML-тегов, а вложенные теги превращаются в списки.
Еще один вариант – Python dataclass. Это встроенная стандартная возможность, которая позволяет определять простые классы с полями и подсказками типов.
Пример: маппинг XML-данных в пользовательский класс
Ниже простой пример кода: он парсит XML в Python, извлекает значения и создает из них Python-объекты.
| import xml.etree.ElementTree as ET from dataclasses import dataclass @dataclass class Book: id: int title: str author: str year: int # Parse the XML tree = ET.parse(“library.xml”) root = tree.getroot() books = [] for book_elem in root.findall(“book”): book = Book( id=int(book_elem.get(“id”)), # parse attribute title=book_elem.findtext(“title”) or “”, # extract text child author=book_elem.findtext(“author”) or “”, year=int(book_elem.findtext(“year”) or “0”) ) books.append(book) # Now `books` is a list of Book objects for b in books: print(b.title, b.author) |
Обработка ошибок и отладка
Когда вы вызываете ET.parse() или ET.fromstring(), парсер выдаст ошибку, если XML сформирован неправильно. Причины бывают разные:
- Несовпадающие или незакрытые теги.
- Проблемы с кодировкой.
- Отсутствующий корневой элемент.
- Недопустимые символы.
Иногда одной синтаксической корректности мало. XML должен соответствовать конкретной структуре. Для этого используют валидацию по схеме. XML-документы могут включать или ссылаться на DTD, Document Type Definition. Также можно использовать внешнюю XML Schema, XSD.
XML-парсинг в Python: безопасность
Когда вы обрабатываете XML-файлы из внешних источников, появляются риски безопасности. Вот как работать с такими файлами аккуратнее.
Используйте defusedxml для ненадежного ввода
Если XML приходит от пользователей, лучше не использовать стандартные парсеры вроде xml.etree.ElementTree. В таких случаях берите defusedxml, потому что он предотвращает распространенные XML-атаки.
Безопасные лимиты и тайм-ауты, если XML приходит из интернета
Когда XML загружается из сети, риски безопасности заметно выше. Для таких файлов нужно ограничивать размер загрузки, а также задавать тайм-ауты подключения и чтения.
Лучшие практики XML-парсинга в Python
- Пишите ясные и точные XML-запросы вместо слишком широких.
- Выбирайте парсер, который работает быстро и при этом остается удобным.
- Создавайте небольшие XML-примеры для unit-тестов. Это тоже важно.
Статью написал:

Фулстек AI-инженер
Александр привносит в инженерную команду Proxywing глубокую фулстек-экспертизу — от архитектуры бэкенда и оптимизации производительности до AI-ориентированных процессов разработки. Его практический опыт охватывает Node.js, React, облачную инфраструктуру и RAG-пайплайны, что позволяет одинаково уверенно работать как с внутренней логикой прокси-платформы, так и с пользовательской частью продукта. В Proxywing Александр сосредоточен на проектировании отказоустойчивых систем, устранении узких мест производительности и внедрении современных AI-инструментов в процесс разработки. Вне кода он увлечён исследованием передовых подходов в AI-инженерии и созданием сайд-проектов, расширяющих технические горизонты.
Все статьи автора (41)


