2011-01-14 3 views
13

나는이 같은 XML이 :효율적인 방법은

<a> 
    <b>hello</b> 
    <b>world</b> 
</a> 
<x> 
    <y></y> 
</x> 
<a> 
    <b>first</b> 
    <b>second</b> 
    <b>third</b> 
</a> 

나는 모든 <a><b> 태그를 반복 할 필요를,하지만 난 문서에 얼마나 그들 중 많은 모른다.

from lxml import etree 

doc = etree.fromstring(xml) 

atags = doc.xpath('//a') 
for a in atags: 
    btags = a.xpath('b') 
    for b in btags: 
      print b 

그것은 작동하지만 난 꽤 큰 파일을 가지고 있고, cProfilexpath 사용하기 매우 비싼 것을 저에게 보여줍니다 그래서 나는 그것을 처리 할 수 ​​xpath를 사용합니다.

궁금한 점이 있다면 무한히 많은 xml 요소를 반복 할 수있는 효율적인 방법이 있습니까?

+1

매우 유용합니다. –

답변

17

XPath가 빠릅니다. 당신의 XPath의 수는 하나의 호출을 줄일 수

doc = etree.fromstring(xml) 
btags = doc.xpath('//a/b') 
for b in btags: 
    print b.text 

를 그만큼 빨리하지 않으면, 당신은 Liza Daly's fast_iter을 시도 할 수 있습니다. 이렇게하면 전체 XML을 먼저 etree.fromstring으로 처리 할 필요가 없으며 하위 노드를 방문한 후에 상위 노드가 버려집니다. 이 두 가지 모두 메모리 요구 사항을 줄이는 데 도움이됩니다. 아래는 더 이상 필요하지 않은 다른 요소를 제거하는 데 더 적극적인 a modified version of fast_iter입니다. 너무 당신에게 유용 읽기 증명할 수 큰 XML 파일을 구문 분석에

def fast_iter(context, func, *args, **kwargs): 
    """ 
    fast_iter is useful if you need to free memory while iterating through a 
    very large XML file. 

    http://lxml.de/parsing.html#modifying-the-tree 
    Based on Liza Daly's fast_iter 
    http://www.ibm.com/developerworks/xml/library/x-hiperfparse/ 
    See also http://effbot.org/zone/element-iterparse.htm 
    """ 
    for event, elem in context: 
     func(elem, *args, **kwargs) 
     # It's safe to call clear() here because no descendants will be 
     # accessed 
     elem.clear() 
     # Also eliminate now-empty references from the root node to elem 
     for ancestor in elem.xpath('ancestor-or-self::*'): 
      while ancestor.getprevious() is not None: 
       del ancestor.getparent()[0] 
    del context 

def process_element(elt): 
    print(elt.text) 

context=etree.iterparse(io.BytesIO(xml), events=('end',), tag='b') 
fast_iter(context, process_element) 

Liza Daly's article. 기사에 따르면, fast_iter의 lxml은 cElementTreeiterparse보다 빠를 수 있습니다. (표 1 참조). 이 모든 메모리를 저장하지 않는

import lxml.etree as ET 
    for event, elem in ET.iterparse(filelike_object): 
     if elem.tag == "a": 
      process_a(elem) 
      for child in elem: 
       process_child(child) 
      elem.clear() # destroy all child elements 
     elif elem.tag != "b": 
      elem.clear() 

참고,하지만 난이 기술을 사용하여 기가 이상의 XML 스트림을 통해 웨이드 할 수있었습니다 :

+0

fast_iter 코드에서'doc = etree.fromstring (xml)'의 목적은 무엇입니까 ?? –

+0

@John Machin : 복사 - 붙여 넣기 오류. 그것을 지적 주셔서 감사합니다. – unutbu

+0

iterparse speed war : 기사가 말하듯이 lxml은 특정 태그 하나를 선택하면 일반 구문 분석 (여러 태그를 검사해야 함)이 빠르면 cElementTree가 빠릅니다. –

10

어때 대략 iter?

>>> for tags in root.iter('b'):   # root is the ElementTree object 
...  print tags.tag, tags.text 
... 
b hello 
b world 
b first 
b second 
b third 
+0

해당 링크가 작동하지 않습니다. http://lxml.de/tutorial.html#tree-iteration –

5

사용 iterparse.

import xml.etree.cElementTree as ET을 시도 ... 파이썬 함께 제공하고 iterparsethe lxml docs에 따르면, lxml.etreeiterparse보다 빠른 :

에게

"" "대용량 파일의 높은 파서 처리량을 요구하는 애플리케이션을 위해, 그리고 그 작은을 직렬화가 필요없는 경우 cET를 선택하는 것이 가장 좋습니다. 소량의 데이터를 추출하거나 메모리에 맞지 않는 대규모 XML 데이터 집합에서 정보를 집계하는 iterparse 응용 프로그램의 경우에도 마찬가지입니다. 그러나 왕복 성능의 경우 lxml은 따라서 입력 문서가 출력보다 크게 나오지 않으면 lxml이 확실한 승자가됩니다. "" "

-2

BS4는 메가 바이트에 "꽤 큰"번역하십시오이

from bs4 import BeautifulSoup 
raw_xml = open(source_file, 'r') 
soup = BeautifulSoup(raw_xml) 
soup.find_all('tags') 
관련 문제