주제 1 / 3
크롤러: 페이지를 대신 읽는 프로그램
크롤러란
크롤러(Crawler)란 사람이 브라우저로 하던 일을 대신하는 프로그램입니다. 사람은 사이트를 열고, 화면을 읽고, 필요한 부분을 복사해 둡니다. 크롤러는 같은 일을 코드로 처리합니다. 매일 아침 쇼핑몰 가격을 확인하거나 여러 블로그의 새 글을 모으는 일처럼, 같은 페이지를 반복해서 읽어야 할 때 주로 씁니다.
크롤러가 하는 일을 노드로 나누면 네 개입니다.
페이지 요청: 사이트 주소로 페이지를 달라고 요청합니다.HTML 받기: 사이트가 보낸 HTML을 받습니다.원하는 부분 고르기: HTML에서 제목이나 가격처럼 필요한 부분만 골라냅니다.저장: 고른 값을 파일이나 데이터베이스에 남깁니다.
앞의 두 노드는 크롤러와 사이트가 주고받는 일입니다. 크롤러가 주소로 요청을 보내면 요청은 인터넷을 거쳐 사이트의 서버에 도착하고, 서버는 그 페이지의 HTML을 담아 응답합니다. 그림 1이 이 요청과 응답이 오가는 순서입니다.
뒤의 두 노드는 받은 HTML 안에서 일어납니다. 그림 2는 쇼핑몰 상품 목록에서 상품마다 상품명, 가격, 평점을 골라 표의 한 행으로 만들고, 그 행들을 products.csv 파일에 쌓는 모습입니다. 화면의 39,000원을 파일에는 39000처럼 숫자만 남기는 정리도 이 단계에서 합니다.
Lesson 0-1에서 다룬 블로그 요약 자동화에도 크롤러가 있었습니다. 본문 가져오기 노드입니다. 그때 블로그를 하나 추가할 때마다 이 노드에 "article 태그 안에서 본문을 찾아라" 같은 규칙을 넣었는데, 이 규칙이 정확히 무엇인지 이번 강의에서 설명합니다.
이번 강의에서는 Python 코드 네 줄로 된 크롤러를 실행해 본 다음, 크롤러가 HTML에서 원하는 부분을 찾는 방법을 DOM과 선택자 순서로 설명하겠습니다.
직접 해 보기: 책 제목 가져오기
크롤링 연습용으로 공개된 책방 사이트(books.toscrape.com)에서 책 제목을 가져와 보겠습니다. 아래 코드는 앞의 네 노드를 순서대로 코드로 옮긴 것입니다.
import requests
from bs4 import BeautifulSoup
html = requests.get("https://books.toscrape.com/").text # 1. 페이지를 요청해 HTML을 받는다
soup = BeautifulSoup(html, "html.parser") # 2. 받은 HTML을 읽는다
for a in soup.select("h3 a"): # 3. 원하는 부분을 고른다
print(a["title"]) # 4. 저장 대신 화면에 출력한다Python에서 크롤러를 만들 때 많이 쓰는 라이브러리입니다. requests는 사이트에 요청을 보내 HTML을 받아 오고, BeautifulSoup은 받은 HTML에서 원하는 부분을 찾을 수 있게 해 줍니다. 터미널에서 pip install requests beautifulsoup4로 설치합니다.
이 코드가 실행될 때 어떤 데이터가 오가는지 단계별로 보겠습니다. 아래에서 다음을 누를 때마다 크롤러가 노드를 하나씩 지나고, 그 단계에서 주고받은 데이터가 아래 칸에 나옵니다.
url = "https://books.toscrape.com/"
실제로 실행하면 첫 페이지에 있는 책 20권의 제목이 한 줄씩 출력됩니다.
A Light in the Attic
Tipping the Velvet
Soumission
...AI에게 맡긴다면 "books.toscrape.com 첫 페이지의 책 제목을 전부 출력하는 Python 크롤러 만들어 줘" 정도로 요청하면 비슷한 코드를 받을 수 있습니다.
그런데 이 코드에서 원하는 부분을 고르는 줄은 soup.select("h3 a") 하나뿐입니다. 페이지에는 책 제목 말고도 메뉴, 가격, 버튼이 함께 들어 있는데, "h3 a"만으로 어떻게 제목만 골라냈을까요? 이걸 이해하려면 먼저 크롤러가 받은 HTML을 어떤 형태로 다루는지 알아야 합니다.
주제 2 / 3
DOM: HTML을 트리로 읽는다
받은 HTML은 하나의 긴 문자열입니다
requests가 받아 온 HTML은 아주 긴 문자열 하나입니다. 문자열 상태로는 "두 번째 책의 가격" 같은 위치를 찾기 어렵습니다. 그래서 브라우저와 BeautifulSoup은 HTML을 받으면 먼저 태그 구조를 읽어 트리 형태로 바꿉니다. 이 과정을 파싱(Parsing)이라고 합니다.
파싱으로 만들어진 트리를 DOM(Document Object Model)이라고 부릅니다. DOM에서는 다른 태그를 감싸는 태그가 부모, 감싸인 태그가 자식이 됩니다. 아래 그림 3에서 article은 body의 자식이면서, h3와 p.price의 부모입니다.
그림 3은 완성된 트리입니다. 트리가 어떤 순서로 만들어지는지는 HTML을 한 줄씩 따라가 보면 알 수 있습니다. 아래에서 다음을 눌러 보세요. 점선 테두리는 지금 부모입니다. 다음에 읽는 태그는 이 요소의 자식으로 붙습니다.
- 1<body>
- 2 <article class="book">
- 3 <h3>책 제목 1</h3>
- 4 <p class="price">12,000원</p>
- 5 </article>
- 6 <article class="book">
- 7 <h3>책 제목 2</h3>
- 8 <p class="price">15,000원</p>
- 9 </article>
- 10</body>
규칙은 두 가지입니다. 여는 태그를 만나면 지금 부모 아래에 자식으로 붙이고, 그 자식이 새 부모가 됩니다. 닫는 태그를 만나면 부모가 한 단계 위로 돌아갑니다. HTML을 들여쓰기해서 쓰는 것도 이 깊이를 눈으로 구분하기 쉽게 하려는 것입니다.
브라우저와 크롤러는 같은 DOM을 만들지만, 그다음에 하는 일이 다릅니다. 브라우저는 DOM을 보고 화면을 그리고, 크롤러는 화면을 그리지 않고 DOM에서 필요한 요소의 값을 꺼냅니다. 크롤러가 읽는 것은 우리가 보는 화면이 아니라, 그 화면을 만든 DOM입니다.
직접 해 보기: 개발자 도구로 DOM 보기
DOM은 브라우저의 개발자 도구에서 바로 확인할 수 있습니다. 크롬 기준으로 따라 해 보세요.
- books.toscrape.com을 열고, 책 제목 하나에 마우스를 올린 뒤 오른쪽 버튼을 눌러
검사를 고릅니다. - 개발자 도구가 열리고
Elements패널에 DOM 트리가 나옵니다. 방금 누른 제목이 들어 있는 줄이 강조되어 있습니다. - 줄 앞의 삼각형을 눌러 접고 펴 보세요. 제목이
article안의h3안의a에 들어 있습니다.
앞에서 쓴 "h3 a"는 이 경로의 뒤쪽 두 단계, 즉 h3 안의 a를 적은 것입니다.
오른쪽 버튼의 페이지 소스 보기는 서버가 처음 보낸 HTML이고, 검사는 그 뒤에 JavaScript가 바꾼 DOM까지 보여 줍니다. requests가 받는 것은 앞쪽입니다. 그래서 검사 화면에는 있는데 크롤러 결과에는 없는 글자가 생길 수 있습니다. 이런 페이지를 다루는 방법은 JavaScript를 배운 뒤에 따로 다룹니다.
주제 3 / 3
선택자: DOM에서 원하는 요소 고르기
선택자의 기본형 네 가지
선택자(Selector)란 DOM 트리에서 원하는 요소를 지정하는 문법입니다. 원래는 CSS에서 어느 요소에 스타일을 적용할지 정할 때 쓰는 문법이라 CSS 선택자라고도 부릅니다. 크롤러는 같은 문법으로 어느 요소의 값을 꺼낼지 정합니다.
그림 3의 HTML을 예로 들면, 기본형 네 가지로 대부분의 요소를 고를 수 있습니다.
h3(태그): 태그 이름이h3인 요소를 모두 고릅니다. 책 제목 두 개가 선택됩니다..price(클래스):class="price"가 붙은 요소를 고릅니다. 점(.)으로 시작합니다. 가격 두 개가 선택됩니다.#shop-name(아이디):id="shop-name"인 요소 하나를 고릅니다. 샵(#)으로 시작합니다. 아이디는 한 페이지에 하나만 있어야 합니다.article h3(안에 있는 요소): 띄어 쓰면 "앞의 요소 안에 있는 뒤의 요소"라는 뜻입니다.article안에 있는h3만 고릅니다.
이제 "h3 a"의 뜻을 알 수 있습니다. h3 안에 있는 a, 즉 책 제목 링크입니다. 메뉴와 버튼은 h3 안에 있지 않아서 선택되지 않습니다. 크롤러가 제목만 골라낼 수 있었던 건, 제목이 DOM의 어디에 있는지 선택자로 정확히 지정했기 때문입니다.
직접 해 보기: 선택자로 요소 고르기
아래 연습판에 선택자를 입력하면, 왼쪽 화면과 오른쪽 DOM 트리에서 선택된 요소가 함께 강조됩니다. 아래 버튼으로 네 가지 기본형을 차례로 눌러 본 뒤, .book .price 같은 조합도 직접 입력해 보세요. 찾는 과정 보기를 누르면 크롤러가 DOM 트리의 요소를 위에서부터 하나씩 선택자와 비교하는 순서가 표시됩니다.
다 해 봤다면 h3를 고른 상태에서 사이트 디자인 바꾸기를 눌러 보세요.
디자인을 바꾸자 화면은 거의 그대로인데, 크롤러는 빈 값을 돌려줍니다. 오른쪽 DOM 트리를 보면 이유를 알 수 있습니다. article은 div로, 제목은 h3에서 h2로, 가격의 클래스는 price에서 cost로 바뀌었습니다. 선택자 h3에 해당하는 요소가 더 이상 없는 것이죠.
화면이 거의 같아 보여도 HTML 구조가 바뀌면, 같은 선택자로는 아무것도 찾지 못합니다. 웹페이지는 사람이 보는 것을 기준으로 만들기 때문에, 사이트 운영자는 화면이 제대로 보이기만 하면 HTML 구조를 얼마든지 바꿀 수 있습니다. Lesson 0-1에서 블로그마다 규칙이 따로 필요했던 것도 같은 이유입니다. 블로그마다 본문이 들어 있는 태그가 달랐습니다.
디자인이 바뀌어도 계속 쓸 수 있는 선택자
사이트가 HTML을 바꾸는 것은 막을 수 없지만, 바뀌어도 계속 쓸 수 있을 가능성이 큰 선택자를 고를 수는 있습니다. 선택자를 고를 때 헷갈리기 쉬운 점은 다음과 같습니다.
- 순서로 고르면 쉽게 어긋납니다.
div:nth-child(3)처럼 "세 번째 요소"를 지정하면, 앞에 광고 요소 하나만 생겨도 다른 요소를 가져옵니다. 빈 값이 아니라 틀린 값이 나오기 때문에 알아차리기도 더 어렵습니다. - 자동으로 만들어진 이름은 바뀌기 쉽습니다.
css-1x9f2k,card-x7f처럼 뜻 없는 글자가 섞인 클래스는 개발 도구가 만든 이름이라, 사이트를 새로 배포할 때마다 바뀔 수 있습니다. - 사람이 뜻을 담아 붙인 이름은 잘 바뀌지 않습니다.
#price,.product-title같은 이름은 디자인을 고친 뒤에도 그대로 남아 있는 경우가 많습니다.
AI에게 크롤러를 맡길 때도 이 기준을 쓸 수 있습니다. "이 선택자를 고른 이유를 DOM 구조로 설명해 줘"라고 요청하면, 순서나 자동으로 만들어진 이름에 의존하는 선택자를 미리 찾아낼 수 있습니다.
다만 이렇게 해도 화면용 HTML을 읽는 한 언젠가는 구조가 바뀝니다. 그래서 많은 서비스가 HTML 대신 데이터만 돌려주는 기능을 따로 제공합니다. 이 기능을 API라고 하고, 다음 강의에서 다룹니다.
기술적으로 가져올 수 있다고 해서 다 가져와도 되는 것은 아닙니다. 사이트 주소 뒤에 /robots.txt를 붙여 열면 그 사이트가 크롤러에게 허락하는 범위가 적혀 있습니다. 이용약관도 함께 확인하고, 요청 사이에 간격을 두어 사이트에 부담을 주지 않아야 합니다. 이 강의의 연습 사이트는 크롤링 연습용으로 공개된 곳입니다.
크롤러는 DOM에서 선택자로 원하는 요소를 찾습니다. 사이트가 HTML 구조를 바꾸면 같은 선택자로는 찾지 못합니다.
마치며
크롤러는 사람이 브라우저로 하던 일을 코드로 처리하는 프로그램입니다. 받은 HTML을 파싱해 DOM 트리로 만들고, 선택자로 그 안에서 필요한 요소를 고릅니다. 코드 네 줄짜리 크롤러든 AI가 만든 긴 크롤러든 이 순서는 같습니다.
선택자는 사이트의 HTML 구조에 맞춰 쓴 것이라, 사이트가 디자인을 바꾸면 같은 선택자로 아무것도 찾지 못할 수 있습니다. 크롤러가 갑자기 빈 값을 돌려준다면 코드를 고치기 전에 개발자 도구로 사이트의 DOM부터 확인해 보세요. 다음 강의에서는 HTML 대신 데이터만 주고받는 방법인 API를 다룹니다.
이 Lesson의 용어
- 크롤러 (Crawler): 웹페이지를 요청해 받고, 그 안에서 필요한 부분을 골라 저장하는 프로그램. 페이지에서 정보를 꺼내는 일만 따로 스크래핑(Scraping)이라고도 부른다
- 파싱 (Parsing): 문자열로 된 HTML을 읽어 태그 구조를 가진 트리로 바꾸는 일
- DOM (Document Object Model): HTML의 태그를 부모와 자식으로 이은 트리. 브라우저는 이걸 보고 화면을 그리고, 크롤러는 여기서 값을 꺼낸다
- 선택자 (Selector): DOM 트리에서 원하는 요소를 지정하는 문법. CSS 선택자라고도 한다
- 개발자 도구 (DevTools): 브라우저에 들어 있는 도구. Elements 패널에서 지금 페이지의 DOM을 볼 수 있다
- robots.txt: 사이트가 크롤러에게 허락하는 범위를 적어 둔 파일
Quiz
크롤러는 DOM에서 선택자로 찾는다 확인 문제
책 제목이 <h2 class="title">책 제목</h2> 안에 들어 있습니다. 이 제목을 고르는 선택자로 알맞은 것은?
답을 고르고 확인을 눌러 주세요.
개발자 도구의 검사 화면에는 보이는 글자가 페이지 소스 보기에는 없습니다. requests로 받아 온 HTML에는 이 글자가 있을까요?
답을 고르고 확인을 눌러 주세요.
어제까지 가격을 잘 가져오던 크롤러가 오늘부터 빈 값만 돌려줍니다. 코드는 바꾸지 않았습니다. 가장 먼저 확인할 것은?
답을 고르고 확인을 눌러 주세요.
사이트 디자인이 바뀐 뒤에도 계속 쓸 수 있을 가능성이 가장 큰 선택자는?
답을 고르고 확인을 눌러 주세요.