Ошибка при загрузке внешнего объекта при использовании 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)

Ответы

Ответ 1

В согласии с тем, что сказал 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.

Ответ 2

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()   

Ответ 3

lxml docs for parse говорит Для синтаксического анализа из строки используйте вместо этого функцию 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).

Ответ 4

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

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

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

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