Parse xml rss feeds python cover

数据有多种格式,从简单的CSV表格和JSON对象,到描述性更强、层级更清晰的XML文档。XML看起来或许有些老旧,但在RSS源、API和软件配置中依然随处可见。

使用XML数据前,需要先对其进行解析。换句话说,就是让程序读懂其中的内容。借助Python的ElementTree、minidom和lxml等库,XML解析过程清晰直观。

无论面对何种数据格式,学会处理它们,尤其是XML,都是开发人员的必备技能。 在本指南中,您将逐步学习如何从XML中读取、导航和提取数据。

XML 基础

XML是可扩展标记语言,是一种用于存储和传输数据的通用格式。它的结构既便于人类阅读,也便于机器处理。XML的设计注重简洁、适应性和广泛的在线可用性。

XML可以理解为一棵树:它有一个根元素,以及层层嵌套的子元素。这种结构体现了XML以层级方式组织数据的特点。Python提供了多种处理XML数据的方法,其中ElementTree模块最为常用。ElementTree模块包含两个主要类:ElementTree(表示整个文档)和Element(表示单个节点)。  

开发者如何解析XML:主要方法

在Python中,parse()函数通常是处理XML文档的第一步。它会解析XML文档,并将其转换为程序可遍历的树结构。无论使用ElementTree、lxml还是其他库,这个函数都是多种解析方法的基础。

要掌握解析方法,首先需要了解XML文档的组成部分:

  • 命名空间:通过限定元素和属性的名称来避免命名冲突。
  • 根元素 :包含所有其他元素的主容器。
  • 属性 :用于提供元素额外信息的键值对。
  • 子元素:按层级组织数据的嵌套元素。
  • 文字内容:元素中包含的实际信息。

这些部分共同构成结构化格式,使程序能够存储和共享复杂数据。了解结构后,我们来看看Python中主要的XML解析方法:  

1. ElementTree模块   

Python内置库,提供易用的API来遍历XML树。它兼顾易用性和性能,适合大多数任务。   

2. lxml   

第三方库,支持XPath、XSLT和验证。它比ElementTree更快、功能更丰富,适合处理复杂的XML。   

3. DOM (文档对象模型)  

它会将完整的XML文档以树结构加载到内存中。虽然易于遍历和修改,但处理较大文件时可能占用大量内存。 

4. SAX (XML简单API)   

一种事件驱动的解析器,按顺序处理XML。它内存效率很高,能快速处理大文件,但处理复杂操作时不如其他方法直观。   

5. Untangle   

将XML数据转换为Python对象,便于访问。它适合用较少代码快速解析,但对复杂XML结构的适应性较弱。   

学习本教程,您需要…

  • Python和Requests  

如果计算机尚未安装Python 3.x,可从以下网址下载:https://www.python.org/。打开终端后,使用pip安装Requests:

pip install requests 或 pip3 install requests

  • Visual Studio Code(VS Code)

可使用Visual Studio Code(VS Code)内置终端运行所需命令。只需从 官方网站下载,并按照对应操作系统的安装说明进行操作。

  • RSS源

RSS源是一种特殊的XML文档格式,可自动传递网站新闻或更新。简而言之,它是一份以程序可读取方式组织的”最新文章列表”。

例如,我们的网站设有教程专区。与其每天检查网站是否发布了新教程,不如使用RSS源,它是一份包含所有近期文章信息的XML文档。我们将使用 DataImpulse RSS源 进行演示。现在来看看需要的库和代码。

ElementTree

下面介绍如何使用Python内置的ElementTree模块解析RSS源中的XML数据。  

首先导入xml.etree.ElementTree。过程很简单:向RSS源URL发送GET请求后,服务器会返回XML数据。响应对象的.content属性会提供可供ElementTree解析的原始字节数据。使用ET.fromstring(),可将XML数据转换为树结构并获得根元素。其中大部分内容位于<channel><item> 元素中。

