Análisis XML en Python

Este artículo se centra en cómo se puede analizar un archivo XML dado y extraer algunos datos útiles de forma estructurada.

XML: XML significa lenguaje de marcado extensible. Fue diseñado para almacenar y transportar datos. Fue diseñado para ser legible tanto por humanos como por máquinas. Por eso, los objetivos de diseño de XML enfatizan la simplicidad, la generalidad y la facilidad de uso en Internet.
El archivo XML que se analizará en este tutorial es en realidad una fuente RSS.

RSS: RSS (Rich Site Summary, a menudo llamado Really Simple Syndication) utiliza una familia de formatos estándar de fuentes web para publicar información actualizada con frecuencia, como entradas de blogs, titulares de noticias, audio y video. RSS es texto sin formato con formato XML.

  • El formato RSS en sí mismo es relativamente fácil de leer tanto por procesos automatizados como por humanos.
  • El RSS procesado en este tutorial es la fuente RSS de las principales noticias de un sitio web de noticias popular. Puedes comprobarlo aquí . Nuestro objetivo es procesar este feed RSS (o archivo XML) y guardarlo en algún otro formato para uso futuro.

Módulo de Python utilizado: este artículo se centrará en el uso del módulo xml incorporado en Python para analizar XML y el enfoque principal estará en la API XML de ElementTree de este módulo.

Implementación:

#Python code to illustrate parsing of XML files
# importing the required modules
import csv
import requests
import xml.etree.ElementTree as ET
  
def loadRSS():
  
    # url of rss feed
    url = 'http://www.hindustantimes.com/rss/topnews/rssfeed.xml'
  
    # creating HTTP response object from given url
    resp = requests.get(url)
  
    # saving the xml file
    with open('topnewsfeed.xml', 'wb') as f:
        f.write(resp.content)
          
  
def parseXML(xmlfile):
  
    # create element tree object
    tree = ET.parse(xmlfile)
  
    # get root element
    root = tree.getroot()
  
    # create empty list for news items
    newsitems = []
  
    # iterate news items
    for item in root.findall('./channel/item'):
  
        # empty news dictionary
        news = {}
  
        # iterate child elements of item
        for child in item:
  
            # special checking for namespace object content:media
            if child.tag == '{http://search.yahoo.com/mrss/}content':
                news['media'] = child.attrib['url']
            else:
                news[child.tag] = child.text.encode('utf8')
  
        # append news dictionary to news items list
        newsitems.append(news)
      
    # return news items list
    return newsitems
  
  
def savetoCSV(newsitems, filename):
  
    # specifying the fields for csv file
    fields = ['guid', 'title', 'pubDate', 'description', 'link', 'media']
  
    # writing to csv file
    with open(filename, 'w') as csvfile:
  
        # creating a csv dict writer object
        writer = csv.DictWriter(csvfile, fieldnames = fields)
  
        # writing headers (field names)
        writer.writeheader()
  
        # writing data rows
        writer.writerows(newsitems)
  
      
def main():
    # load rss from web to update existing xml file
    loadRSS()
  
    # parse xml file
    newsitems = parseXML('topnewsfeed.xml')
  
    # store news items in a csv file
    savetoCSV(newsitems, 'topnews.csv')
      
      
if __name__ == "__main__":
  
    # calling main function
    main()

El código anterior:

  • Cargue la fuente RSS desde la URL especificada y guárdela como un archivo XML.
  • Analice el archivo XML para guardar noticias como una lista de diccionarios donde cada diccionario es una sola noticia.
  • Guarde las noticias en un archivo CSV.

