이 Playwright MCP 서버를 사용한 웹 브라우저 자동화 및 웹 스크래핑 | Claude Desktop (전체 튜토리얼)

채널 아이콘
Jie Jenn 구독자 68,800명

요약

이 영상은 Playwright 기반의 mCP 서버를 Python으로 개발하여 Cloud Desktop 환경에서 웹 브라우저 자동화와 동적 웹 스크래핑을 구현하는 방법을 상세하게 설명합니다. 영상 초반에는 Playwright 프레임워크의 기본 개념과 웹 스크래핑 데모(예, Zillow, Wikipedia, eBay 페이지)를 통해 자동화 도구의 필요성과 장점을 소개합니다. 이어서 Python 환경에서 라이브러리 설치, 비동기 이벤트 루프 처리, 그리고 다양한 브라우저 제어 함수들을 구현하는 과정을 단계별로 다룹니다. 마지막으로, 개발된 mCP 서버를 Cloud Desktop에 통합하고 실제 테스트하는 과정을 통해 실용적인 웹 자동화 솔루션을 완성하는 과정을 보여줍니다.

주요 키워드

Playwright mCP 서버 웹 스크래핑 브라우저 자동화 Cloud Desktop Python 비동기 자동화 함수 데모 통합

하이라이트

  • 🔑 Playwright 프레임워크를 활용해 웹 브라우저 자동화와 동적 웹 스크래핑을 구현하는 방법을 설명합니다.
  • ⚡️ Microsoft의 도구와 달리 TypeScript 대신 Python을 이용하여 mCP 서버를 개발하는 과정을 상세하게 다룹니다.
  • 🌟 Zillow, Wikipedia, eBay 등의 실제 웹 페이지를 대상으로 데모를 진행하며, 안티 스크래핑 우회 기법을 소개합니다.
  • 📌 다양한 브라우저 제어 함수(탭 생성, 폼 입력, 스크린샷, PDF 저장 등)를 직접 구현 및 설명합니다.
  • 🚀 개발된 서버를 Cloud Desktop에 통합하고, 최종 테스트를 통해 자동화 도구의 활용 가능성을 입증합니다.

용어 설명

Playwright

웹 브라우저 자동화를 위한 오픈 소스 프레임워크로, Chrome, Firefox, Safari 등 다양한 브라우저를 코드로 제어할 수 있습니다.

mCP 서버

Cloud Desktop에 통합되어 웹 자동화 기능을 제공하는 서버로, 다양한 Playwright 함수들을 활용하여 브라우저 동작을 제어합니다.

Cloud Desktop

클라우드 기반 데스크탑 환경으로, 여러 자동화 도구와 기능들을 통합하여 사용자에게 제공하는 플랫폼입니다.

[00:00:00] 소개 및 동기

Microsoft의 Playwright 도구 출시에 영감을 받아, TypeScript 대신 Python으로 mCP 서버를 개발하는 배경과 목표를 설명합니다.

마이크로소프트의 MCP용 Playwright 패키지 출시 배경과 직접 개발하게 된 계기를 설명합니다.
Playwright의 기본 개념과 브라우저 자동화 기능을 소개합니다.
Playwright의 주요 기능인 양식 작성, 스크린샷, 웹 스크래핑 등의 자동화 기능을 설명합니다.
일반 스크래퍼와 달리 JavaScript로 동적 생성되는 콘텐츠도 처리할 수 있는 Playwright의 장점을 설명합니다.
[00:02:05] 웹 스크래핑 데모 및 활용 사례

Zillow, Wikipedia 등에서 웹 스크래핑과 브라우저 자동화를 시연하며, Playwright를 통한 동적 컨텐츠 처리와 안티 스크래핑 우회 기법을 소개합니다.

Cloud Desktop에서 Playwright를 사용한 안티봇 우회 및 웹 스크래핑 데모를 보여줍니다.
Zillow 웹사이트에서 Playwright를 사용해 성공적으로 데이터를 스크래핑하는 실제 예시를 보여줍니다.
Cloud가 웹 페이지 탐색, 필드 입력, 결과 반환 등의 작업을 수행할 수 있음을 설명합니다.
Playwright 서버를 사용하여 위키피디아 웹사이트에서 '일본' 검색, 스크린샷 촬영, 마크다운 파일로 저장하는 예제를 시연합니다.
브라우저 실행, 검색 필드 입력, 검색 실행, 스크린샷 촬영 및 저장 과정을 단계별로 보여줍니다.
Playwright가 생산성 향상과 Cloud Desktop 사용 방식을 혁신할 수 있는 다목적 도구임을 강조합니다.
[00:04:42] Playwright mCP 서버 개발

