이거 모르면 크롤링 못한다! 웹 크롤링의 기본, XPath 알아보기 - 심화편

XPath의 와일드카드, 노드, 함수를 이해하여 XML 문서에서 데이터를 정확하게 찾고 추출하는 방법을 알아봅니다.

0. 개요

XPath 1편에서는 웹크롤링에 있어 필수적인 XPath의 개념과 기본 문법에 대해 다뤄봤었는데요, 2편에서는 XPath의 심화 내용에 대해서 알려드리겠습니다.
 
 

1. 와일드카드에 대한 이해

심화 내용으로 들어가기 전, XPath에서 '*(와일드카드)'가 가지는 의미에 대해서 필수적인 이해가 필요합니다.
  • (와일드카드)는 XPath에서 어떠한 요소에든 매칭되며, 모든 요소를 선택하는데 사용됩니다. 예시를 들어 설명하겠습니다.
//div[contains(@class, "aa")]
위의 XPath는 'aa'를 포함하는 class명을 가진 div 요소를 나타냅니다. 여기서 div 대신 와일드카드를 사용하면 어떻게 될까요?
//*[contains(@class, "aa")]
위의 XPath에서 ‘*’는 모든 요소에 일치하므로 위 XPath는 ‘aa’를 포함하는 class명을 가진 모든 요소를 나타내게 됩니다.
 
 

2. XPath 계층 구조의 이해

이제 XPath의 심화 내용으로 들어가보겠습니다.
다음은 간단한 HTML 코드입니다.
<AAA> <BBB> <CCC/> <DDD/> </BBB> <EEE> <FFF> <GGG/> <GGG/> <III> <JJJ/> </III> </FFF> </EEE> <KKK> <LLL/> </KKK> </AAA>
HTML 코드의 각 요소와 속성들은 계층 관계를 이루고 있으며 XPath에서는 이러한 계층 관계를 트리(Tree) 구조로 표현합니다. 이때 축은 트리 구조에서 노드(node : 데이터 지점, 단위)를 참조하고 선택하는 데 사용되는 방향 또는 관계를 나타냅니다. 축에는 self 축, parent 축, child 축 등이 있는데 아래에서 예시를 사용하여 하나씩 설명드리겠습니다.
위 요소들의 계층 구조를 그림으로 나타내면 다음과 같습니다.
 
notion image
이제 축을 사용하여 어떻게 노드를 나타낼 수 있는지 알아보도록 하겠습니다.
 
 

3. 노드(node)의 표현 방법

 

3.1. self

: 현재 노드를 자체를 나타냅니다.
/AAA/self::*
위의 XPath의 결과로는 현재 노드인 <AAA> 요소가 선택됩니다.
 

3.2. parent

: 현재 노드의 부모 노드를 나타냅니다.
/AAA/EEE/FFF/parent::*
위의 XPath의 결과로는 현재 노드인 <FFF> 요소의 부모 노드인 <EEE> 요소가 선택됩니다.
notion image
 

3.3. child : 현재 노드의 자식 노드를 나타냅니다.

/AAA/EEE/FFF/child::*
위의 XPath의 결과로는 현재 노드인 <FFF> 요소의 자식 노드인 <GGG>, <GGG>, <III>가 모두 선택됩니다.
notion image
여기서 <III> 요소만을 고르고 싶다면 다음과 같이 XPath를 수정할 수 있습니다.
/AAA/EEE/FFF/child::III
또한, 두 <GGG> 요소 중 첫번째 <GGG> 요소를 고르고 싶다면 다음과 같이 수정할 수 있습니다.
/AAA/EEE/FFF/child::GGG[1]
이때, 대부분의 다른 프로그래밍 언어와는 다르게 XPath에서는 인덱스가 1부터 시작함을 주의해야 합니다!
 

3.3. ancestor

: 현재 노드의 모든 조상 노드를 나타냅니다.
/AAA/EEE/FFF/ancestor::*
위의 XPath의 결과로는 현재 노드인 <FFF> 요소의 조상 노드인 <EEE>, <AAA>가 모두 선택됩니다.
notion image
 

3.4. descendant

