2012-05-04 2 views
14

Я пытаюсь разобрать документ XML я извлекать из Интернета, но он выходит из строя после разбора с этой ошибкой:Ошибка «Не удалось загрузить внешний объект» при использовании Python LXML

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

Это является второй line в загружаемом 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) 

ответ

0

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

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

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

lxml documentation включает в себя раздел под названием «Document loading and URL resolving», в котором имеется практически вся необходимая информация.

+0

Знаете ли вы, можно ли отключить загрузку всех внешних ресурсов? Я просмотрел документацию, но ничего не нашел. – daveeloo

+1

"* Вы получаете эту ошибку, потому что загружаемый XML-код ссылается на внешний ресурс *". Нет. Это не то, почему вы получаете ошибку. Пожалуйста, см. Мой ответ. – mzjn

9

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

В competing answer, предполагается, что 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() 
+0

Downvoter: пожалуйста, объясните, что не так с этим ответом. – mzjn

+0

спасибо mzjn. Ты прав! upvoted. – Duke

+0

@ Duke: Спасибо! Приятно наконец получить положительные отзывы. – mzjn

18

В концерте с тем, что 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 documentation.

+3

Для python3: 'from io import StringIO' – Adversus

1

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