Python 라이브러리 설치, 비동기 이벤트 루프 처리 및 Playwright 드라이버 설치 과정을 설명하며, 코드 구조와 핵심 함수 구현 방법에 대해 다룹니다.

Playwright MCP 서버 개발을 위한 필요한 라이브러리 설치와 드라이버 설정 과정을 설명합니다.
Python 파일 구조 생성 및 기본 설정에 대해 설명하며, 이벤트 루프 처리와 관련된 중요한 설정을 다룹니다.
PlaywrightManager 클래스 생성과 브라우저 인스턴스 초기화 방법, 그리고 헤드리스 모드 설정에 대해 상세히 설명합니다.
브라우저 실행을 위한 async 메서드를 생성하고 페이지 객체를 설정합니다. 뷰포트 크기는 모니터 해상도에 맞게 동적으로 조정할 수 있습니다.
컨텍스트 객체는 독립된 브라우저 세션을 관리하며, 여러 독립적인 페이지 세션을 하나의 브라우저 인스턴스에서 실행할 수 있습니다.
Playwright MCP 서버 객체를 생성하고 필요한 의존성을 설정합니다. 서버 이름과 도구 목록이 MCP에 표시됩니다.
함수 등록 시 name과 description을 설정할 수 있으며, browser_navigate 함수는 URL 탐색을 담당하는 핵심 기능을 수행합니다.
사용 사례에 따라 필요한 함수만 선택적으로 사용할 수 있으며, 각 함수의 주요 기능과 용도를 이해하는 것이 중요합니다.
Playwright 객체의 시스템 리소스 관리와 Chrome 인스턴스 종료 함수에 대해 설명합니다.
브라우저 종료나 헤드리스 모드 실행 시 발생할 수 있는 리소스 관리 문제와 해결 방법을 설명합니다.
Playwright MCP 서버의 선택적 함수들과 browser_fill, browser_find_by_xpath 함수의 기능을 소개합니다.
브라우저 네비게이션 관련 함수들(뒤로가기, 새로고침, 클릭)의 기능을 설명합니다.
PDF 저장, 스크린샷 캡처, 페이지 스크롤 관련 함수들의 특징과 사용법을 설명합니다.
URL 획득, HTML 요소 추출, 텍스트 추출 등 페이지 콘텐츠 관련 함수들의 기능과 활용법을 설명합니다.
get_element_text 함수는 HTML 마크업 대신 요소의 텍스트 내용만을 반환하는 기능을 합니다.
get_page_content와 get_page_HTML 함수는 각각 페이지의 보이는 텍스트와 HTML 마크업을 반환합니다.
save_element_as_HTML과 save_page_as_HTML 함수는 각각 특정 요소와 전체 페이지의 HTML을 파일로 저장합니다.
clear_field와 browser_press_key 함수는 입력 필드 조작과 키보드 입력 시뮬레이션을 담당합니다.
browser_scroll_one_step 함수는 지연 로딩 콘텐츠를 위한 페이지 스크롤 기능을 제공합니다.
MCP 서버 개발이 완료되어 Cloud Desktop에 설치하는 단계로 진행됩니다.
[00:17:29] Cloud Desktop 통합 및 최종 테스트

개발된 mCP 서버를 Cloud Desktop에 통합한 후, 실제 테스트를 통해 브라우저 자동화 기능과 파일 저장 등 다양한 기능이 정상적으로 작동함을 확인합니다.