Tratemos de entender el código en partes:

  • Cargando y guardando fuentes RSS
    def loadRSS():
        # url of rss feed
        url = 'http://www.hindustantimes.com/rss/topnews/rssfeed.xml'
        # creating HTTP response object from given url
        resp = requests.get(url)
        # saving the xml file
        with open('topnewsfeed.xml', 'wb') as f:
            f.write(resp.content)

    Aquí, primero creamos un objeto de respuesta HTTP enviando una solicitud HTTP a la URL de la fuente RSS. El contenido de la respuesta ahora contiene los datos del archivo XML que guardamos como topnewsfeed.xml en nuestro directorio local.
    Para obtener más información sobre cómo funciona el módulo de requests, siga este artículo:
    Requests GET y POST usando Python

  • Analizando XML
    Hemos creado la función parseXML() para analizar el archivo XML. Sabemos que XML es un formato de datos inherentemente jerárquico y la forma más natural de representarlo es con un árbol. Mira la imagen de abajo por ejemplo:
    parsing XML

    Aquí, estamos usando el módulo xml.etree.ElementTree (llámelo ET, en resumen). Element Tree tiene dos clases para este propósito: ElementTree representa todo el
    documento XML como un árbol y Element representa un solo Node en este árbol. Las interacciones con todo el documento (leer y escribir en/desde archivos) generalmente se realizan en el nivel de ElementTree . Las interacciones con un solo elemento XML y sus subelementos se realizan en el nivel de elemento .

    Ok, ahora revisemos la función parseXML() :

    tree = ET.parse(xmlfile)

    Aquí, creamos un objeto ElementTree analizando el archivo xml pasado .

    root = tree.getroot()

    La función getroot() devuelve la raíz del árbol como un objeto Element .

    for item in root.findall('./channel/item'):

    Ahora, una vez que haya echado un vistazo a la estructura de su archivo XML, notará que solo estamos interesados ​​en el elemento del elemento.
    ./channel/item es en realidad sintaxis XPath (XPath es un lenguaje para direccionar partes de un documento XML). Aquí, queremos encontrar todos los elementos nietos de los hijos del canal del elemento raíz (indicado por ‘.’).
    Puede leer más sobre la sintaxis XPath admitida aquí .

    for item in root.findall('./channel/item'):
    
            # empty news dictionary
            news = {}
    
            # iterate child elements of item
            for child in item:
    
                # special checking for namespace object content:media
                if child.tag == '{http://search.yahoo.com/mrss/}content':
                    news['media'] = child.attrib['url']
                else:
                    news[child.tag] = child.text.encode('utf8')
    
            # append news dictionary to news items list
            newsitems.append(news)

    Ahora, sabemos que estamos iterando a través de elementos de elementos donde cada elemento de elemento contiene una noticia. Entonces, creamos un diccionario de noticias vacío en el que almacenaremos todos los datos disponibles sobre la noticia. Para iterar a través de cada elemento secundario de un elemento, simplemente iteramos a través de él, así:

    for child in item:

    Ahora, observe un elemento de elemento de muestra aquí:
    16

    Tendremos que manejar las etiquetas de espacio de nombres por separado a medida que se expanden a su valor original, cuando se analizan. Entonces, hacemos algo como esto:

    if child.tag == '{http://search.yahoo.com/mrss/}content':
                    news['media'] = child.attrib['url']

    child.attrib es un diccionario de todos los atributos relacionados con un elemento. Aquí, estamos interesados ​​en el atributo url de la etiqueta de espacio de nombres media:content .
    Ahora, para todos los demás niños, simplemente hacemos:

    news[child.tag] = child.text.encode('utf8')

    child.tag contiene el nombre del elemento secundario. child.text almacena todo el texto dentro de ese elemento secundario. Entonces, finalmente, un elemento de elemento de muestra se convierte en un diccionario y se ve así:

    {'description': 'Ignis has a tough competition already, from Hyun.... ,
     'guid': 'http://www.hindustantimes.com/autos/maruti-ignis-launch.... ,
     'link': 'http://www.hindustantimes.com/autos/maruti-ignis-launch.... ,
     'media': 'http://www.hindustantimes.com/rf/image_size_630x354/HT/... ,
     'pubDate': 'Thu, 12 Jan 2017 12:33:04 GMT ',
     'title': 'Maruti Ignis launches on Jan 13: Five cars that threa..... }

    Luego, simplemente agregamos este elemento dict a la lista newsitems .
    Finalmente, se devuelve esta lista.

  • Guardar datos en un archivo CSV
    Ahora, simplemente guardamos la lista de noticias en un archivo CSV para que pueda usarse o modificarse fácilmente en el futuro usando la función savetoCSV() . Para obtener más información sobre cómo escribir elementos de diccionario en un archivo CSV, consulte este artículo:
    Trabajar con archivos CSV en Python

Así que ahora, así es como se ven nuestros datos formateados ahora:
result

Como puede ver, los datos del archivo XML jerárquico se han convertido en un archivo CSV simple para que todas las noticias se almacenen en forma de tabla. Esto también facilita la ampliación de la base de datos.
Además, ¡uno puede usar los datos similares a JSON directamente en sus aplicaciones! Esta es la mejor alternativa para extraer datos de sitios web que no proporcionan una API pública pero proporcionan algunas fuentes RSS.

Todo el código y los archivos utilizados en el artículo anterior se pueden encontrar aquí .

¿Qué sigue?

  • Puede echar un vistazo a más fuentes RSS del sitio web de noticias utilizado en el ejemplo anterior. Puede intentar crear una versión extendida del ejemplo anterior analizando también otras fuentes RSS.
  • ¿Eres fanático del críquet? ¡ Entonces este feed rss debe ser de tu interés! ¡Puede analizar este archivo XML para obtener información sobre los partidos de cricket en vivo y usarlo para crear un notificador de escritorio!

Cuestionario de HTML y XML

Este artículo es una contribución de Nikhil Kumar. Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo y enviarlo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *