"이 응답 파싱해서 DB에 넣어 주세요", "그 사이트 크롤링 좀 해 봐요" 같은 말을 회의에서 자주 듣습니다. 말하는 사람마다 뜻이 조금씩 달라서, 일을 받는 입장에서는 정확히 어디까지 해 달라는 건지 되묻게 됩니다. 세 단어는 겹치는 부분이 있지만 가리키는 작업이 다릅니다.

파싱은 "의미 있는 덩어리로 쪼개는 일"

영어 parse에 -ing가 붙은 말입니다. 가장 쉬운 예가 문자열을 숫자로 바꾸는 함수입니다. 자바스크립트의 parseInt("3"), VB.NET의 Integer.Parse("3")은 글자 "3"을 읽어서 정수 3이라는 값으로 바꿔 줍니다. 겉으로는 같아 보여도 하나는 텍스트이고 하나는 계산에 쓸 수 있는 숫자입니다.

광고

컴퓨터 과학에서의 정의는 조금 더 엄격합니다. 문자열을 의미 있는 토큰(token)으로 나누고, 그 토큰들의 관계를 파스 트리(parse tree)라는 구조로 만드는 과정을 파싱이라고 합니다. 컴파일러나 인터프리터 안에서 소스 코드를 읽고 문법이 맞는지 검사하는 부품이 바로 파서(parser)입니다. 우리가 코드를 잘못 쓰면 "구문 오류"가 나는 것도 이 단계에서 걸린 겁니다.

실무에서 "파싱한다"고 할 때는 보통 그보다 넓은 뜻입니다. JSON 문자열을 객체로 바꾸기, CSV 한 줄을 쉼표로 나눠 열 값 꺼내기, HTML 문서에서 상품명과 가격이 들어 있는 태그만 찾아 값 뽑기 같은 작업이 다 파싱입니다. 공통점은 "이미 손에 들어온 데이터"를 내가 쓸 수 있는 형태로 가공한다는 것입니다.

크롤링은 "링크를 따라 돌아다니며 모으는 일"

크롤러(crawler)는 웹 페이지를 방문하고, 그 페이지에 걸린 링크를 따라 다른 페이지로 계속 이동하면서 문서를 수집하는 프로그램입니다. 링크를 타고 웹을 기어 다니는 모습이 거미 같다고 해서 스파이더(spider)라고도 부릅니다. 검색 엔진이 대표적인 예로, 수많은 페이지를 모아서 나중에 빨리 찾을 수 있게 인덱싱해 둡니다.

핵심은 "어디를 방문할지"를 스스로 넓혀 간다는 점입니다. 한 페이지만 받아 오는 프로그램은 엄밀히 말하면 크롤러라고 보기 어렵습니다.

스크래핑은 "특정 사이트에서 원하는 정보를 긁어 오는 일"

스크래핑(scraping)은 HTTP로 웹 사이트 내용을 받아서 필요한 정보만 원하는 형태로 뽑아내는 작업 전반을 말합니다. 영어권 자료에서는 우리가 흔히 "크롤링"이라고 부르는 작업 대부분을 Web Scraping이라고 씁니다. 그래서 해외 자료를 찾을 때는 "web crawling"보다 "web scraping with VB.NET", "web scraping with PHP"처럼 검색하는 쪽이 원하는 결과가 더 잘 나옵니다.

예를 들어 음원 사이트 차트에서 순위, 곡명, 가수, 앨범, 발매일을 매일 가져와 DB에 쌓아야 한다고 해 봅시다. 사람이 매일 들어가서 엑셀에 옮겨 적을 수도 있지만, 다른 프로그램에서 그 데이터를 쓰려면 결국 자동화가 필요합니다. 웹 페이지는 HTML로 되어 있고, 브라우저의 "페이지 소스 보기"나 개발자 도구로 보면 같은 종류의 정보가 같은 모양의 태그 안에 반복해서 들어 있는 걸 볼 수 있습니다. 이 규칙을 찾아서 필요한 값만 꺼내는 게 스크래핑입니다.

세 가지가 실제로 이어지는 순서

실제 수집 프로그램을 짜 보면 세 단계가 차례로 붙어 있습니다.

  1. 수집할 페이지 주소 목록을 만들거나 링크를 따라가며 넓혀 갑니다(크롤링).
  2. 각 페이지의 HTML을 HTTP로 받아 옵니다(스크래핑의 요청 단계).
  3. 받은 HTML에서 원하는 값만 뽑아 숫자, 날짜 같은 형태로 바꿉니다(파싱).

마지막 단계를 PHP로 간단히 보면 이런 모습입니다. HTML 문자열을 DOM으로 해석한 뒤 XPath로 특정 클래스를 가진 요소의 글자만 꺼냅니다.

<?php
$html = '<ul><li class="title">첫 번째 곡</li><li class="title">두 번째 곡</li></ul>';

$dom = new DOMDocument();
libxml_use_internal_errors(true);          // 엉성한 HTML 경고 숨김
$dom->loadHTML('<?xml encoding="UTF-8">' . $html);

$xpath = new DOMXPath($dom);
foreach ($xpath->query('//li[@class="title"]') as $node) {
    echo trim($node->textContent), PHP_EOL;
}

loadHTML 앞에 <?xml encoding="UTF-8">을 붙이는 건 한글이 깨지지 않게 하려는 요령입니다. 실제 사이트 HTML은 태그가 덜 닫혀 있는 경우가 많아 경고가 쏟아지는데, libxml_use_internal_errors(true)로 그 경고를 숨깁니다.

파싱은 페이지 구조에 기대고 있어서, 사이트가 디자인을 바꾸면 하루아침에 아무 값도 안 나올 수 있습니다. 수집 프로그램을 운영한다면 값이 비었을 때 바로 알 수 있게 로그나 알림을 걸어 두는 게 좋습니다. 그리고 사이트가 공식 API를 제공한다면 HTML을 긁는 것보다 API를 쓰는 쪽이 훨씬 안정적이고, robots.txt와 이용약관에서 수집을 허용하는지도 먼저 확인해야 합니다.

참고: aftersiesta 티스토리 | potter777777 네이버 블로그 | Wikipedia - Web scraping