find() 方法返回第一个匹配元素,而findall() 返回具有给定标签的所有子元素。这里的items是元素列表,每个元素代表一篇教程或文章。

代码示例:  


import xml.etree.ElementTree as ET
import requests

# URL of the RSS feed (from DataImpulse site)
FEED_URL = "https://dataimpulse.com/tutorials-category/web-scraping-seo/feed/"

# Download the XML data
response = requests.get(FEED_URL)
xml_data = response.content

# Parse the XML
root = ET.fromstring(xml_data)

# In RSS feeds, items are inside 
channel = root.find("channel")
items = channel.findall("item")

# Print titles and links of the items
for item in items:
   title = item.findtext("title")
   link = item.findtext("link")
   print(f"Title: {title}")
   print(f"Link: {link}\n")
      
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
      

最后,使用 findtext()直接获取文本内容,并提取和打印每个项目的标题与链接。运行脚本后,将得到一份格式整齐的教程标题及其URL列表。  

lxml 

lxml是一个第三方库,扩展了ElementTree的功能,并支持XPath这种用于遍历XML文档的查询语言。本例将使用lxml.etree解析RSS源并提取文章标题。

和前面一样,首先使用requests.get()获取RSS源,再将响应内容传给etree.fromstring(),它会解析XML并返回根元素。借助lxml,可以使用XPath表达式查找元素,比标准的ElementTree方法更灵活高效。


import requests
from lxml import etree

# URL of the RSS feed
FEED_URL = "https://dataimpulse.com/tutorials-category/web-scraping-seo/feed/"

# Download the XML data
response = requests.get(FEED_URL)
xml_data = response.content

# Parse XML
root = etree.fromstring(xml_data)
items = root.xpath("//channel/item")

# Show list of titles with numbers
print("Available blog posts:\n")
for item in items:
   title = item.findtext("title")
   print(title)
      
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
      

最后,遍历 <item> 元素,使用findtext(“title”)提取每篇文章的标题并打印出来。

Minidom 

本例使用Minidom,即”最小DOM实现”。它是Python标准库的一部分,会将完整XML文档作为文档对象模型(DOM)加载到内存中。  

调用minidom.parseString()来解析XML并构建DOM对象(文档)。这里将使用两个常见的DOM方法。第一个是getElementsByTagName(“tag”,),它会查找具有给定标签名的所有元素。第二个是.firstChild.nodeValue,用于获取节点的文本内容。

最后,使用toprettyxml(). 它会以格式化的XML形式打印第一个item元素。   

以下展示如何使用Minidom解析RSS源中的数据:


import requests
from xml.dom import minidom

# URL of the RSS feed
FEED_URL = "https://dataimpulse.com/tutorials-category/web-scraping-seo/feed/"

# Download XML data
response = requests.get(FEED_URL)
xml_data = response.content

# Parse XML with minidom
doc = minidom.parseString(xml_data)

# Get all  elements
items = doc.getElementsByTagName("item")

print(f"Total articles found in feed: {len(items)}\n")

# Show titles with links
for i, item in enumerate(items, start=1):
   title = item.getElementsByTagName("title")[0].firstChild.nodeValue
   link = item.getElementsByTagName("link")[0].firstChild.nodeValue
   print(f"{i}. {title}")
   print(f"   Link: {link}\n")

# Show raw XML of the first  (just for demo)
print("First  as raw XML:\n")
print(items[0].toprettyxml())
      
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
      

SAX 

SAX会按顺序逐个读取XML元素,并在处理XML的不同部分时触发特定事件:

  • startElement(name, attrs):标签开始时触发
  • characters(content):读取标签之间的文本时触发
  • endElement(name):标签结束时触发

将代码保存到文件后运行:  


import requests
import xml.sax

