如何从 python 中的 xml 文件中获取文本?
How can I get text from an xml file in python?
我目前正在使用下面的代码来计算 xml
文件中 text
元素的数量。
from bs4 import BeautifulSoup
soup = BeautifulSoup(open('wiki.xml'), 'lxml')
count = 0
for text in soup.find_all('text', recursive=False):
count += 1
print(count)
由于文件的大小,我无法显示完整的 xml
文件,但这里有一个简短的片段...
<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en">
<siteinfo>
<sitename>Wikipedia</sitename>
<dbname>simplewiki</dbname>
<base>https://simple.wikipedia.org/wiki/Main_Page</base>
<generator>MediaWiki 1.30.0-wmf.14</generator>
<case>first-letter</case>
<namespaces>
<namespace key="-2" case="first-letter">Media</namespace>
<namespace key="-1" case="first-letter">Special</namespace>
<namespace key="0" case="first-letter" />
<namespace key="1" case="first-letter">Talk</namespace>
<namespace key="2" case="first-letter">User</namespace>
<namespace key="3" case="first-letter">User talk</namespace>
<namespace key="4" case="first-letter">Wikipedia</namespace>
<namespace key="5" case="first-letter">Wikipedia talk</namespace>
<namespace key="6" case="first-letter">File</namespace>
<namespace key="7" case="first-letter">File talk</namespace>
<namespace key="8" case="first-letter">MediaWiki</namespace>
<namespace key="9" case="first-letter">MediaWiki talk</namespace>
<namespace key="10" case="first-letter">Template</namespace>
<namespace key="11" case="first-letter">Template talk</namespace>
<namespace key="12" case="first-letter">Help</namespace>
<namespace key="13" case="first-letter">Help talk</namespace>
<namespace key="14" case="first-letter">Category</namespace>
<namespace key="15" case="first-letter">Category talk</namespace>
<namespace key="828" case="first-letter">Module</namespace>
<namespace key="829" case="first-letter">Module talk</namespace>
<namespace key="2300" case="first-letter">Gadget</namespace>
<namespace key="2301" case="first-letter">Gadget talk</namespace>
<namespace key="2302" case="case-sensitive">Gadget definition</namespace>
<namespace key="2303" case="case-sensitive">Gadget definition talk</namespace>
<namespace key="2600" case="first-letter">Topic</namespace>
</namespaces>
</siteinfo>
<page>
<title>April</title>
<ns>0</ns>
<id>1</id>
<revision>
<id>5753795</id>
<parentid>5732421</parentid>
<timestamp>2017-08-11T21:06:32Z</timestamp>
<contributor>
<ip>2602:306:3433:C7F0:188F:FDE3:9FBE:D0B0</ip>
</contributor>
<model>wikitext</model>
<format>text/x-wiki</format>
<text xml:space="preserve">{{monththisyear|4}}
'''April''' is the fourth [[month]] of the [[year]], and comes between [[March]] and [[May]]. It is one of four months to have 30 [[day]]s.
April always begins on the same day of week as [[July]], and additionally, [[January]] in leap years. April always ends on the same day of the week as [[December]].
April's [[flower]]s are the [[Sweet Pea]] and [[Asteraceae|Daisy]]. Its [[birthstone]] is the [[diamond]]. The meaning of the diamond is innocence.
简而言之,对于最终产品,我希望它能够搜索 page
元素以找到 titles
,它将在其中搜索我输入的特定短语,然后return 该页面内的 text
元素,如果找不到结果,那么它 return 是最相似的前三个。这可能吗,有人可以帮忙吗?我对所使用的库很灵活,这意味着它不必是 bs4
。谢谢。
编辑:
我刚刚发现,如果我从上面的代码中删除 recursive=False
,它会 returns 1
而不是 0
。不知道为什么?
编辑:
我也试过下面的代码,但它也是 returns 0
。贝娄也是我想要的最终产品的例子,都在字典里。
import xml.etree.ElementTree as ET
def get_data():
tree = ET.parse(open("wiki.xml"))
root = tree.getroot()
results = {}
for title in root.findall('./page/title') and text in root.findall('./page/revision/text'):
results[title] = text
return results
r = get_data()
print(len(r))
编辑:
我刚刚在下面的 xml
文件中尝试了一些代码...
<vehicles>
<car name="BMW">
<model>850 CSI</model>
<speed>1000</speed>
</car>
<car name="Mercedes">
<model>SL65</model>
<speed>900</speed>
</car>
<car name="Jaguar">
<model>EV400</model>
<speed>850</speed>
</car>
<car name="Ferrari">
<model>Enzo</model>
<speed>2</speed>
</car>
</vehicles>
这是我使用的代码...
from bs4 import BeautifulSoup
def get_data():
soup = BeautifulSoup(open('test.xml'), 'lxml')
count = 0
for text in soup.select("vehicles car model"):
count += 1
return count
r = get_data()
print(r)
此脚本 returned 4
这是正确的数字。但是,当我将 vehicles car model
更改为 page revision text
并在 wiki.xml
文件上尝试时,它不起作用并且仍然 returns 1
。注意:在 wiki
文件中有更多的文本元素,然后我有时间自己计算,所以 1
绝对不正确。
编辑:
这是我一直试图用来解析文件的代码...
def parser(file_name="wiki.xml",save_to="weboffline.csv",url='http://www.mediawiki.org/xml/export-0.10/'):
doc = tree.parse(file_name)
titles = []
texts = []
for title in doc.findall('.//mediawiki{'+url+'}//page//title'):
titles.append(title)
for text in doc.findall('.//mediawiki{'+url+'}//page//revision//text'):
texts.append(text)
with open(save_to, mode='w') as file:
writer = csv.writer(file)
writer.writerow(['TITLES', 'TEXT'])
for items in zip(titles,texts):
writer.writerow(items)
然而,这个 return 的 CSV 文件仅在 TITLES,TEXT
中。有人有解决办法吗?
recursive=False
只会找到顶级元素的直接 children。在你展示的例子中,只有 <mediawiki>
的 children 是 <siteinfo>
和 <page>
,没有 <text>
,所以 0 是正确的。通过递归到结构中,我们发现单个 <text>
元素作为 child,同时递归到 <page>
,然后是 <revision>
。所以 1 是正确的!
如果你想像这样找到 children-of-children(等等),你必须使用 recursive=True
(这是通过省略 recursive
选项暗示的)。
import xml.etree.ElementTree as etree
import codecs
import csv
import time
import os
def hms_string(sec_elapsed):
h = int(sec_elapsed / (60 * 60))
m = int((sec_elapsed % (60 * 60)) / 60)
s = sec_elapsed % 60
return "{}:{:>02}:{:>05.2f}".format(h, m, s)
def strip_tag_name(t,elem):
t = elem.tag
idx = k = t.rfind("}")
if idx != -1:
t = t[idx + 1:]
return t
def parseWikiFile():
PATH_WIKI_XML = ''
FILENAME_WIKI = 'resources/wiki.xml'
FILENAME_PAGES = 'resources/weboffline.csv'
ENCODING = "utf-8"
pathWikiXML = os.path.join(PATH_WIKI_XML, FILENAME_WIKI)
pathPages = os.path.join(PATH_WIKI_XML, FILENAME_PAGES)
pageCount = 0
totalCount = 0
title = None
start_time = time.time()
with codecs.open(pathPages, "w", ENCODING) as pagesFH:
pageWriter = csv.writer(pagesFH, quoting=csv.QUOTE_MINIMAL)
pageWriter.writerow(['title', 'text'])
for event, elem in etree.iterparse(pathWikiXML, events=('start', 'end')):
tname = strip_tag_name(elem.tag,elem)
if event == 'start':
if tname == 'page':
title = ''
text = ''
else:
continue
else:
if tname == 'title':
title = elem.text
elif tname == 'text':
text = elem.text
elif tname == 'page':
totalCount += 1
pageCount += 1
pageWriter.writerow([title, text])
if totalCount > 1 and (totalCount % 100000) == 0:
print("{:,}".format(totalCount))
elem.clear()
elapsed_time = time.time() - start_time
print("Total pages: {:,}".format(totalCount))
print("Text pages: {:,}".format(pageCount))
print("Elapsed time: {}".format(hms_string(elapsed_time)))
这是我从 this 网站修改的代码,效果非常好。我想我最初想做的只是寻找元素作为位置而不是标签名称。无论如何,这有效。
我目前正在使用下面的代码来计算 xml
文件中 text
元素的数量。
from bs4 import BeautifulSoup
soup = BeautifulSoup(open('wiki.xml'), 'lxml')
count = 0
for text in soup.find_all('text', recursive=False):
count += 1
print(count)
由于文件的大小,我无法显示完整的 xml
文件,但这里有一个简短的片段...
<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en">
<siteinfo>
<sitename>Wikipedia</sitename>
<dbname>simplewiki</dbname>
<base>https://simple.wikipedia.org/wiki/Main_Page</base>
<generator>MediaWiki 1.30.0-wmf.14</generator>
<case>first-letter</case>
<namespaces>
<namespace key="-2" case="first-letter">Media</namespace>
<namespace key="-1" case="first-letter">Special</namespace>
<namespace key="0" case="first-letter" />
<namespace key="1" case="first-letter">Talk</namespace>
<namespace key="2" case="first-letter">User</namespace>
<namespace key="3" case="first-letter">User talk</namespace>
<namespace key="4" case="first-letter">Wikipedia</namespace>
<namespace key="5" case="first-letter">Wikipedia talk</namespace>
<namespace key="6" case="first-letter">File</namespace>
<namespace key="7" case="first-letter">File talk</namespace>
<namespace key="8" case="first-letter">MediaWiki</namespace>
<namespace key="9" case="first-letter">MediaWiki talk</namespace>
<namespace key="10" case="first-letter">Template</namespace>
<namespace key="11" case="first-letter">Template talk</namespace>
<namespace key="12" case="first-letter">Help</namespace>
<namespace key="13" case="first-letter">Help talk</namespace>
<namespace key="14" case="first-letter">Category</namespace>
<namespace key="15" case="first-letter">Category talk</namespace>
<namespace key="828" case="first-letter">Module</namespace>
<namespace key="829" case="first-letter">Module talk</namespace>
<namespace key="2300" case="first-letter">Gadget</namespace>
<namespace key="2301" case="first-letter">Gadget talk</namespace>
<namespace key="2302" case="case-sensitive">Gadget definition</namespace>
<namespace key="2303" case="case-sensitive">Gadget definition talk</namespace>
<namespace key="2600" case="first-letter">Topic</namespace>
</namespaces>
</siteinfo>
<page>
<title>April</title>
<ns>0</ns>
<id>1</id>
<revision>
<id>5753795</id>
<parentid>5732421</parentid>
<timestamp>2017-08-11T21:06:32Z</timestamp>
<contributor>
<ip>2602:306:3433:C7F0:188F:FDE3:9FBE:D0B0</ip>
</contributor>
<model>wikitext</model>
<format>text/x-wiki</format>
<text xml:space="preserve">{{monththisyear|4}}
'''April''' is the fourth [[month]] of the [[year]], and comes between [[March]] and [[May]]. It is one of four months to have 30 [[day]]s.
April always begins on the same day of week as [[July]], and additionally, [[January]] in leap years. April always ends on the same day of the week as [[December]].
April's [[flower]]s are the [[Sweet Pea]] and [[Asteraceae|Daisy]]. Its [[birthstone]] is the [[diamond]]. The meaning of the diamond is innocence.
简而言之,对于最终产品,我希望它能够搜索 page
元素以找到 titles
,它将在其中搜索我输入的特定短语,然后return 该页面内的 text
元素,如果找不到结果,那么它 return 是最相似的前三个。这可能吗,有人可以帮忙吗?我对所使用的库很灵活,这意味着它不必是 bs4
。谢谢。
编辑:
我刚刚发现,如果我从上面的代码中删除 recursive=False
,它会 returns 1
而不是 0
。不知道为什么?
编辑:
我也试过下面的代码,但它也是 returns 0
。贝娄也是我想要的最终产品的例子,都在字典里。
import xml.etree.ElementTree as ET
def get_data():
tree = ET.parse(open("wiki.xml"))
root = tree.getroot()
results = {}
for title in root.findall('./page/title') and text in root.findall('./page/revision/text'):
results[title] = text
return results
r = get_data()
print(len(r))
编辑:
我刚刚在下面的 xml
文件中尝试了一些代码...
<vehicles>
<car name="BMW">
<model>850 CSI</model>
<speed>1000</speed>
</car>
<car name="Mercedes">
<model>SL65</model>
<speed>900</speed>
</car>
<car name="Jaguar">
<model>EV400</model>
<speed>850</speed>
</car>
<car name="Ferrari">
<model>Enzo</model>
<speed>2</speed>
</car>
</vehicles>
这是我使用的代码...
from bs4 import BeautifulSoup
def get_data():
soup = BeautifulSoup(open('test.xml'), 'lxml')
count = 0
for text in soup.select("vehicles car model"):
count += 1
return count
r = get_data()
print(r)
此脚本 returned 4
这是正确的数字。但是,当我将 vehicles car model
更改为 page revision text
并在 wiki.xml
文件上尝试时,它不起作用并且仍然 returns 1
。注意:在 wiki
文件中有更多的文本元素,然后我有时间自己计算,所以 1
绝对不正确。
编辑:
这是我一直试图用来解析文件的代码...
def parser(file_name="wiki.xml",save_to="weboffline.csv",url='http://www.mediawiki.org/xml/export-0.10/'):
doc = tree.parse(file_name)
titles = []
texts = []
for title in doc.findall('.//mediawiki{'+url+'}//page//title'):
titles.append(title)
for text in doc.findall('.//mediawiki{'+url+'}//page//revision//text'):
texts.append(text)
with open(save_to, mode='w') as file:
writer = csv.writer(file)
writer.writerow(['TITLES', 'TEXT'])
for items in zip(titles,texts):
writer.writerow(items)
然而,这个 return 的 CSV 文件仅在 TITLES,TEXT
中。有人有解决办法吗?
recursive=False
只会找到顶级元素的直接 children。在你展示的例子中,只有 <mediawiki>
的 children 是 <siteinfo>
和 <page>
,没有 <text>
,所以 0 是正确的。通过递归到结构中,我们发现单个 <text>
元素作为 child,同时递归到 <page>
,然后是 <revision>
。所以 1 是正确的!
如果你想像这样找到 children-of-children(等等),你必须使用 recursive=True
(这是通过省略 recursive
选项暗示的)。
import xml.etree.ElementTree as etree
import codecs
import csv
import time
import os
def hms_string(sec_elapsed):
h = int(sec_elapsed / (60 * 60))
m = int((sec_elapsed % (60 * 60)) / 60)
s = sec_elapsed % 60
return "{}:{:>02}:{:>05.2f}".format(h, m, s)
def strip_tag_name(t,elem):
t = elem.tag
idx = k = t.rfind("}")
if idx != -1:
t = t[idx + 1:]
return t
def parseWikiFile():
PATH_WIKI_XML = ''
FILENAME_WIKI = 'resources/wiki.xml'
FILENAME_PAGES = 'resources/weboffline.csv'
ENCODING = "utf-8"
pathWikiXML = os.path.join(PATH_WIKI_XML, FILENAME_WIKI)
pathPages = os.path.join(PATH_WIKI_XML, FILENAME_PAGES)
pageCount = 0
totalCount = 0
title = None
start_time = time.time()
with codecs.open(pathPages, "w", ENCODING) as pagesFH:
pageWriter = csv.writer(pagesFH, quoting=csv.QUOTE_MINIMAL)
pageWriter.writerow(['title', 'text'])
for event, elem in etree.iterparse(pathWikiXML, events=('start', 'end')):
tname = strip_tag_name(elem.tag,elem)
if event == 'start':
if tname == 'page':
title = ''
text = ''
else:
continue
else:
if tname == 'title':
title = elem.text
elif tname == 'text':
text = elem.text
elif tname == 'page':
totalCount += 1
pageCount += 1
pageWriter.writerow([title, text])
if totalCount > 1 and (totalCount % 100000) == 0:
print("{:,}".format(totalCount))
elem.clear()
elapsed_time = time.time() - start_time
print("Total pages: {:,}".format(totalCount))
print("Text pages: {:,}".format(pageCount))
print("Elapsed time: {}".format(hms_string(elapsed_time)))
这是我从 this 网站修改的代码,效果非常好。我想我最初想做的只是寻找元素作为位置而不是标签名称。无论如何,这有效。