: 현재 노드의 모든 후손 노드를 나타냅니다.
/AAA/EEE/FFF/descendant::*
위의 XPath의 결과로는 현재 노드인 <FFF> 요소의 후손 노드인 <GGG>, <GGG>, <III>, <JJJ>가 모두 선택됩니다.
notion image
 

3.5. ancestor-or-self

: 현재 노드와 현재 노드의 모든 조상 노드를 나타냅니다.
/AAA/EEE/FFF/ancestor-or-self::*
위의 XPath의 결과로는 현재 노드인 <FFF> 요소 자신과 조상 노드가 모두 선택되어 <FFF>, <EEE>, <AAA>가 모두 선택됩니다.
 

3.6. descendant-or-self

: 현재 노드와 현재 노드의 모든 후손 노드를 나타냅니다.
/AAA/EEE/FFF/descendant-or-self::*
위의 XPath의 결과로는 현재 노드인 <FFF> 요소 자신과 후손 노드가 모두 선택되어 <FFF>, <GGG>, <GGG>, <III>, <JJJ>가 모두 선택됩니다.
 

3.7. following

: 현재 노드의 태그를 종료한 뒤에 나오는 모든 노드를 나타냅니다.
/AAA/EEE/following::*
위의 XPath의 결과로는 현재 노드인 <EEE> 다음에 나오는 노드인 <FFF>, <GGG>, <GGG>, <III>, <JJJ>, <KKK>, <LLL>이 모두 선택됩니다.
 
notion image

3.8. preceding

: 현재 노드의 태그가 시작되기 전에 나오는 모든 노드를 나타냅니다.
/AAA/EEE/preceding::*
위의 XPath의 결과로는 현재 노드인 <EEE> 이전에 나오는 노드인 <BBB>, <CCC>, <DDD>가 모두 선택됩니다.
notion image
 

3.9. following-sibling

: 현재 노드 다음에 나오는 모든 형제 노드를 나타냅니다.
/AAA/EEE/following-sibling::*
위의 XPath의 결과로는 현재 노드인 <EEE> 다음에 나오는 형제 노드인 <KKK>가 선택됩니다.
notion image
 

3.10. preceding-sibling

: 현재 노드 이전에 나오는 모든 형제 노드를 나타냅니다.
/AAA/EEE/preceding-sibling::*
위의 XPath의 결과로는 현재 노드인 <EEE> 이전에 나오는 형제 노드인 <BBB> 가 선택됩니다.
notion image
지금까지 XPath에서 노드를 나타내기 위해 사용되는 축에 대해 알아보았습니다.
추가로, XPath에서 사용할 수 있는 또 다른 두 함수에 대해 알아보겠습니다.
 
 

4. XPath에 사용하는 함수

 

4.1. count

: 특정 조건에 맞는 노드의 개수를 반환합니다.
#class 속성 값이 ‘example인 div 요소의 개수를 반환 count(//div[@class="example"]) #p 요소의 총 개수를 반환 count(//p)
 

4.2. position

: 현재 노드의 위치를 반환합니다. (위치는 1부터 시작하여 순차적으로 증가합니다.)
<root> <item>Item 1</item> <item>Item 2</item> <item>Item 3</item> </root>
예를 들어 다음과 같은 xml 코드가 있을 때 XPath를 다음과 같이 작성할 수 있습니다.
//item[position() = 2]
position 함수를 사용하여 3개의 item 요소 중 두번째 item 요소를 선택할 수 있습니다.
 
 

5. 결론

지금까지 XPath의 심화 내용까지 알아보았습니다. 기본편부터 심화편까지 마스터하셨다면, 이제 XPath를 통해 XML 문서에서 원하는 요소를 정확하게 찾고 데이터를 추출하는데 필요한 기초지식은 어느정도 학습되신 것이라 보아도 무방합니다.
XPath는 XML 문서를 탐색하고 조작하는 강력한 도구로, 실무에서 데이터 스크래핑, 웹 스크래핑, XML 기반 웹 서비스에서 데이터 추출 등 다양한 분야에 활용되고 있습니다. XPath를 사용하여 데이터를 효율적으로 추출하고 활용하는 데 성공하시길 바랍니다!