본문 중간의 쿠팡 추천 상품 구매시 쿠팡 파트너스에서 일정액의 수수료를 제공받습니다.

[크롤링] 데이터 수집을 위한 크롤링 9편 : Last-Modified와 If-Modified-Since 사용법
Last-Modified와 If-Modified-Since는 크롤러가 이미 받아 둔 리소스를 다시 전부 내려받지 않도록 도와주는 가장 기본적인 조건부 요청 조합이다. RFC 9110과 MDN 문서를 기준으로 보면, 서버는 리소스의 최종 수정 시각을 Last-Modified로 알려 줄 수 있고, 클라이언트는 다음 요청에서 If-Modified-Since를 보내 변경 여부를 확인할 수 있다.
이 방식은 ETag보다 단순하지만 정밀도는 낮다. 그래도 정적 파일, 문서, 피드, 공지 페이지처럼 수정 시각을 비교해도 충분한 리소스에서는 구현 부담이 낮고, 수집 트래픽을 줄이는 데 효과적이다. 이 글은 공식 문서 기준으로 두 헤더의 역할, 304 응답 흐름, ETag와의 차이, 크롤링에서의 안전한 사용 기준을 정리한다.
Last-Modified는 무엇을 의미할까?
MDN은 Last-Modified를 원본 서버가 해당 리소스가 마지막으로 수정되었다고 판단한 시각을 담는 응답 헤더로 설명한다. 형식은 HTTP-date이며, 날짜는 항상 GMT로 표현된다.
RFC 9110은 원본 서버가 리소스의 마지막 수정 시각을 합리적이고 일관되게 판단할 수 있다면 Last-Modified를 보내는 편이 좋다고 설명한다. 이 값은 조건부 요청뿐 아니라 캐시 신선도 판단과 불필요한 전송 감소에도 쓰인다.
If-Modified-Since는 어떻게 동작할까?
If-Modified-Since는 GET 또는 HEAD 요청을 조건부 요청으로 바꾸는 헤더다. RFC 9110 기준으로 서버는 요청에 담긴 시각보다 리소스가 더 최근에 수정된 경우에만 본문을 포함한 200 OK를 보내고, 그렇지 않으면 304 Not Modified를 보내 전송을 생략할 수 있다.
실무 흐름은 단순하다. 첫 요청에서 응답의 Last-Modified 값을 저장해 두고, 다음 요청 때 그 값을 그대로 If-Modified-Since에 넣어 보낸다. 변경이 없으면 304, 변경이 있으면 새 본문과 새 Last-Modified가 돌아온다.
크롤러에서는 어떤 순서로 쓰면 될까?
- 첫 수집에서 응답 본문과
Last-Modified값을 함께 저장한다. - 재수집 시
If-Modified-Since헤더에 저장한 값을 그대로 넣는다. 304 Not Modified를 받으면 기존 저장본을 그대로 사용한다.200 OK를 받으면 새 본문과 새 검증값으로 갱신한다.
MDN의 조건부 요청 가이드는 이 패턴이 캐시 갱신의 대표적인 사용 사례라고 설명한다. 크롤러 입장에서는 같은 문서를 반복 수집하는 비용을 줄이는 데 바로 적용할 수 있다.
ETag와 무엇이 다를까?
MDN은 Last-Modified가 파일 내용 비교 기준으로는 ETag보다 덜 정확하다고 설명한다. 수정 시각은 보통 초 단위이며, 서버 구현에 따라 실제 내용이 바뀌지 않아도 시간이 달라질 수 있고, 반대로 같은 초 안에서 여러 번 바뀌면 구분이 어려울 수 있다.
RFC 9110도 If-None-Match가 있을 때는 If-Modified-Since를 무시해야 한다고 규정한다. 이는 엔터티 태그 기반 검증이 더 정확한 대체 수단으로 간주되기 때문이다. 따라서 서버가 안정적인 ETag를 제공한다면 그 값을 우선 쓰고, 없을 때 Last-Modified를 보조 검증값으로 쓰는 구성이 일반적이다.
언제 특히 유용할까?
1. 정적 문서나 공지 페이지를 주기적으로 확인할 때
보도자료, 문서 페이지, 정책 안내, RSS/Atom 피드처럼 수정 시각이 의미 있는 리소스는 이 방식과 잘 맞는다. 본문 전체를 다시 받지 않아도 되므로 네트워크 비용과 처리 시간을 함께 줄일 수 있다.
2. 서버가 ETag를 주지 않을 때
MDN은 Last-Modified를 ETag가 없을 때 쓸 수 있는 대체 검증 수단으로 설명한다. 오래된 서버, 단순한 정적 호스팅, 일부 CDN 환경에서는 이 조합만으로도 충분히 이득이 생길 수 있다.
3. 최근 변경된 문서만 다시 훑고 싶을 때
RFC 9110은 If-Modified-Since가 최근에 바뀐 리소스만 다시 가져오는 웹 탐색 범위 제한에도 쓰인다고 설명한다. 크롤링 주기가 짧고 변경 빈도가 낮은 사이트에서는 특히 효율적이다.
주의할 점은 무엇일까?
1. If-Modified-Since는 GET과 HEAD에만 맞다
RFC 9110은 요청 메서드가 GET 또는 HEAD가 아니면 수신자가 If-Modified-Since를 무시해야 한다고 설명한다. 크롤러에서 문서 확인 용도로 쓰는 것은 적절하지만, 상태 변경 요청 제어 용도로 같은 방식으로 이해하면 안 된다.
2. 서버 시계를 기준으로 판단된다
RFC 9110은 이 헤더의 시각을 원본 서버의 시계 기준으로 해석해야 한다고 명시한다. 따라서 로컬 시간대 문자열을 임의로 넣기보다, 이전 응답에서 받은 HTTP-date를 그대로 재사용하는 편이 가장 안전하다.
3. Last-Modified가 없을 수 있다
모든 리소스가 이 헤더를 보내는 것은 아니다. RFC 9110은 리소스에 수정 시각이 없으면 If-Modified-Since를 무시해야 한다고 설명한다. 크롤러는 이 경우 일반 GET으로 돌아가거나, 가능하면 ETag 기반 검증으로 전환해야 한다.
4. 밀리초 단위 변경 감지는 기대하면 안 된다
수정 시각 검증은 본질적으로 시간값 비교이기 때문에, 빠르게 여러 번 갱신되는 API나 실시간 데이터에는 충분히 정밀하지 않을 수 있다. 내용 동일성 자체가 중요하다면 ETag 쪽이 더 적합하다.
간단한 요청 예시는?
GET /notice.html HTTP/1.1
Host: example.com
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
리소스가 그 시각 이후 바뀌지 않았다면 서버는 본문 없이 304 Not Modified를 보낼 수 있다. 바뀌었다면 새 본문과 함께 갱신된 Last-Modified 값이 다시 온다.
FAQ
Q. Last-Modified만 있으면 항상 충분할까?
항상 그렇지는 않다. MDN 기준으로 Last-Modified는 ETag보다 덜 정확하다. 내용 동일성을 더 엄밀하게 판별해야 하면 ETag가 더 적합하다.
Q. If-None-Match와 함께 보내면 어떻게 될까?
RFC 9110 기준으로 수신자는 If-None-Match가 있으면 If-Modified-Since를 무시해야 한다. 둘을 함께 보내더라도 실제 우선순위는 ETag 쪽이 더 높다.
Q. 크롤러 저장소에는 무엇을 같이 보관해야 할까?
최소한 본문, 응답 시각, Last-Modified, 가능하면 ETag를 함께 보관하는 편이 좋다. 그래야 서버가 어떤 검증 수단을 제공하는지에 따라 재수집 전략을 바꿀 수 있다.
정리
Last-Modified와 If-Modified-Since는 구현이 단순하고 널리 지원되는 조건부 요청 조합이다. 2026년 5월 22일 기준 RFC 9110과 MDN 문서의 핵심은 세 가지다. 첫째, Last-Modified는 리소스의 최종 수정 시각을 나타낸다. 둘째, If-Modified-Since는 GET/HEAD 요청에서 변경이 없으면 304를 받게 해 준다. 셋째, 더 정확한 검증이 필요하면 ETag를 우선 고려해야 한다.
크롤러에서는 이전 응답의 날짜 값을 그대로 재사용하고, 304 응답을 정상 흐름으로 취급하는 것만으로도 수집 비용을 꽤 줄일 수 있다.
참고 자료
'시리즈물 > 데이터 수집을 위한 크롤링' 카테고리의 다른 글
| [크롤링] 데이터 수집을 위한 크롤링 10편 : Sitemap XML과 sitemap index 사용법 (0) | 2026.06.11 |
|---|---|
| [크롤링] 데이터 수집을 위한 크롤링 8편 : ETag와 If-None-Match로 변경된 페이지만 다시 받는 방법 (0) | 2026.05.14 |
| [크롤링] 데이터 수집을 위한 크롤링 5편 : Yahoo 파이낸스를 이용한 환율 크롤링 (422) | 2019.03.02 |
| [크롤링] 데이터 수집을 위한 크롤링 4편 : Java의 설치와 간단한 Jsoup 예제 (1) | 2019.03.02 |
| [크롤링] 데이터 수집을 위한 크롤링 3편 : JSON, 더 자세한 설명 (434) | 2019.03.02 |





