본문 바로가기
카테고리 없음

구글 시트로 웹 스크래핑 자동화하기: IMPORTXML과 Apps Script로 실시간 데이터 수집 시스템 구축

by 시트자동화 2025. 10. 8.

웹에서 필요한 데이터를 수동으로 복사하여 붙여넣는 작업은 비효율적이고 오류가 발생하기 쉽습니다. 구글 시트를 활용하면 코딩 지식 없이도 웹사이트에서 자동으로 데이터를 가져올 수 있습니다. IMPORTXML 함수를 사용한 XPath 기반 데이터 추출부터 IMPORTHTML로 표와 목록 가져오기, 그리고 Apps Script를 활용한 고급 스크래핑 기법까지 단계별로 안내합니다. 환율 정보, 주식 시세, 경쟁사 가격 정보 등 실시간으로 변하는 데이터를 자동으로 수집하여 업무 효율성을 극대화할 수 있습니다. 반복적인 데이터 수집 작업에서 벗어나 전략적인 분석에 집중하시기 바랍니다.


IMPORTXML 함수를 사용한 XPath 기반 데이터 추출

IMPORTXML은 구글 시트에서 가장 강력한 웹 스크래핑 함수입니다. XPath를 사용하여 웹페이지의 특정 요소를 정확하게 추출할 수 있습니다. 기본 문법은 IMPORTXML(URL, XPath쿼리)입니다. 예를 들어 특정 웹사이트의 제목을 가져오려면 IMPORTXML("https://example.com", "//h1")처럼 작성합니다. XPath는 HTML 문서의 구조를 탐색하는 언어로, 슬래시(/)를 사용하여 계층을 표현합니다. 이중 슬래시(//)는 문서 전체에서 해당 요소를 찾으라는 의미이고, 단일 슬래시(/)는 직계 자식만 찾습니다. 클래스나 아이디로 요소를 찾을 때는 속성 선택자를 사용합니다. //div[@class="price"]는 클래스가 price인 div 요소를 찾습니다. 여러 조건을 결합할 때는 and 연산자를 사용하는데, //span[@class="value" and @id="current"]처럼 작성합니다. 텍스트 내용만 추출하려면 /text()를 추가합니다. //h2[@class="title"]/text()는 제목 요소의 텍스트만 반환합니다. 속성값을 가져올 때는 @속성명을 사용합니다. //img/@src는 이미지의 소스 URL을 추출합니다. 링크를 수집할 때는 //a/@href로 모든 링크 주소를 가져올 수 있습니다. 특정 순서의 요소를 선택하려면 대괄호에 인덱스를 지정합니다. (//div[@class="item"])[1]은 첫 번째 아이템만 선택합니다. contains 함수를 사용하면 부분 일치 검색이 가능합니다. //div[contains(@class, "product")]는 클래스에 product가 포함된 모든 div를 찾습니다. 실무에서 자주 사용하는 패턴은 테이블 데이터 추출입니다. //table//tr//td는 테이블의 모든 셀 데이터를 가져옵니다. 특정 열만 필요하다면 //table//tr/td[2]처럼 인덱스로 제한합니다. 크롬 개발자 도구를 사용하면 XPath를 쉽게 찾을 수 있습니다. 웹페이지에서 F12를 눌러 개발자 도구를 열고, 원하는 요소를 마우스 오른쪽 버튼으로 클릭한 후 Copy XPath를 선택하면 정확한 경로를 복사할 수 있습니다. 단, 복사한 XPath는 너무 구체적일 수 있으므로 일반화하는 것이 좋습니다. IMPORTXML은 동적으로 로드되는 콘텐츠는 가져올 수 없다는 제한이 있습니다. 자바스크립트로 렌더링되는 페이지는 Apps Script를 사용해야 합니다. 또한 웹사이트의 robots.txt 정책을 준수해야 하며, 과도한 요청은 IP 차단을 유발할 수 있습니다.


IMPORTHTML로 표와 목록 간편하게 가져오기

IMPORTHTML 함수는 웹페이지의 표나 목록을 빠르게 가져올 수 있는 편리한 도구입니다. XPath를 몰라도 사용할 수 있어 초보자에게 적합합니다. 기본 문법은 IMPORTHTML(URL, 쿼리유형, 인덱스)입니다. 쿼리유형은 "table" 또는 "list"를 지정할 수 있습니다. 예를 들어 웹페이지의 첫 번째 표를 가져오려면 IMPORTHTML("https://example.com", "table", 1)처럼 작성합니다. 인덱스는 1부터 시작하며, 페이지에 여러 표가 있을 때 몇 번째 표를 가져올지 지정합니다. 두 번째 표를 원한다면 인덱스를 2로 설정합니다. 리스트를 가져올 때는 "list"를 사용하는데, HTML의 ul이나 ol 태그로 만들어진 목록을 추출합니다. IMPORTHTML("https://news.example.com", "list", 1)은 첫 번째 목록 항목들을 가져옵니다. 실무에서 자주 활용되는 사례는 환율 정보 수집입니다. 환율 정보를 제공하는 웹사이트의 환율표를 IMPORTHTML로 가져와 자동으로 업데이트되는 환율 계산기를 만들 수 있습니다. 주식 정보도 마찬가지로, 증권사 웹사이트의 시세표를 실시간으로 가져와 포트폴리오 관리에 활용합니다. 경쟁사 가격 모니터링에도 유용한데, 여러 쇼핑몰의 가격표를 주기적으로 수집하여 비교 분석할 수 있습니다. 날씨 정보, 스포츠 순위, 뉴스 헤드라인 등 표 형태로 제공되는 모든 데이터가 대상이 됩니다. IMPORTHTML의 장점은 자동 새로고침입니다. 시트를 열거나 일정 시간이 지나면 자동으로 최신 데이터를 가져옵니다. 단, 구글 시트의 캐싱 정책으로 인해 즉시 업데이트되지 않을 수 있습니다. 강제로 새로고침하려면 URL 끝에 쿼리 스트링을 추가하는 방법이 있습니다. IMPORTHTML("https://example.com?refresh="&NOW())처럼 NOW 함수를 포함하면 시간이 변할 때마다 새로운 URL로 인식되어 캐시를 우회합니다. 여러 페이지에서 데이터를 수집할 때는 IMPORTHTML을 여러 셀에 작성하고 QUERY 함수로 통합합니다. 예를 들어 A1, A2, A3 셀에 각각 다른 URL의 IMPORTHTML을 작성하고, 다른 시트에서 QUERY({A1:C10;A15:C25}, "SELECT *")로 합칠 수 있습니다. 오류 처리도 중요한데, IFERROR로 감싸면 웹사이트가 응답하지 않을 때 대체 메시지를 표시할 수 있습니다. IFERROR(IMPORTHTML(...), "데이터 로드 실패")처럼 작성합니다. 일부 웹사이트는 스크래핑을 차단하므로 사전에 테스트가 필요합니다.


Apps Script를 활용한 고급 스크래핑 기법

IMPORT 함수로 해결할 수 없는 복잡한 스크래핑 작업은 Apps Script로 구현합니다. UrlFetchApp 서비스를 사용하면 HTTP 요청을 보내고 응답을 처리할 수 있습니다. 기본 코드 구조는 UrlFetchApp.fetch(url)로 웹페이지를 가져온 후 getContentText()로 HTML을 문자열로 변환합니다. 정규표현식을 사용하여 원하는 패턴을 추출할 수 있는데, match 메서드나 exec 메서드를 활용합니다. 예를 들어 가격 정보를 추출하려면 /\$[\d,]+\.\d{2}/g 같은 정규식으로 달러 표시가 있는 숫자를 찾습니다. 더 정교한 파싱이 필요하다면 XmlService를 사용합니다. XmlService.parse()로 HTML을 파싱한 후 getRootElement()로 루트 요소에 접근하고 getChildren()으로 하위 요소를 탐색합니다. 단, HTML이 완벽한 XML 형식이 아니면 오류가 발생할 수 있으므로 사전 정제가 필요합니다. 실무에서는 여러 페이지를 순회하며 데이터를 수집하는 경우가 많습니다. for 루프를 사용하여 페이지 번호를 바꿔가며 요청을 보냅니다. 예를 들어 1페이지부터 10페이지까지 수집하려면 for 루프 안에서 URL에 페이지 번호를 포함시킵니다. 각 요청 사이에는 Utilities.sleep(1000)으로 1초 간격을 두어 서버에 부담을 주지 않도록 합니다. 로그인이 필요한 사이트는 쿠키나 헤더를 설정해야 합니다. UrlFetchApp.fetch()의 두 번째 인수로 옵션 객체를 전달하는데, headers 속성에 인증 토큰이나 쿠키를 포함시킵니다. API가 제공되는 경우 JSON 형식으로 데이터를 받을 수 있어 더 편리합니다. JSON.parse()로 파싱한 후 객체의 속성에 접근하여 필요한 정보를 추출합니다. 트리거를 설정하면 자동 실행이 가능한데, 시간 기반 트리거로 매시간 또는 매일 특정 시간에 스크래핑을 실행하도록 예약합니다. 구글 시트로 웹 스크래핑 자동화하기의 핵심은 수집한 데이터를 시트에 효율적으로 저장하는 것입니다. getRange().setValues()를 사용하여 2차원 배열을 한 번에 쓰는 방식이 가장 빠릅니다. 기존 데이터를 유지하면서 새 데이터를 추가하려면 getLastRow()로 마지막 행을 찾은 후 그 다음 행부터 입력합니다. 중복 확인도 중요한데, 기존 데이터와 비교하여 새로운 항목만 추가하는 로직을 구현합니다. 오류 처리를 위해 try-catch 블록을 사용하고, 오류 발생 시 이메일 알림을 보내도록 MailApp.sendEmail()을 호출합니다. 대용량 데이터를 처리할 때는 배치 크기를 제한하고, 진행 상황을 별도 시트에 기록하여 중단된 시점부터 재개할 수 있도록 합니다.