Ошибка «не удалось загрузить внешний объект» при использовании Python lxml

Я пытаюсь проанализировать XML-документ, полученный из Интернета, но после анализа происходит сбой с этой ошибкой:

': failed to load external entity "<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="GreenButtonDataStyleSheet.xslt"?>

Это вторая строка загружаемого XML. Есть ли способ предотвратить попытку парсера загрузить внешний объект или другой способ решить эту проблему? Это код, который у меня есть до сих пор:

import urllib2
import lxml.etree as etree

file = urllib2.urlopen("http://www.greenbuttondata.org/data/15MinLP_15Days.xml")
data = file.read()
file.close()

tree = etree.parse(data)

person daveeloo    schedule 04.05.2012    source источник


Ответы (4)


В соответствии с тем, что сказал mzjn, если вы хотите передать строку в etree.parse(), просто оберните ее в объект StringIO.

Пример:

from lxml import etree
from StringIO import StringIO

myString = "<html><p>blah blah blah</p></html>"

tree = etree.parse(StringIO(myString))

Этот метод используется в документации lxml.

person kevin    schedule 20.10.2012
comment
Для python3: from io import StringIO - person Adversus; 19.09.2017

etree.parse(source) ожидает, что source будет одним из

  • имя файла/путь
  • файловый объект
  • файлоподобный объект
  • URL-адрес с использованием протокола HTTP или FTP

Проблема в том, что вы предоставляете содержимое XML в виде строки.

Можно и без urllib2.urlopen(). Просто используйте

tree = etree.parse("http://www.greenbuttondata.org/data/15MinLP_15Days.xml")

Демонстрация (с использованием lxml 2.3.4):

>>> from lxml import etree
>>> tree = etree.parse("http://www.greenbuttondata.org/data/15MinLP_15Days.xml")
>>> tree.getroot()
<Element {http://www.w3.org/2005/Atom}feed at 0xedaa08>
>>>   

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

Если вы действительно хотите загрузить таблицу стилей, вы должны указать это явно. Нужно что-то вроде этого:

from lxml import etree

tree = etree.parse("http://www.greenbuttondata.org/data/15MinLP_15Days.xml")

# Create an _XSLTProcessingInstruction object
pi = tree.xpath("//processing-instruction()")[0] 

# Parse the stylesheet and return an ElementTree
xsl = pi.parseXSL()   
person mzjn    schedule 06.05.2012
comment
@Duke: Спасибо! Приятно наконец получить положительные отзывы. - person mzjn; 07.08.2012
comment
Я получаю эту ошибку при анализе URL-адреса. Любая идея, как отключить загрузку этих внешних объектов? Меня не интересуют таблицы стилей, я просто хочу анализировать якоря со страницы. - person MightyPork; 01.02.2014
comment
@MightyPork: этот вопрос на самом деле не о внешних объектах; сообщение об ошибке вводит в заблуждение. Проблема здесь в том, что OP использует etree.parse() для строкового объекта, что не работает. Если у вас есть связанная проблема, я думаю, вам следует задать новый вопрос. - person mzjn; 01.02.2014
comment
@mzjn Я действительно спрашивал, но все советы, которые я получил, заключались в том, чтобы использовать другую библиотеку для получения URL-адреса. Я думал, что вы лучше понимаете проблему и можете помочь. - person MightyPork; 01.02.2014
comment
Да downvoter, это очень вероятно проблема. Это было в моем случае. - person Iharob Al Asimi; 29.09.2015
comment
etree.parse('google.com'): OSError: Ошибка чтения файла 'google.com': не удалось загрузить внешний объект google.com - person vault; 11.11.2016
comment
В моем случае я получил ошибку, потому что попытался открыть URL-адрес https с помощью синтаксического анализа. - person Shane Lu; 01.01.2018
comment
@ShaneLu: Да, HTTPS почему-то не работает. Поддерживаются только протоколы HTTP и FTP (как указано в документации lxml). - person mzjn; 01.01.2018

В документах lxml для синтаксического анализа сказано: Для синтаксического анализа строки используйте вместо этого функцию fromstring().

parse(...)
    parse(source, parser=None, base_url=None)

    Return an ElementTree object loaded with source elements.  If no parser
    is provided as second argument, the default parser is used.

    The ``source`` can be any of the following:

    - a file name/path
    - a file object
    - a file-like object
    - a URL using the HTTP or FTP protocol

    To parse from a string, use the ``fromstring()`` function instead.

    Note that it is generally faster to parse from a file path or URL
    than from an open file object or file-like object.  Transparent
    decompression from gzip compressed sources is supported (unless
    explicitly disabled in libxml2).
person jrwren    schedule 25.06.2013

Вы получаете эту ошибку, потому что XML, который вы загружаете, ссылается на внешний ресурс:

<?xml-stylesheet type="text/xsl" href="GreenButtonDataStyleSheet.xslt"?>

LXML не знает, как разрешить GreenButtonDataStyleSheet.xslt. Вы и я, вероятно, понимаем, что он будет доступен относительно вашего исходного URL-адреса, http://www.greenbuttondata.org/data/15MinLP_15Days.xml... хитрость заключается в том, чтобы сообщить lxml, как его загрузить.

документация lxml включает раздел под названием "Загрузка документов и преобразование URL", в котором содержится практически вся необходимая информация.

person larsks    schedule 05.05.2012
comment
Не знаете, можно ли отключить загрузку всех внешних ресурсов? Я смотрел в документации, но ничего не нашел. - person daveeloo; 05.05.2012
comment
Вы получаете эту ошибку, потому что загружаемый XML ссылается на внешний ресурс. Нет. Вы получаете ошибку не поэтому. Пожалуйста, смотрите мой ответ. - person mzjn; 11.07.2012