웹 크롤링은 데이터를 자동으로 수집하고 처리하는 데 매우 유용합니다. 특히, HTML 구조에서 특정 위치에 있는 요소를 선택할 때 nth-child를 활용하면 효율적인 데이터 수집이 가능합니다. 같은 DOM 패턴인데 그 중에 몇번째 데이터를 찾고 싶다 이런경우에 사용할 수 있는 방법을 공개합니다. 그리고 nth-of-type도 있는데 그 차이점도 알아두시면 크롤링할때 도움이 될것입니다. classs나 id에 변수명이 있으면 좋지만 없을때 활용해보세요
1. nth-child란?
nth-child는 CSS 선택자 중 하나로, HTML 구조에서 특정 위치에 있는 자식 요소를 선택하는 데 사용됩니다.
예를 들어, 아래와 같은 HTML 구조가 있다고 가정합시다:
<ul>
<li>첫 번째 항목</li>
<li>두 번째 항목</li>
<li>세 번째 항목</li>
</ul>
혹은
<table>
<tr>
<th scope="col">제목</th>
<th scope="col">날짜</th>
<th scope="col">조회수</th>
</tr>
<tr>
<td>우리나라 근대사</td>
<td>2024.10.24(목) 14:00</td>
<td> 1,841
<td>
</tr>
<tr>
<td>세계인물 역사편</td>
<td>2024.11.24(목) 14:00</td>
<td> 12,401
<td>
</tr>
</table>
이런경우 li나 td의 몇번째 요소를 조회하고 싶을때 사용이 가능합니다.
- li:nth-child(1)은 첫 번째 li 요소를 선택합니다.
- li:nth-child(2)는 두 번째 li 요소를 선택합니다.
- li:nth-child(odd)는 홀수 번째 li 요소(1, 3, 5...)를 선택합니다.
같이보면 좋은 글
실제 이런 경우가 개발을 하다보면 많이 존재하는데 웹상에 데이터를 조회해서 DOM구조를 파싱할때 발생했었습니다. 이를 이용한 예제를 한번 소개합니다.
from bs4 import BeautifulSoup
data="""
<table>
<tr>
<td>이름</td>
<td>나이</td>
</tr>
<tr>
<td>홍길동</td>
<td>25</td>
</tr>
<tr>
<td>김철수</td>
<td>30</td>
</tr>
</table>
"""
soup = BeautifulSoup(data, 'html.parser')
#tr 데이터를 가져오기
data=soup.select("tr")
for item in data:
#td의 첫번째 이름을 가져오기
name_cell = (item.select_one('td:nth-child(1)').text).strip()
#td의 두번째 나이를 가져오기
age_cell = (item.select_one('td:nth-child(2)').text).strip()
#출력
print("이름:"+name_cell+"\t,나이:"+age_cell)
여기서 주의할 부분이 있습니다. nth-child의 친구가 있는데 이 친구 이름은 nth-of-type 입니다. n 번째 요소를 찾는것은 같지만 살짝 다른점이 있습니다.
- nth-child(n): 부모의 모든 자식 중 n번째 요소를 선택합니다.
- nth-of-type(n): 특정 태그 종류 내에서 n번째 요소를 선택합니다.
목적은 두번째 p 태그의 값인 "두 번째 단락"의 값을 조회하는것입니다. 이때 nth-child를 쓰면 2번째 요소는 span이기 때문에 원하는 데이터를 찾지 못합니다. 이럴때는 두번째 타입을 써서 데이터를 가져와야지 정상적으로 조회할 수 있습니다.
from bs4 import BeautifulSoup
data="""
<div>
<p>첫 번째 단락</p>
<span>첫 번째 스팬</span>
<p>두 번째 단락</p>
</div>
"""
soup = BeautifulSoup(data, 'html.parser')
#에러발생
data=soup.select_one('p:nth-child(2)')
#정상작동
data1=soup.select_one('p:nth-of-type(2)')
print(data)
print(data1)
같이보면 좋은 글