맛집 정보 수집하기
네이버 지도에서 검색한 서울의 미쉐린 맛집을 CSV 파일로 저장하겠습니다. 크로미움 웹 브라우저의 개발자 도구의 인스펙트를 사용하여 네이버 지도 검색 결과룰 분석한 후, 이를 바탕으로 데이터 수집을 자동화하는 함수를 작성할 것입니다.
데이터 추출
01 소스 코드 'step_1_3.py'를 실행하고 인스펙터에서 왼쪽 상단의 Pick locator 아이콘을 클릭합니다.

02 네이버 지도에서 검색 결과의 업체명을 클릭합니다. 인스펙터 하단 [Locator] 탭에 iframe 태그를 특정하고 내부의 요소를 제어하는 함수 frame_locator()가 포함된 코드가 생성됩니다.

| locator("iframe[title=\"Naver Place Search\"]").content_frame.get_by_role("button", name="대삼계장인 톡톡 백숙,삼계탕") |
03 HTML 요소를 분석하기 위해 크로미움 웹 브라우저에서 F12 키를 눌러 개발자 도구를 엽니다. 개발자 도구 왼쪽 상단의 검사 모드 아이콘을 클릭한 후, 네이버 지도에서 검색한 결과의 업체명을 클릭합니다.

개발자 도구 [요소] 탭을 클릭하고 마우스를 사용하여 업체명을 둘러싼 태그 구조를 살펴봅시다. 네이버 지도에서 키워드 검색 결과는 <ul> 태그와 <li> 태그로 구성되어 있습니다. 하단의 <div class="lazyload-wrapper">에 주목합니다.
<ul>
<li class="UEzoS rTjJo" data-laim-exp-id="undefinedundefined">
<div class="CHC5F">
<div class="SgjqM">
<a href="#" target="_self" role="button" class="YTJkH CtW3e"
><span class="TYaxT">3대삼계장인</span
><span class="W6IZ8"
><span class="KCMnt">백숙,삼계탕</span></a
>
...중략...
</li>
<li class="UEzoS rTjJo"></li>
<div class="lazyload-wrapper"></div>
<div class="lazyload-wrapper"></div>
</ul>
<div> 태그의 속성 class의 값인 lazyload-wrapper는 지연 로딩을 의미합니다. 지연 로딩은 웹 문서의 모든 내용을 한 번에 불러오지 않고, 스크롤을 내리는 등으 동작을 할 때마다 필요한 데이터를 추가적으로 불러오는 기법입니다. 네이버 지도 페이지에 지연 로딩이 적용되어 있으므로, 필요한 데이터를 모두 수집하려면 스크롤을 움직여 현재 표시된 것보다 더 많은 데이터를 불러와야 합니다.
개발자 도구의 요소 탭에서 <div class="lazyload-wrapper"></div> 태그를 클릭한 후, 마우스 오른쪽 버튼을 누르고 [Scroll into view(보기로 스크롤)] 메뉴를 선택합니다. 해당 요소로 스크롤이 이동한 후 새로운 데이터가 추가로 로드됩니다. 이 과정을 <ul> 태그의 바로 하위 <div> 태그가 모두 사라질 때까지 반복되면 모든 데이터를 불러올 수 있습니다.
지금까지 분석한 내용을 바탕으로 네이버 지도 검색 결과에서 업체명과 카테고리를 추출하는 함수를 작성해 봅시다. 비주얼 스튜디오 코드에서 새로운 파일을 만들고, 파일명을 'step_1_3.py'로 저장합니다. 다음 코드를 입력한 후 실행 아이콘을 클릭하여 실행합니다. 크로미움 웹 브라우저가 네이버 지도에서 '미쉐린 서울'을 검색한 뒤, 검색 결과에서 업체명과 카테고리를 추출하여 화면에 출력합니다.
ch_12/step_1_4.py
from playwright.sync_api import Page
from step_1_3 import search_map # 이전에 작성한 모듈을 불러옵니다.
def parse_names(page: Page) -> list[tuple[str, str]]: # 04
iframe = page.locator('iframe[title="Naver Place Search"]').content_frame # 검색 결과 창 # 05
while iframe.locator("ul > div").count() > 0: # ul 바로 하위의 div가 발견되면, # 06
iframe.locator("ul > div").last.scroll_into_view_if_needed() # div로 이동 # 07
page.wait_for_timeout(500) # 0.5초간 일시정지 # 08
names = [] # 이 변수에 검색 결과를 저장 # 10
for tag_li in iframe.locator("ul > li").all(): # ul 바로 하위의 모든 li 추출 # 11
tag_a = tag_li.locator("a").first # li 하위의 a 태그 중 첫 번째 # 12
tag_span = tag_a.locator("span") # a 태그 하위의 span 태그 # 13
name = tag_span.first.inner_text() # 첫 번째 span의 텍스트는 업체명 # 14
category = tag_span.last.inner_text() # 마지막 span의 텍스트는 카테고리
names.append((name, category)) # (업체명, 카테고리) 형식으로 결과를 저장
return names
if __name__ == "__main__":
play, browser, page = search_map("미쉐린 서울") # 네이버 지도에서 키워드 검색
names = parse_names(page) # 업체명과 카테고리 추출
print(names)
browser.close() # Browser 객체 삭제
play.stop() # Playwright 객체 삭제
실행 결과
[('3대삼계장인', '백숙,삼계탕'), ('서령 본점', '한식'), ('광화문미진', '한식'), ('우래옥', '냉면'), ('봉밀가 강남구청점', '냉면'), ('진미평양냉면', '냉면'), ('오레노라멘 본점', '일본식라면'), ('평양면옥', '냉면'), ('고사리 익스프레스 신당', '한식'), ('필동면옥', '냉면')]
04 네이버 지도 검색 결과에서 업체명과 카테고리를 추출하는 함수 parse_names()를 정의합니다.
05 인스펙터로 녹화한 코드에서 함수 frame_locator()를 복사하여 코드 편집기에 붙여 넣으세요. 이 코드를 실행하면 <iframe> 태그를 찾고, 변수 iframe에 저장합니다.
06~07 <ul> 태그 바로 하위의 <div> 태그를 찾는 CSS 셀렉터 "ul > div"와 요소와 개수를 세는 함수 count()를 사용하여 <div> 태그를 찾고, 함수 scroll_into_view_if_needed()를 호출하여 해당 태그로 이동합니다. 이때 last 속성을 사용하여 마지막 <div> 태그를 선택합니다.
08 새로운 데이터가 로딩될 때까지 기다리기 위해 함수 wait_for_timeout(500)를 사용하여 실행을 0.5초간 일시정지합니다.
10 CSS 셀렉터 "ul > li"와 함수 all()을 사용해 <ul> 태그 하위의 <li> 태그를 추출합니다.
11~12 <li> 태그 하위의 <a> 태그 중 첫 번째를 선택하고, 해당 <a> 태그의 히위 <span> 태그를 선택합니다.
13~14 속성 first와 함수 inner_text()를 사용해 첫 번째 <span> 태그의 텍스트를 업체명으로, 속성 last과 함수 inner_text()를 사용해 마지막 <span> 태그의 텍스트를 카테고리를 추출합니다.
'프로그래밍 언어 > Python' 카테고리의 다른 글
| 맛집 검색 자동화하기 (0) | 2026.06.22 |
|---|---|
| 맛집 탐색 자동화하기- 파이썬 패키지 준비하기 (0) | 2026.06.19 |
| 단위 면적당 평균 실거래가 시각화하기 (0) | 2026.06.16 |
| GeoJSON으로 데이터 저장 (0) | 2026.06.16 |
| 행정구역 경계 시각화 (0) | 2026.06.13 |