eBay 상품 페이지를 테스트하여 HTML 저장 및 스크린샷 기능이 정상 작동함을 확인했습니다.
마이크로소프트가 최근 자체
MCP용 Playwright 도구 패키지를 출시했지만
안타깝게도 이 라이브러리는
타입스크립트로 작성되었고 제가
타입스크립트를 전혀 모르기 때문에
제가 직접 Playwright MCP 도구
패키지를 만들어 Cloud Desktop에서
브라우저를 자동화하기로 했습니다. 이 영상에서는
Cloud에 필요한 Playwright MCP 서버를
Python으로 구축하는 방법을 자세히
설명하여 브라우저를 자동화하는
방법을 알려드리겠습니다
Playwright를 모르시는 분들을 위해 설명하자면
Playwright는 브라우저 자동화를 위한
오픈소스 프레임워크입니다. Chrome, Firefox, Safari와 같은
브라우저를 코드로 제어할 수 있어
일반적으로 수동으로 하는 웹 작업을
자동화할 수 있습니다
본질적으로 코드가 실제 사람처럼
웹사이트를 탐색할 수 있게 해주는 도구입니다
페이지 탐색, 버튼 클릭, 그리고
모든 종류의 웹 콘텐츠를 다룰 수 있습니다
Playwright를 사용하면
브라우저 기반의 거의 모든 작업을
자동화할 수 있습니다. 양식 작성, 버튼 클릭
스크린샷 캡처, 복잡한 웹 애플리케이션
탐색이 가능하며
웹 스크래핑을 통한 데이터 추출도 가능합니다
HTTP GET 요청과 Beautiful Soup를 사용하는
기존의 스크래핑 방식과 달리
정적 HTML만 가져오는 것이 아닌, Playwright는
JavaScript를 포함한
전체 페이지를 렌더링합니다. 이는
페이지 로드 후에 동적으로 로드되는
콘텐츠도 스크래핑할 수 있다는 의미입니다
이는 일반 스크래퍼로는
불가능한 작업입니다. 자, 이제
Playwright로 수행할 수 있는
작업이 매우 많기 때문에
제가 생각하기에 Cloud Desktop에서 유용하게 사용될
20개 이상의 함수를 만들었습니다
더 필요한 기능이 있다면
댓글로 남겨주시면
감사하겠습니다
MCP 서버 개발에 들어가기 전에
Cloud Desktop에서 Playwright를 사용하는
몇 가지 데모를 보여드리겠습니다
제가 Cloud Desktop에서 Playwright 도구를
사용하는 주된 목적은
일반적인 HTTP 요청으로는 접근할 수 없는
웹페이지의 안티봇 탐지를 우회하는
웹 스크래핑입니다
주요 목적 중 하나는 Cloud 모델이
더 정확하고 상세한 응답을 생성하도록
컨텍스트를 추가하는 것입니다
예를 들어, 여기 제가 준비한 프롬프트는
Claude에게 일반 도구 MCP 서버의
웹 페이지 콘텐츠 추출 마크다운 도구를 사용하여
Zillow 페이지에서 부동산 정보를 스크래핑하고
그 정보를 로컬 디렉토리에
마크다운 파일로 저장하도록
지시하는 내용입니다. 만약
요청을 보내면
Zillow에 의해 요청이 차단되는 것을
볼 수 있는데, 이는 데이터를 보호하고
봇의 접근을 막기 위해 설계된
안티스크래핑 조치 때문입니다
하지만 실제 브라우저 환경을 시뮬레이션하는
Playwright 도구로 전환하면
더 이상 차단되지 않고
JavaScript로 생성된 콘텐츠도
스크래핑할 수 있습니다
그리고 Claude가 생성한
마크다운 파일을 보면
Zillow 페이지의 매물 정보가
내부 상세 정보부터
가격 이력까지 모두
포함되어 있습니다
다른 활용 사례로는
Cloud가 웹 페이지로 이동하거나
필드를 입력하고 결과를 반환하는 등의 작업을 수행할 수 있습니다
여기 제가 Playwright 서버의 도구를 사용하도록
Cloud에게 지시하는 프롬프트가 있습니다
위키피디아 웹사이트로 이동해서
일본을 검색하고 페이지의
스크린샷을 찍고
요약본을 로컬 디렉토리의 마크다운 파일로
저장하도록 하겠습니다. 이제 요청을
실행해보겠습니다. 먼저 Claude가 브라우저를
실행하고, 검색 필드를 찾아서
browser_fill 함수를 사용해 검색어를 입력하고
엔터 키를 눌러
검색을 실행합니다
목표 페이지에 도달하면
스크린샷을 찍고 페이지를 요약해서
모든 것을 제 로컬 디렉토리에 저장합니다
이는 매우 다목적으로 활용 가능한
도구로, 생산성을 크게 향상시키고
Cloud Desktop을 사용하는 방식을
바꿀 수 있습니다
데모는 여기까지입니다. 이제
Playwright MCP 서버를 Python으로
개발하는 방법을 살펴보겠습니다
프로젝트 디렉토리에서 터미널을 실행하고
명령어를 실행하여
mcp-nest, asyncio, psutil 그리고
playwright-python 라이브러리를 설치합니다
Python 라이브러리가 설치되면
Playwright 드라이버를 설치해야 합니다
드라이버를 설치하려면 'playwright install' 명령어를 실행하세요
이 명령어는 Firefox, Chrome,
그리고 WebKit용 드라이버를 설치합니다
그리고
Playwright 드라이버는
웹 브라우저를 실행하고 제어하는데 사용되는
자동화 목적의 컴포넌트입니다
이제 코드 에디터에서 mcp_playwright_tools.py라는
Python 파일을 프로젝트
디렉토리에
생성합니다. Python에서 Playwright를
사용하는 방법에 대한 튜토리얼은 이미 많이
있으므로, 소스 코드에 대해
간단히 설명하고
각 함수의 사용법과 Cloud Desktop용
Playwright MCP 서버 설정 방법을
설명하겠습니다. 구체적인 질문이 있다면
아래 댓글로 문의해
주세요. 먼저 Python
의존성을
임포트합니다. Python에서 다른 이벤트 루프 안에서
비동기 이벤트 루프를 실행하려고 하면
런타임
에러가 발생합니다
여기서 nest_asyncio.apply() 메소드를 사용하여
이러한 제한을 해결하고, MCP 서버를 실행할 때
중첩된 이벤트 루프가 원활하게 실행되도록
합니다
다음으로 로거를 설정합니다
Python 클래스 작성에
익숙하지 않다면 약간 어려울 수 있습니다
사용법만 알고 싶다면 그냥
복사해서 붙여넣기 하면 됩니다
PlaywrightManager 클래스를 두 개의 메소드로 생성합니다
이 클래스는 핵심 기능만 있는
Playwright 브라우저 인스턴스를
초기화하는 데 사용됩니다
필수적인
함수만으로요. 매개변수를 보면
PlaywrightManager 객체를 생성할 때
사용할 브라우저 종류, 브라우저를 표시할지
여부, 그리고 브라우저 창 크기를
지정할 수 있습니다
헤드리스 모드를 false로 설정하면
브라우저가 일반 모드로 실행되어
브라우저 창과 실시간으로
실행되는 동작을 직접 볼 수 있으며
Cloud가 작업할 때
실시간으로 확인할 수 있습니다
실제로 브라우저를 실행하기 위해
async 메서드를 만들어 브라우저를 생성하고
메서드 내에서 브라우저 페이지를 생성합니다
여기서는 Playwright 객체를 생성하고
브라우저를 실행한 다음
출력으로 페이지 객체를 추가합니다
Playwright에서 페이지는
브라우저 탭과 동일합니다. 여기서 뷰포트는
브라우저 창의
크기를 제어하며, 모니터
해상도에 따라 조정이 필요할 수 있습니다
또는 다른 방법으로
모니터의 해상도를 가져오는
프로시저를 추가하여
비율을 계산해 적절한 치수를
반환하도록 할 수 있습니다
컨텍스트 객체는 고유한 설정,
쿠키, 캐시를 가진 독립된
브라우저 세션을 나타내며
하나의 브라우저 인스턴스 내에서
여러 독립적인 페이지 세션을 허용합니다
이는 다양한 시나리오를
시뮬레이션하거나 여러 독립적인
브라우저 상태를 관리할 때 유용하며
여러 브라우저를 실행하는 오버헤드 없이 가능합니다
async close 메서드에서는
모든 리소스를 종료하여
백그라운드에서 메모리를
소비하지 않도록 합니다
이것이 Playwright를 시작하기 위한
기본적인 보일러플레이트입니다
이제 Playwright MCP 서버 객체를 만들어보겠습니다
FMCP 클래스를 사용하여 name 속성은
서버 이름이며, 이는 MCP에서
사용 가능한 도구 목록에
표시될 이름입니다. dependencies는
서버 운영에 필요한
서드파티 파이썬 라이브러리입니다
여기서 Playwright 매니저 객체의
인스턴스를 생성하고
현재 작업 디렉토리를
저장할 변수를 만듭니다
MCP 서버에 함수를 등록하기 위해
MCP 객체에서 tool 데코레이터를 사용하고
name과 description 매개변수로
함수를 설명합니다
만약 name과 description 필드를
비워두면
Claude Desktop에서는 표시될 이름으로
함수 이름을 대신 사용합니다
여기서 browser_navigate 함수는
도구 세트에서 가장 중요한
함수 중 하나입니다
이 함수는 URL을 받아 브라우저를 실행하고
해당 URL로 이동합니다
만약 브라우저 인스턴스가 없는 경우
예를 들어 새로운 채팅 세션을 시작했지만
실수로 브라우저를 닫은 경우
함수가 브라우저
세션을 다시 생성합니다
앞서 언급했듯이 저는 많은
Playwright 도구 함수들을
MCP 서버에 만들었지만
사용 사례에 따라
모든 함수가 필요하지 않을 수 있습니다
필요하지 않은 함수는
주석 처리하는 것을 추천합니다
Playwright는 파이썬의 고급 프레임워크이며
제가 이미 코드를 작성했기 때문에
각 함수가 무엇을 하는지만
알면 됩니다
나머지 함수들을 설명할 때
각 함수의 기능과
코드에서 알아야 할
중요한 부분에 초점을 맞추겠습니다
browser_close 함수는
모든 브라우저 프로세스를 종료하고 리소스를 해제합니다
Playwright 객체의 시스템 리소스
모든 Chrome 인스턴스 종료
함수는 Playwright가 생성한
모든 Chrome 인스턴스를
프로세스에서 종료합니다
이 함수를 만든 이유는
브라우저를 종료할 때나
헤드리스 모드로 브라우저를 실행하고
브라우저 인스턴스를 종료하는 것을 잊었을 때
프로세스가 백그라운드에서
계속 실행되어 리소스를 차지하기 때문입니다
모든 Chrome 인스턴스 종료 함수는
모든 리소스가 확실히 종료되도록 합니다
이것이 Playwright MCP 서버에서
필요한 세 가지 필수 함수입니다
이제부터 소개할 나머지 함수들은
선택사항입니다. 필요하지 않은
함수는 주석 처리할 수 있습니다
다음으로 넘어가겠습니다
browser_fill 함수는 선택자로 식별된
폼 필드에 텍스트를 입력합니다
선택자는 특정 HTML 요소를
찾는데 사용되는 패턴입니다
browser_find_by_xpath는
웹 스크래핑 작업을 많이 할 때
유용한 함수 중 하나입니다
이 함수는 특정 XPath 쿼리와
일치하는 요소의 수를 계산하여
자동화를 진행하기 전에 특정 요소가
웹 페이지에 존재하는지 확인하거나
중복된 요소의 수를
확인합니다
browser_go_back 함수는
이전 페이지로 돌아갑니다
browser_reload 함수는
페이지를
새로고침 합니다. browser_click 함수는
선택자로 식별된 요소를 클릭합니다
보통 이 함수를 사용하여
드롭다운이나 버튼과 같은
클릭 가능한 요소를 찾아 상호작용합니다
browser_save_as_pdf 함수는
현재 웹 페이지를 PDF 파일로 저장합니다
현재 이 함수는 Chrome에
특화되어 있습니다. 다른 드라이버는
PDF 저장에 다른 설정이 필요하기 때문입니다
browser_screenshot 함수는
현재 페이지나
특정 요소의 이미지를 캡처합니다
browser_scroll_to_top
함수는 페이지의
맨 위로 스크롤합니다. 제가 아마도
scroll_to_bottom 함수를
포함하는 것을 잊은 것 같은데
영상 이후에 소스 코드를 업데이트하고
링크를 설명란에 넣겠습니다
browser_scroll_to_element 함수는
browser_scroll_to_top 함수와 비슷하지만
이 함수는 특정 요소가 있는
위치로 페이지를 스크롤합니다
get_current_url 함수는
현재 페이지의
URL을 반환합니다. get_element_html 함수는
XPath 쿼리로 지정된
요소에서 HTML 마크업을
추출하여 반환합니다. 보통 이 함수를
웹 페이지의 특정 요소를
저장하거나 추출할 때 사용합니다. 예를 들어
Google 지도에는
여러 구성 요소가 있는데
이 함수를 사용하여 특정
컴포넌트의 HTML만 반환할 수 있습니다
Cloud Desktop에서 이 함수를
사용하는 주된 이유는 입력 컨텍스트
크기를 줄이기 위해서입니다. 일부 페이지는
HTML이 매우 방대하기 때문입니다
get_element_text는
get_element_html 함수와 유사하게 작동합니다
단, 이 함수는 텍스트를 반환합니다
HTML이 아닌 요소와 연관된 텍스트 내용을
반환합니다
get_page_content 함수의 경우
웹 페이지에서 보이는 모든 텍스트를
반환합니다. get_page_HTML 함수는
비슷하게 작동하지만 HTML 마크업을
반환합니다
get_page_title 함수는
현재 웹 페이지의 제목을 반환합니다
save_element_as_HTML 함수는
특정 요소의 HTML 내용을 추출하여
XPath를 기반으로 파일로
저장합니다
save_page_as_HTML 함수는
현재 웹 페이지를 HTML 파일로 저장하고
save_page_screenshot 함수는
현재 웹 페이지의 이미지를
캡처하여 저장합니다
clear_field 함수는 XPath로 식별된
입력 필드를 지웁니다
browser_press_key 함수는
매우 유용한 또 다른 함수입니다
이 함수는 특정 키보드 키를
누르는 것을 시뮬레이션합니다
이 함수를 사용하여 타이핑이나
엔터 키 또는 탭 키와 같은
키 입력 동작을 수행할 수 있습니다
그리고 마지막으로
browser_scroll_one_step 함수는
지정된 거리만큼 페이지를
스크롤합니다
보통 이 함수는
YouTube 댓글이나 Ajax를 사용하는
웹사이트의 지연 로딩 콘텐츠를
로드하는 데 사용합니다
아직 사용 사례를 찾지 못해서
clear_browser_data와 get_cookies
함수는 주석 처리했지만
나중에 필요할 수 있으니
남겨두기로 했습니다
마지막 단계로 MCP_run 메소드를 사용하여
MCP 서버를 실행합니다
이제 공식적으로
Playwright MCP 서버 개발을
완료했습니다. 다음 단계는 MCP 서버를
Cloud Desktop에 추가하는 것입니다
먼저 제 Cloud Desktop에 있는 기존
Playwright 서버를 제거하겠습니다
Playwright MCP 서버를 Cloud Desktop에 추가하려면
터미널에서 mcp install 명령어와
Python 파일 이름을 입력하면
됩니다
설치가 성공적으로 완료되면
'Successfully install Playwright Tools in Cloud app'
이라는 로그가 표시됩니다. 이제
Cloud Desktop을
재시작하세요. 사용 가능한
MCP 도구를 확인하면 Playwright MCP 서버의
함수들이 목록에 나타날 것입니다
여기 제 Playwright 환경 프로젝트의 프롬프트와
나머지 프롬프트가
있습니다
Patreon 멤버이신 경우
설명란의 링크에서 모든 리소스를
다운로드할 수 있습니다
이제 Cloud Desktop에서 Playwright
함수들이 제대로 작동하는지
테스트해보겠습니다
Cloud가 eBay 상품 페이지로 이동하여
페이지를 HTML 파일로 로컬 폴더에
저장하도록 해보겠습니다
브라우저가 성공적으로 실행되어
eBay 상품 페이지가 표시되는 것을
볼 수 있습니다
지정한 대로 몇 가지 사항을 확인하여
대상 페이지가 맞는지
확인합니다. 로컬 폴더를 보면
스크린샷도 저장되었고
요청한 대로 페이지가 HTML 파일로
로컬 폴더에 저장되었습니다
Playwright로 할 수 있는 자동화
사례가 매우 많습니다. 튜토리얼
아이디어나 기능에 대한 제안이
있으시다면 아래 댓글로
남겨주세요. 이것으로 Cloud Desktop용
Playwright MCP 서버 개발 walkthrough를
마치겠습니다. 이 영상이
도움이 되었길 바랍니다. 다루었으면 하는
튜토리얼 아이디어가 있다면
댓글로 남겨주세요. 좋아요와
구독도 잊지 마시고
즐거운 코딩 되세요. 다음에 뵙겠습니다
감사합니다