2012-05-04 13 views
14

Estoy tratando de analizar un documento XML recupero de la web, pero se bloquea después de analizar con este error:error 'no se pudo cargar entidad externa' al utilizar Python lxml

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

Esa es la segunda línea en el XML que se descarga. ¿Hay alguna manera de evitar que el analizador intente cargar la entidad externa u otra forma de resolver esto? Este es el código que tengo hasta ahora:

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) 

Respuesta

0

Usted está consiguiendo que el error debido a que el XML va a cargar un recurso externo referencias:

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

LXML no sabe cómo resolver GreenButtonDataStyleSheet.xslt . Usted y yo probablemente nos damos cuenta de que va a estar disponible en relación con su URL original, http://www.greenbuttondata.org/data/15MinLP_15Days.xml ... el truco está en decirle lxml cómo cargarlo.

La lxml documentation incluye una sección titulada "Document loading and URL resolving", que tiene casi toda la información que necesita.

+0

¿Sabe si es posible desactivar la carga de todos los recursos externos? Miré en la documentación pero no pude encontrar nada. – daveeloo

+1

"* Obtiene ese error porque el XML que está cargando hace referencia a un recurso externo *". No. Esa no es la razón por la que obtienes el error. Por favor mira mi respuesta. – mzjn

9

etree.parse(source) espera source ser uno de

  • un nombre de archivo/ruta
  • un objeto de archivo
  • un objeto de tipo fichero
  • un URL usando el HTTP o FTP protocolo

El problema es que está suministrando el contenido XML como una cadena.

También puede hacerlo sin urllib2.urlopen(). Sólo tiene que utilizar

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

demostración (usando 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> 
>>> 

En un competing answer, se sugiere que lxml falla debido a la hoja de estilo que hace referencia la instrucción de procesamiento en el documento . Pero ese no es el problema aquí. lxml no intenta cargar la hoja de estilo, y el documento XML se analiza perfectamente si lo hace como se describe anteriormente.

Si realmente desea cargar la hoja de estilo, tiene que ser explícito al respecto. Se necesita algo como esto:

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: por favor explique qué está mal con esta respuesta. – mzjn

+0

gracias mzjn. ¡tienes razón! votado. – Duke

+0

@Duke: ¡Gracias! Es bueno finalmente obtener algunos comentarios positivos. – mzjn

18

En concierto con lo mzjn Dicho esto, si usted quiere pasar una cadena a etree.parse(), justo lo envuelve en un objeto StringIO.

Ejemplo:

from lxml import etree 
from StringIO import StringIO 

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

tree = etree.parse(StringIO(myString)) 

Este método se utiliza en el lxml documentation.

+3

Para python3: 'from io import StringIO' – Adversus

1

lxml docs para parse dice Para analizar de una cadena, utilice la función fromstring() en su lugar.

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