简介
***可扩展标记语言(XML)***是一种标记语言,因其结构数据的方式而流行。它在数据传输(代表序列化的对象)和配置文件中发现了用途。
尽管JSON越来越受欢迎,你仍然可以在Android开发的清单文件、Java/Maven构建工具和网络上的SOAP API中找到XML。因此,解析XML仍然是开发人员必须要做的一项常见任务。
在Python中,我们可以通过利用两个库来读取和解析XML。 BeautifulSoup和 LXML.
在本指南中,我们将看看如何从XML文件中提取和解析数据,用 BeautifulSoup和 LXML,并使用Pandas存储结果。
设置LXML和BeautifulSoup
我们首先需要安装这两个库。我们将在你的工作区创建一个新的文件夹,建立一个虚拟环境,然后安装库。
$ mkdir xml_parsing_tutorial
$ cd xml_parsing_tutorial
$ python3 -m venv env # Create a virtual environment for this project
$ . env/bin/activate # Activate the virtual environment
$ pip install lxml beautifulsoup4 # Install both Python packages
现在我们已经设置好了一切,让我们做一些解析吧
用 lxml 和 BeautifulSoup 解析 XML
解析总是取决于底层文件和它所使用的结构,所以没有一个单一的银弹适用于所有文件。BeautifulSoup会自动解析它们,但底层元素是由任务决定的。
因此,最好用实践的方法来学习解析。把下面的XML保存到你工作目录下的一个文件中--teachers.xml
。
<?xml version="1.0" encoding="UTF-8"?>
<teachers>
<teacher>
<name>Sam Davies</name>
<age>35</age>
<subject>Maths</subject>
</teacher>
<teacher>
<name>Cassie Stone</name>
<age>24</age>
<subject>Science</subject>
</teacher>
<teacher>
<name>Derek Brandon</name>
<age>32</age>
<subject>History</subject>
</teacher>
</teachers>
<teachers>
标签表示XML文档的根,<teacher>
标签是<teachers></teachers>
的一个子元素或子元素,有关于一个单数人的信息。<name>
,<age>
,<subject>
是<teacher>
标签的子女,是<teachers>
标签的孙子。
上面的示例文档中的第一行,<?xml version="1.0" encoding="UTF-8"?>
,被称为XML prolog。它总是出现在一个XML文件的开头,尽管在一个XML文件中包括一个XML序言是完全可选的。
上面显示的XML序言指出了所使用的XML的版本和字符编码的类型。在这种情况下,XML文档中的字符是以UTF-8编码的。
现在我们了解了XML文件的结构--我们可以解析它了。在你的工作目录中创建一个名为teachers.py
的新文件,并导入BeautifulSoup库。
from bs4 import BeautifulSoup
**注意:**你可能已经注意到,我们没有导入lxml
!随着BeautifulSoup的导入,LXML被自动集成,所以单独导入它是没有必要的,但它并没有作为BeautifulSoup的一部分安装。
现在让我们读取我们创建的XML文件的内容,并将其存储在一个叫做soup
的变量中,这样我们就可以开始解析了。
with open('teachers.xml', 'r') as f:
file = f.read()
# 'xml' is the parser used. For html files, which BeautifulSoup is typically used for, it would be 'html.parser'.
soup = BeautifulSoup(file, 'xml')
soup
这个变量现在有我们的XML文件的解析内容。我们可以使用这个变量和与之相连的方法,用 Python 代码检索 XML 信息。
比方说,我们只想从 XML 文档中查看教师的名字。我们可以用几行代码得到这些信息。
names = soup.find_all('name')
for name in names:
print(name.text)
运行python teachers.py
,我们就可以得到。
Sam Davis
Cassie Stone
Derek Brandon
find_all()
方法返回一个作为参数传入的所有匹配标签的列表。如上面的代码所示,soup.find_all('name')
返回XML文件中所有的<name>
标签。然后我们遍历这些标签并打印它们的text
属性,其中包含标签的值。
在一个表格中显示解析过的数据
让我们更进一步,我们将解析XML文件的所有内容,并以表格的形式显示。
让我们用重写teachers.py
文件。
from bs4 import BeautifulSoup
# Opens and reads the xml file we saved earlier
with open('teachers.xml', 'r') as f:
file = f.read()
# Initializing soup variable
soup = BeautifulSoup(file, 'xml')
# Storing <name> tags and elements in names variable
names = soup.find_all('name')
# Storing <age> tags and elements in 'ages' variable
ages = soup.find_all('age')
# Storing <subject> tags and elements in 'subjects' variable
subjects = soup.find_all('subject')
# Displaying data in tabular format
print('-'.center(35, '-'))
print('|' + 'Name'.center(15) + '|' + ' Age ' + '|' + 'Subject'.center(11) + '|')
for i in range(0, len(names)):
print('-'.center(35, '-'))
print(
f'|{names[i].text.center(15)}|{ages[i].text.center(5)}|{subjects[i].text.center(11)}|')
print('-'.center(35, '-'))
上述代码的输出看起来是这样的。
-----------------------------------
| Name | Age | Subject |
-----------------------------------
| Sam Davies | 35 | Maths |
-----------------------------------
| Cassie Stone | 24 | Science |
-----------------------------------
| Derek Brandon | 32 | History |
-----------------------------------
祝贺你!你刚刚用BeautifulSoup和LXML解析了你的第一个XML文件!现在你对这个理论和过程更加熟悉了,让我们试试一个更真实的例子。
我们将数据格式化为一个表,作为将其存储在一个多功能数据结构中的前奏。也就是说--在即将到来的小项目中,我们将把数据存储在一个PandasDataFrame
。
解析RSS提要并将数据存储到CSV中
在这一节中,我们将解析一个RSS提要的 纽约时报新闻并将这些数据存储在一个 CSV 文件中。
RSS是以下术语的简称 真正简单的联合传播.一个RSS提要是一个包含网站更新摘要的文件,用XML写成。在这种情况下,《纽约时报》的RSS提要包含其网站上每日新闻更新的摘要。这个摘要包含新闻发布的链接、文章图片的链接、新闻项目的描述等等。RSS源也被用来让人们在不搜刮网站的情况下获得数据,作为网站所有者的一个很好的信物。
这里是纽约时报的一个RSS提要的快照。
你可以通过这个链接获得不同大洲、国家、地区、主题和其他标准的纽约时报RSS提要。
在开始解析数据之前,看到并理解数据的结构是很重要的。我们想从RSS提要中提取的关于每篇新闻文章的数据是。
- 全球唯一标识符(GUID)
- 标题
- 出版日期
- 描述
现在我们已经熟悉了结构并有了明确的目标,让我们开始我们的程序吧我们将需要requests
库和pandas
库来检索数据并轻松地将其转换为CSV文件。
通过requests
,我们可以向网站发出HTTP请求并解析响应。在这种情况下,我们可以用它来检索他们的RSS提要(XML格式),这样BeautifulSoup就可以解析它了。有了pandas
,我们就可以将解析后的数据格式化为一个表,最后将表的内容存储到一个CSV文件中。
在同一个工作目录下,安装requests
和pandas
(你的虚拟环境应该仍然是活动的)。
$ pip install requests pandas
在一个新文件中,nyt_rss_feed.py
,让我们导入我们的库。
import requests
from bs4 import BeautifulSoup
import pandas as pd
然后,让我们向《纽约时报》的服务器发出一个HTTP请求,以获得他们的RSS提要并检索其内容。
url = 'https://rss.nytimes.com/services/xml/rss/nyt/US.xml'
xml_data = requests.get(url).content
通过上面的代码,我们已经能够从HTTP请求中获得一个响应,并将其内容存储在xml_data
变量中。requests
库返回的数据为bytes
。
现在,在BeautifulSoup的帮助下,创建以下函数,将XML数据解析成Pandas中的一个表格。
def parse_xml(xml_data):
# Initializing soup variable
soup = BeautifulSoup(xml_data, 'xml')
# Creating column for table
df = pd.DataFrame(columns=['guid', 'title', 'pubDate', 'description'])
# Iterating through item tag and extracting elements
all_items = soup.find_all('item')
items_length = len(all_items)
for index, item in enumerate(all_items):
guid = item.find('guid').text
title = item.find('title').text
pub_date = item.find('pubDate').text
description = item.find('description').text
# Adding extracted elements to rows in table
row = {
'guid': guid,
'title': title,
'pubDate': pub_date,
'description': description
}
df = df.append(row, ignore_index=True)
print(f'Appending row %s of %s' % (index+1, items_length))
return df
上面的函数用BeautifulSoup解析来自HTTP请求的XML数据,将其内容存储在一个soup
。通过df
变量引用带有行和列的Pandas DataFrame,用于我们想要解析的数据。
然后我们在XML文件中进行迭代,找到所有带有<item>
的标签。通过遍历<item>
标签,我们能够提取其子标签。<guid>
,<title>
,<pubDate>
, 和<description>
。注意我们是如何使用find()
方法来获取一个对象的。我们将每个子标签的值追加到Pandas表中。
现在,在文件末尾的函数之后,添加这两行代码来调用函数并创建一个CSV文件。
df = parse_xml(xml_data)
df.to_csv('news.csv')
运行python nyt_rss_feed.py
,在你现在的工作目录下创建一个新的CSV文件。
Appending row 1 of 24
Appending row 2 of 24
...
Appending row 24 of 24
该CSV文件的内容将看起来像这样。
注意:下载数据可能需要一些时间,这取决于你的互联网连接和RSS提要。解析数据也可能需要一些时间,这取决于你的CPU和内存资源。我们使用的源是相当小的,所以它应该很快处理。如果你没有立即看到结果,请耐心等待。
恭喜你,你已经成功地解析了纽约时报新闻的RSS提要,并将其转换为CSV文件!
总结
在本指南中,我们学习了如何设置BeautifulSoup和LXML来解析XML文件。我们首先通过解析一个带有教师数据的简单的XML文件进行了练习,然后我们解析了纽约时报的RSS提要,将他们的数据转换为CSV文件。
你可以使用这些技术来解析你可能遇到的其他XML,并将它们转换成你需要的不同格式