2013-12-06 3 views
12

Я новичок в разборе xml и Python, так что несите меня. Я использую lxml для анализа дампа wiki, но я просто хочу, чтобы для каждой страницы, ее названия и текста.Пустой список вернулся из ElementTree findall

Сейчас у меня есть это:

from xml.etree import ElementTree as etree 

def parser(file_name): 
    document = etree.parse(file_name) 
    titles = document.findall('.//title') 
    print titles 

В названиях момент ничего не возвращает. Я посмотрел на предыдущие ответы вроде этого: ElementTree findall() returning empty list и документацию по lxml, но большинство вещей, похоже, были адаптированы к разбору HTML.

Это часть моего XML:

<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.7/"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.7/ http://www.mediawiki.org/xml/export-0.7.xsd" version="0.7" xml:lang="en"> 
    <siteinfo> 
    <sitename>Wikipedia</sitename> 
<base>http://en.wikipedia.org/wiki/Main_Page</base> 
<generator>MediaWiki 1.20wmf9</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="100" case="first-letter">Portal</namespace> 
    <namespace key="101" case="first-letter">Portal talk</namespace> 
    <namespace key="108" case="first-letter">Book</namespace> 
    <namespace key="109" case="first-letter">Book talk</namespace> 
</namespaces> 
    </siteinfo> 
    <page> 
    <title>Aratrum</title> 
    <ns>0</ns> 
    <id>65741</id> 
    <revision> 
    <id>349931990</id> 
    <parentid>225434394</parentid> 
    <timestamp>2010-03-15T02:55:02Z</timestamp> 
    <contributor> 
    <ip>143.105.193.119</ip> 
    </contributor> 
    <comment>/* Sources */</comment> 
    <sha1>2zkdnl9nsd1fbopv0fpwu2j5gdf0haw</sha1> 
    <text xml:space="preserve" bytes="1436">'''Aratrum''' is the Latin word for [[plough]], and &quot;arotron&quot; (αροτρον) is the [[Greek language|Greek]] word. The [[Ancient Greece|Greeks]] appear to have had diverse kinds of plough from the earliest historical records. [[Hesiod]] advised the farmer to have always two ploughs, so that if one broke the other might be ready for use. These ploughs should be of two kinds, the one called &quot;autoguos&quot; (αυτογυος, &quot;self-limbed&quot;), in which the plough-tail was of the same piece of timber as the share-beam and the pole; and the other called &quot;pekton&quot; (πηκτον, &quot;fixed&quot;), because in it, three parts, which were of three kinds of timber, were adjusted to one another, and fastened together by nails. 

The ''autoguos'' plough was made from a [[sapling]] with two branches growing from its trunk in opposite directions. In ploughing, the trunk served as the pole, one of the two  branches stood upwards and became the tail, and the other penetrated the ground and, sometimes shod with bronze or iron, acted as the [[ploughshare]]. 

==Sources== 
Based on an article from ''A Dictionary of Greek and Roman Antiquities,'' John Murray,  London, 1875. 
ἄρατρον 

==External links== 
*[http://penelope.uchicago.edu/Thayer/E/Roman/Texts/secondary/SMIGRA*/Aratrum.html Smith's  Dictionary article], with diagrams, further details, sources. 
[[Category:Agricultural machinery]] 
[[Category:Ancient Greece]] 
[[Category:Animal equipment]]</text> 
</revision> 
</page> 

Я также попытался iterparse, а затем напечатать тег элемента он находит:

for e in etree.iterparse(file_name): 
    print e.tag 

но жалуется на е не с атрибутом тега.

EDIT: screenshot

ответ

22

Проблема в том, что вы не учитываете пространства имен XML. XML-документ (и все его элементы) находится в пространстве имен http://www.mediawiki.org/xml/export-0.7/. Для того, чтобы заставить его работать, вам необходимо изменить

titles = document.findall('.//title') 

в

titles = document.findall('.//{http://www.mediawiki.org/xml/export-0.7/}title') 

Пространство имен также могут быть предоставлены через namespaces параметра:

NSMAP = {'mw':'http://www.mediawiki.org/xml/export-0.7/'} 
titles = document.findall('.//mw:title', namespaces=NSMAP) 

Это работает в Python 2.7, но не объясняется в Python 2.7 documentation (лучше подходит Python 3.3 documentation).

См. Также http://effbot.org/zone/element-namespaces.htm и этот вопрос с ответом: Parsing XML with namespace in Python via 'ElementTree'.


Проблема с iterparse() вызвана тем, что эта функция обеспечивает (event, element) кортежей (а не только элементы). Для того, чтобы получить имя тега, изменить

for e in etree.iterparse(file_name): 
    print e.tag 

к этому:

for e in etree.iterparse(file_name): 
    print e[1].tag 
+0

Не существует ли другой метод, который заменяет пространства имен как еще один параметр для lxml? В любом случае это работает! Так что спасибо тебе! Я просто собираюсь добавить текст заголовка для других людей, рассматривающих этот вопрос. – liloka

+2

Это именно то, что я искал! Спасибо! – Apolymoxic

0

Во-первых, вам нужно найти родительский элемент, page. Я не знаю, сколько слоев это вложенное, но как только вы найдете его, вы можете получить immmidiately title тега:

>>> page_tag = ET.fromstring(xdata) 
>>> title_tag = page_tag.find('title') 
>>> title_tag.text 
'Aratrum' 

С дополнительной информацией затопленной, вы можете сделать это:

def parser(file_name): 
    document = etree.parse(file_name) 
    titles = [] 
    for page_tag in document.findall('page'): 
     titles.append(page_tag.find('title').text) 
    return titles 

Надеюсь, это поможет!

+0

Простите меня, но что именно это XData? Я пробовал корень проанализированного XML-файла и анализируемый документ напрямую, но я просто получаю ошибки. – liloka

+0

О, xdata является частью вашего xml.Весь тег 'page'. Если у него все еще есть родитель, отличный от root, получите его от родителя. Если это не так, вы можете искать 'root.findall ('page')' прямо сейчас. – aIKid

+0

... и как мне создать этот объект? > .o – liloka