# Custom handler for SAX parsing
class RSSHandler(xml.sax.ContentHandler):
   def __init__(self):
       super().__init__()
       self.current_tag = ""
       self.in_item = False
       self.title = ""
       self.link = ""
       self.counter = 0

   def startElement(self, name, attrs):
       if name == "item":
           self.in_item = True
           self.title = ""
           self.link = ""
       self.current_tag = name

   def characters(self, content):
       if self.in_item:
           if self.current_tag == "title":
               self.title += content
           elif self.current_tag == "link":
               self.link += content

   def endElement(self, name):
       if name == "item":
           self.counter += 1
           print(f"{self.counter}. {self.title.strip()}")
           print(f"   Link: {self.link.strip()}\n")
           self.in_item = False
       self.current_tag = ""

# Download the XML feed
FEED_URL = "https://dataimpulse.com/tutorials-category/web-scraping-seo/feed/"
response = requests.get(FEED_URL)
xml_data = response.content

# Parse XML with SAX
print("Parsing RSS feed with SAX...\n")
handler = RSSHandler()
xml.sax.parseString(xml_data, handler)

print(f"Total items parsed: {handler.counter}")
      
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
      

这种方法的优点是内存效率高,因为不会存储整个文档。  

Untangle

Untangle是处理XML的一种更简单的方法。该库会将XML文档转换为Python对象,因此无需手动遍历元素或处理事件。  

使用untangle.parse()时,会自动读取XML文档,将每个XML标签转换为Python对象,并将标签数据存储在.cdata属性中(如果标签包含文本内容)。无需使用节点或事件,只需像使用常规Python对象一样遍历XML结构即可。  

代码如下:


import requests
import untangle
from io import BytesIO

# RSS feed from DataImpulse
FEED_URL = "https://dataimpulse.com/tutorials-category/web-scraping-seo/feed/"

# Download XML
resp = requests.get(FEED_URL)
resp.raise_for_status()
xml_bytes = resp.content

# Parse XML with untangle (use BytesIO for bytes input)
doc = untangle.parse(BytesIO(xml_bytes))

# Get all  elements
items = doc.rss.channel.item

print("Articles from DataImpulse RSS:\n")

# Print articles
for i, it in enumerate(items, start=1):
   title = it.title.cdata if hasattr(it, "title") else ""
   link = it.link.cdata if hasattr(it, "link") else ""
   desc = it.description.cdata if hasattr(it, "description") else ""
  
   print(f"{i}. {title}")
   print(f"   Link: {link}")
   if desc:
       print(f"   Description: {desc}")
   print()

      
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
      

其他建议

  • 检查解析错误

有时RSS源可能不可用,或包含意外标签。遇到这种情况时,请在下载或解析XML的代码中使用try/except。

  • 使用.content下载XML

.content 属性返回原始字节数据,可避免.text 属性 可能导致的编码问题。

  • 验证元素是否存在  

并非所有XML文档的结构都相同。访问标签前,可使用如下条件判断:if item.find(‘title’) is not None

  • 关注大文件的资源占用

对于大型XML文档,请使用SAX。它会按顺序读取数据,而不会将所有内容加载到内存中。

从外部网站获取XML有时并不容易。代理有助于在不同地区顺畅访问,并保护隐私。

要点回顾

  • 解析XML是读取XML文档并以结构化、可用的方式提取数据的过程。
  • ElementTree提供基于树的方式来遍历和提取XML元素。
  • lxml支持XPath查询,可更快速地解析XML。
  • Minidom会将完整XML加载为DOM树,让你像访问结构化对象一样访问节点和文本。
  • SAX非常适合大型XML文档,因为它会逐步处理XML,而不会将所有内容保留在内存中。
  • Untangle将XML转换为Python对象,便于访问标签及其内容。

相关文章  

在Python Requests中使用代理

如何使用Python和代理抓取eBay数据

如何在Java中配置DataImpulse代理

使用Python抓取Amazon产品数据

使用Python构建自定义代理轮换器

使用Python和Selenium处理安全检查

Share article: