복붙노트

[PYTHON] XML 요소를 통해 반복하는 효율적인 방법

PYTHON

XML 요소를 통해 반복하는 효율적인 방법

나는 이런 식으로 XML을 가지고 :

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

모든 태그를 반복해야하지만 문서에 얼마나 많은 태그가 있는지 모릅니다. 그래서 그것을 처리하는 xpath 사용 :

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

그것은 작동하지만 꽤 큰 파일을 가지고 있고, cProfile은 xpath가 사용하기에 매우 비쌉니다.

아마도 무한히 많은 xml 요소를 반복하는 효율적인 방법이 있을까요?

해결법

  1. ==============================

    1.XPath는 빠릅니다. XPath 호출 수를 1로 줄일 수 있습니다.

    XPath는 빠릅니다. XPath 호출 수를 1로 줄일 수 있습니다.

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

    그렇게 빠르지 않으면 Liza Daly의 fast_iter를 시도해 볼 수 있습니다. 이것은 우선 전체 XML을 etree.fromstring으로 처리 할 필요가 없다는 장점이 있으며, 부모 노드는 자식을 방문한 후에 버려집니다. 이 두 가지 모두 메모리 요구 사항을 줄이는 데 도움이됩니다. 다음은 더 이상 필요없는 다른 요소를 제거하는 데 더 적극적인 fast_iter의 수정 된 버전입니다.

    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)
    

    큰 XML 파일을 파싱하는 Liza Daly의 기사가 여러분에게 유용한 읽을 거리가 될 것입니다. 이 기사에 따르면 fast_iter가있는 lxml은 cElementTree의 iterparse보다 빠를 수 있습니다. (표 1 참조).

  2. ==============================

    2.iter는 어때?

    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
    
  3. ==============================

    3.iterparse 사용 :

    iterparse 사용 :

       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()
    

    이것은 모든 메모리를 저장하지는 않지만이 기술을 사용하여 GB 이상의 XML 스트림을 탐색 할 수있었습니다.

    import xml.etree.cElementTree를 ET로 사용해보십시오 ... lxml docs에 따르면, it는 Python과 함께 제공되며 iterparse는 lxml.etree iterparse보다 빠릅니다.

    큰 파일의 높은 파서 처리량이 필요하고 직렬화가 거의 필요없는 응용 프로그램의 경우 cET가 가장 좋습니다. 소량의 데이터를 추출하거나 그렇지 않은 대형 XML 데이터 집합에서 정보를 집계하는 iterparse 응용 프로그램의 경우 " 그러나 라운드 트립 성능의 경우 lxml은 여러 번 더 빠르다는 경향이 있으므로 입력 문서가 출력보다 크게 나오지 않으면 lxml이 확실한 승자가됩니다. ""

  4. ==============================

    4.bs4는이 작업에 매우 유용합니다.

    bs4는이 작업에 매우 유용합니다.

    from bs4 import BeautifulSoup
    raw_xml = open(source_file, 'r')
    soup = BeautifulSoup(raw_xml)
    soup.find_all('tags')
    
  5. from https://stackoverflow.com/questions/4695826/efficient-way-to-iterate-throught-xml-elements by cc-by-sa and MIT license