
[크롤링] 데이터 수집을 위한 크롤링 8편 : ETag와 If-None-Match로 변경된 페이지만 다시 받는 방법
크롤링에서 같은 URL을 반복 수집할 때 핵심은 두 가지다. 서버가 ETag 같은 검증자(validator)를 제공하는지, 그리고 클라이언트가 이전 응답의 ETag를 저장했다가 다음 요청에 If-None-Match로 다시 보내는지다. 이 조건이 맞으면 서버는 내용이 바뀌지 않았을 때 304 Not Modified를 돌려주고, 본문을 다시 전송하지 않아도 된다.
RFC 9110 기준으로 If-None-Match는 조건부 요청 헤더이고, GET이나 HEAD에서 조건이 실패하면 서버는 304 Not Modified로 응답해야 한다. 즉 크롤러 입장에서는 "다시 요청은 하되, 바뀌지 않았으면 바디는 받지 않는다"는 흐름을 표준 방식으로 구현할 수 있다.
왜 ETag를 먼저 봐야 할까?
ETag는 특정 시점의 리소스 표현(representation)을 식별하는 값이다. 리소스가 바뀌면 새로운 ETag가 생성돼야 하므로, 같은 URL이라도 현재 버전이 이전과 같은지 비교하는 기준으로 쓸 수 있다.
이 방식이 유용한 이유는 URL 자체만으로는 변경 여부를 알 수 없기 때문이다. 뉴스 본문, 상품 상세, 문서 페이지처럼 주소는 같지만 내용은 바뀔 수 있는 페이지에서는 ETag가 있으면 전체 HTML을 다시 내려받지 않고도 변경 여부를 판별할 수 있다.
If-None-Match는 어떻게 동작할까?
첫 요청에서는 평소처럼 리소스를 받고 응답 헤더의 ETag 값을 저장한다. 다음 요청부터는 같은 URL에 대해 If-None-Match 헤더에 그 값을 넣어 보낸다.
GET /resource HTTP/1.1
Host: example.com
If-None-Match: "abc123"
RFC 9110에 따르면 서버는 If-None-Match를 평가할 때 약한 비교(weak comparison)를 사용한다. 현재 리소스의 ETag가 요청 헤더에 들어온 값과 일치하면, GET과 HEAD에서는 요청 본문을 다시 보내지 않고 304 Not Modified로 응답해야 한다.
304 Not Modified를 받으면 무엇을 해야 할까?
304 Not Modified는 "변경이 없으니 기존에 저장한 표현을 계속 써도 된다"는 뜻이다. MDN과 RFC 설명 모두 이 응답에는 본문이 없어야 한다는 점을 분명히 한다.
따라서 크롤러는 304를 오류로 처리하면 안 된다. 보통은 이전에 저장해 둔 본문이나 파싱 결과를 유지하고, 마지막 확인 시각만 갱신하는 식으로 처리한다. 반대로 200 OK가 오면 새 본문과 새 ETag를 함께 저장해야 다음 요청에서도 조건부 요청을 이어갈 수 있다.
ETag가 있으면 항상 트래픽이 줄어들까?
대부분의 경우 줄어들지만, 전제는 있다. 서버가 실제로 ETag를 보내야 하고, 이후 요청에서 If-None-Match를 해석해 304를 돌려줘야 한다. 일부 사이트는 ETag를 아예 제공하지 않거나, 캐시 정책상 다른 검증자를 우선 사용할 수 있다.
또한 304는 바디 전송을 줄여 주는 것이지 요청 자체를 없애 주는 것은 아니다. 연결 수, 요청 빈도, robots 정책 준수는 여전히 별도의 문제다. 조건부 요청은 크롤링 예절을 대체하는 기능이 아니라 재수집 비용을 줄이는 표준 메커니즘으로 보는 편이 맞다.
If-Modified-Since와는 무엇이 다를까?
If-Modified-Since는 날짜 기반 검증자이고, If-None-Match는 ETag 기반 검증자다. RFC 9110은 두 헤더가 함께 있을 때 If-None-Match를 더 정확한 조건으로 보고, 수신자는 If-None-Match가 있으면 If-Modified-Since를 무시해야 한다고 정의한다.
즉 서버가 ETag를 제공한다면 보통은 ETag 기반 흐름이 더 우선이다. 날짜는 서버 시계 보정, 복원 시점, 초 단위 정밀도 문제 때문에 해석이 미묘해질 수 있지만, ETag는 표현 버전을 직접 식별하는 값이라 조건부 재수집에 더 적합한 경우가 많다.
크롤러에서는 어떤 흐름으로 구현하면 될까?
실무 흐름은 단순하다. 첫 수집 때 URL별로 본문과 ETag를 함께 저장하고, 다음 수집 때는 저장된 ETag가 있으면 If-None-Match를 넣어 요청한다. 응답이 304면 기존 데이터를 재사용하고, 200이면 본문과 ETag를 갱신한다.
이때 주의할 점은 ETag를 URL 단위로만 대충 공유하지 않는 것이다. 쿼리스트링, 언어, 인증 상태, 콘텐츠 협상에 따라 같은 경로라도 다른 표현이 나올 수 있다. 서버가 Vary 헤더를 보내는 경우에는 어떤 요청 헤더 조합이 다른 표현을 만들 수 있는지도 함께 봐야 한다.
약한 ETag와 강한 ETag는 어떻게 봐야 할까?
ETag는 W/ 접두사가 붙은 약한 ETag와 그렇지 않은 강한 ETag로 나뉜다. MDN 설명처럼 약한 ETag는 의미상 같은 표현을 판별하는 데는 쓸 수 있지만, 바이트 단위 동일성이 중요한 비교에는 덜 적합하다.
다만 If-None-Match는 원래 약한 비교를 사용하도록 정의돼 있다. 그래서 변경 감지 목적의 재수집에서는 약한 ETag도 충분히 유효할 수 있다. 반대로 부분 응답이나 바이트 단위 동일성이 중요한 경우에는 강한 검증자가 더 적합할 수 있다.
FAQ
모든 사이트가 ETag를 보내나?
아니다. ETag는 널리 쓰이지만 필수 헤더는 아니다. 서버가 ETag를 보내지 않으면 해당 URL에는 If-None-Match 기반 재검증을 적용할 수 없다.
304 응답에도 헤더는 올 수 있나?
그렇다. MDN과 RFC 설명 기준으로 304는 본문은 없어야 하지만, 캐시 갱신에 필요한 일부 헤더는 포함될 수 있다. 따라서 바디가 비었다고 해서 응답 헤더까지 무시하면 안 된다.
If-None-Match와 If-Modified-Since를 같이 보내도 되나?
보낼 수는 있지만, RFC 9110은 If-None-Match가 있을 때 If-Modified-Since를 무시해야 한다고 정의한다. 즉 실질적인 기준은 ETag 쪽이 된다.
정리
크롤링 재수집 비용을 줄이려면 기준은 명확하다. 응답의 ETag를 저장하고, 다음 요청에 If-None-Match를 보내고, 304면 기존 데이터를 재사용한다는 흐름을 지키면 된다. 이 방식은 임의 규칙이 아니라 RFC 9110에 정의된 조건부 요청 절차다.
서버가 ETag를 제공하지 않는다면 Last-Modified와 If-Modified-Since를 대안으로 볼 수 있지만, 둘 다 있을 때는 ETag 기반 검증이 우선이라는 점까지 함께 기억해 두는 편이 안전하다.
참고 자료
'시리즈물 > 데이터 수집을 위한 크롤링' 카테고리의 다른 글
| [크롤링] 데이터 수집을 위한 크롤링 10편 : Sitemap XML과 sitemap index 사용법 (0) | 2026.06.11 |
|---|---|
| [크롤링] 데이터 수집을 위한 크롤링 9편 : Last-Modified와 If-Modified-Since 사용법 (0) | 2026.05.22 |
| [크롤링] 데이터 수집을 위한 크롤링 5편 : Yahoo 파이낸스를 이용한 환율 크롤링 (422) | 2019.03.02 |
| [크롤링] 데이터 수집을 위한 크롤링 4편 : Java의 설치와 간단한 Jsoup 예제 (1) | 2019.03.02 |
| [크롤링] 데이터 수집을 위한 크롤링 3편 : JSON, 더 자세한 설명 (434) | 2019.03.02 |





