본문 바로가기
← 목록으로

구글봇의 상대성 이론 - 시간과 캐싱의 비결

bigcommerce.websiteadvantage.com.au조회수 0332일 전

핵심

구글봇은 예측 가능한 독립적인 시간 체계를 유지한다. CPU가 작업 중일 때는 시간을 멈추고, 네트워크 자원 대기 중에도 시간을 멈추며, 유휴 상태일 때만 빠르게 진행한다. 약 5초(구글봇 내부 시간)에 도달하면 뷰포트를 조정하고 페이지가 콘텐츠를 로드할 마지막 기회를 얻은 후, 약 5.25초일 때 렌더링된 HTML을 캡처한다.

연구 배경

이 분석은 2025년 초 수행되었으며, JavaScript 위젯이 구글봇에 감지되지 않는 문제를 해결하려는 초기 조사에서 비롯되었다. 다양한 실험 후 여러 이론을 개발했으며, 현재 주제가 업계에서 주목받고 있어 공개하기로 결정했다.

구글봇의 시간 이론

구글봇은 자체 제어 속도로 변형된 시간을 가진 예측 가능한 환경을 만든다. 작업 중이거나 네트워크 자원을 기다릴 때는 시간을 멈추고, 그렇지 않으면 시간이 빠르게 진행한다.

관찰 방법론: 구글봇을 들여다보는 외부 관점

구글은 구글봇 활동에 대한 인사이트를 제공하는 몇 가지 도구를 제공한다(예: 서치 콘솔의 URL 검사 도구, 독립형 리치 결과 테스트 도구). 이를 통해 다음을 관찰할 수 있다:

실제 색인에 페이지를 추가하는 구글봇은 테스트 도구와 다르게 동작한다. 테스트 도구와 실제 구글봇의 동기(motivation)가 다르기 때문이다(예: 실제 구글봇은 효율성을 원하므로 적극적으로 캐싱함). 따라서 두 시나리오 모두 테스트해야 한다.

서버 로그를 통해서도 정보를 수집할 수 있지만 어렵고, 이 정보가 필요하지 않음을 발견했다.

관찰 방법: 렌더링된 HTML에 데이터 삽입

작은 로깅 스크립트를 사용하여 렌더링된 HTML에 데이터를 삽입한 후, 도구를 통해 관찰할 수 있다. htmlLog(message) 함수는 메시지를 텍스트 스크립트(테스트 도구에서 보기 좋음)와 페이지에 표시되는 사본에 삽입한다. 각 줄은 현재 performance.now() 값으로 브라우저 시작 이후의 밀리초를 추적한다. 모든 시간은 UTC이다.

일반 브라우저에서 기본적으로 로그되는 항목:

performance.now()
154.1999999880791: User Agent: Mozilla/5.0...
154.1999999880791: Browser Start (performance.timeOrigin): 2025-01-05T20:52:36.293Z
154.1999999880791: Server Start (HTML requested): 2025-01-05T20:52:36.373Z
154.3999999761581: Body End Script
228.5999999940395: Event: DOMContentLoaded
254.0000000000000: Event: load

구글봇 공개: 검색 뒤의 실체

네비게이터 API에서 구글봇에 대한 세부 정보를 수집하는 간단한 시연. 실제 구글봇의 스냅샷:

13.0000000000000: navigator: {
  "cookieEnabled": true,
  "appName": "Netscape",
  "appCodeName": "Mozilla",
  "platform": "Linux armv8l",
  "product": "Gecko",
  "appVersion": "5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.139 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
  "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.139 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
  "language": "en-US",
  "onLine": true,
  "deviceMemory": 8,
  "hardwareConcurrency": 128,
  "vendor": "Google Inc.",
  "javaEnabled": false
}

일부 페이지 속도 최적화 전문가들이 Linux 머신의 자원을 비활성화한다. 페이지 속도 테스트 도구가 Linux에서 실행되는 경향이 있고, 페이지의 절반을 비활성화하면 로딩이 훨씬 빨라 보이기 때문이다. 이는 Linux 사용자에게 좋지 않으며, 구글봇이 페이지를 제대로 로드하는 것을 막을 수도 있다.

난수의 복잡성과 구글봇 내 예측 가능한 패턴

구글의 난수 생성은 상당히 예측 가능하다. 실제로는 난수가 아니다.

캐시 버스터를 설정하여 페이지 자원을 항상 크롤링하도록 하려던 중 무작위 숫자가 항상 같다는 것을 발견했다. 실제 구글봇을 통해 색인된 페이지에서 난수 시퀀스의 로그:

1.0000000000000: User Agent: Mozilla/5.0...
2.0000000000000: Browser Start (performance.timeOrigin): 2025-01-05T00:00:00.000Z
3.0000000000000: Server Start (HTML requested): 2025-01-05T21:16:43.275Z
4.0000000000000: Math.random() 1: 0.6393021999392658
5.0000000000000: Math.random() 2: 0.5943970666266978
6.0000000000000: Math.random() 3: 0.08336732489988208
7.0000000000000: Math.random() 4: 0.3935315718408674
8.0000000000000: Math.random() 5: 0.9578430985566229
9.0000000000000: crypto random: {
  "0": 866266943,
  "1": 2265860932,
  "2": 1996670117,
  "3": 3830160457,
  "4": 1005482941
}

테스트 구글봇을 사용한 라이브 테스트 결과는 동일한 난수를 보인다. 리치 결과 테스트 도구도 동일하다.

표준 브라우저에서는 로드할 때마다 숫자가 변한다:

848.3000000119209: Math.random() 1: 0.22958714071254382
848.3000000119209: Math.random() 2: 0.07547011299586193
...
1380.0000000000000: Math.random() 1: 0.5222172700746359
1380.0000000000000: Math.random() 2: 0.4440564579172728

컴퓨터는 일반적으로 현재 시간 같은 시드를 기반으로 시퀀스에서 의사난수(pseudorandom numbers)를 생성한다. 구글봇의 난수 시드가 상수인 것으로 추정된다.

결론: 구글봇은 페이지 콘텐츠가 더 예측 가능하도록 비난수화된 난수를 사용한다. 페이지를 볼 때마다 콘텐츠가 무작위로 변하는 것을 원하지 않는다.

시간의 불일치: 구글봇 시간과 실제 시간

오래전에 타사 리뷰 위젯과 구조화된 데이터가 구글봇에 의해 감지되지 않는 문제를 해결하려 할 때 이 분석이 시작되었다. 구글봇 시계가 약 5.5초에 도달하면 시공간을 멈추고 렌더링된 HTML을 처리한다는 것을 발견했다.

슈뢰딩거의 봇(Schrödinger's bot) 이론으로, Tame The Bots의 Dave Smart가 지적했다. 구글봇은 다른 리듬으로 틱한다. 추가 테스트가 이를 확인했지만, 구글봇의 시간 개념에 대해 깊이 있게 들어가기까지 지금까지 걸렸다. 구글봇이 약 5.5초라고 생각하는 것이 맞았지만, 행성의 시간은 달랐다.

크롤링 종료 시점에 10ms 타임아웃 루프에서 performance.now()를 로깅하는 테스트. 구글봇이 보여주는 결과:

js-performance.now: 5250.0999999046326

현실을 잇기: 구글봇이 실제 세계를 엿보도록 활성화

구글봇이 어떻게 움직이는지 어떻게 관찰할까? 관찰자로서 구글봇이 제공하는 HTML에 데이터를 로깅하여 그 시간 진행 상황을 실제 시간과 상대적으로 표시해야 한다.

첫 번째 단계는 서버가 HTML을 생성할 때의 실제 시간을 삽입하는 것이다. 구글봇이 정확히 언제 요청했는지 알 수 있다:

3.0000000000000: Server Start (HTML requested): 2025-01-05T21:16:43.275Z

또한 시간이 진행됨에 따라 관찰하고 싶다. 해결책은 테스트 페이지가 요청하는 자원들 내에서 실제 시간을 반환한 후, 이 실제 시간을 나중에 관찰할 수 있도록 페이지에 로깅하는 것이다. 서버는 구글봇이 페이지를 처리하는 동안 실제 시간이 어떻게 지나가는지의 출처가 된다:

27.0000000000000: Resource "async1": Server Request: 2025-01-05T23:23:49.3750522Z (+4237ms)
28.0000000000000: Resource "async1": Server Delay: 100
29.0000000000000: Resource "async1": Server Response: 2025-01-05T23:23:49.4750194Z (+4337ms)

참고: 많은 혼란 끝에 구글봇이 이 자원들을 매우 잘 캐싱(이후 참조)하고 있어 과거 서버 응답의 에코를 보고 있다는 것을 깨달았다. 이를 해결하기 위해 요청에 캐시 버스터를 추가했고, 그때 구글봇 내에서 난수나 시간에 접근할 수 없다는 것을 발견했다.

구글봇 시간의 기원

표준 브라우저와 테스트 도구에서 브라우저 시간은 실제 시간으로 시작한다:

2.0000000000000: Browser Start (performance.timeOrigin): 2025-01-05T21:09:26.000Z
3.0000000000000: Server Start (HTML requested): 2025-01-05T21:09:27.223Z

브라우저 시작 시간이 서버 시작 시간(관찰된 실제 시간)과 매우 가깝다. 그러나 크롤링된 페이지 HTML을 보면 것들이 맞지 않는다:

2.0000000000000: Browser Start (performance.timeOrigin): 2025-01-05T00:00:00.000Z
3.0000000000000: Server Start (HTML requested): 2025-01-05T21:06:20.911Z

실제 구글봇은 시간대를 가린다!

결론: 시간대는 페이지 콘텐츠의 난수성을 제거하기 위한 상수다.

시간 팽창: 구글봇 시계의 느린 틱

Date.now()를 5번 연속으로 호출하는 테스트(다른 작업 없음)를 실행했다. 그 후 각 Date.now() 요청 사이에 지연을 추가한 테스트를 반복했다(1,000개 요소 추가/제거). 일반 브라우저의 모습:

941.5999999940395: JS Date elapsed ms: 942 (5번 모두)
972.0999999940395: delay complete
972.0999999940395: JS Date elapsed ms: 972
1000.0000000000000: delay complete
1000.0999999940395: JS Date elapsed ms: 1000
...

예상대로 처음 5개 요청은 순간적(모두 동시에)이었고, 다음은 지연 시간을 반영했다. Date.now()performance.now()가 밀접하게 일치했다.

구글봇으로 테스트를 실행했다:

2.0000000000000: Browser Start (performance.timeOrigin): 2025-01-05T22:11:04.000Z
3.0000000000000: Server Start (HTML requested): 2025-01-05T22:11:04.881Z
4.0000000000000: JS Date elapsed ms: 0
5.0000000000000: JS Date elapsed ms: 1
6.0000000000000: JS Date elapsed ms: 2
7.0000000000000: JS Date elapsed ms: 3
8.0000000000000: JS Date elapsed ms: 4
9.0000000000000: delay complete
10.0000000000000: JS Date elapsed ms: 5
...

첫 번째 주목할 점은 브라우저 시작과 테스트 실행 사이에 소비된 시간이 없다는 것(일반 브라우저에서는 941ms의 지연). 테스트의 지연도 실행 시간이 없다.

결론: 구글봇 시간은 CPU가 바쁠 때 멈춘다.

1ms씩 증가하는 것이 보인다. performance.now()Date.now()가 다른 시간을 반환한다. 각 API는 호출될 때마다 별도로 증가한다.

결론: 구글봇은 시간이 계속 움직이는 것처럼 보이도록 시간 API에 1ms 증분을 추가한다. 예를 들어, 나쁜 코딩 관행에서 현재 시간을 확인하는 루프 기반 타이머가 구현될 수 있다. 시간이 멈추면 루프가 영원히 실행되고 구글 행성에서 작은 폭발이 발생한다.

최종 타임아웃 확인은 테스트 전후에 실행된다. 둘 다 2초로 표시되어 내부 시간이 우리에게 주어진 시간을 사용하지 않음을 나타낸다. 시간을 빠르게 하자:

4.0000000000000: Date.now() = 0
5.0000000000000: 10,000 * Date.now(). Date.now() = 10001
5006.0000000000000: 5,000 * performance.now(). Date.now() = 10002
5010.0000000000000: 2 seconds timeout: JS Date elapsed ms: 10003
5011.0000000000000: 5 seconds timeout: JS Date elapsed ms: 10004

Date.now() 호출 10,000회는 Date.now()만 증가시키고 performance.now()에 영향 없음. performance.now() 호출 5,000회는 performance.now()만 증가시키고 Date.now()에 영향 없음. 타임아웃은 테스트 완료 후 발생하여 이들이 API가 반환하는 것과 다른 시간을 사용함을 나타낸다. 6초 타임아웃이 기록되지 않아 구글봇이 5초와 6초 사이(내부 시간)에 멈췄음을 나타낸다.

구글봇 시계와 시간 왜곡

브라우저가 코드 실행에 바쁠 때 시간이 멈추는 것을 이미 발견했다. 그러나 실제 시간과 어떻게 비교되는지는 아직 테스트하지 않았다. 실제 시간을 얻기 위해 자원 요청을 트리거하는 간단한 5초 타이머를 테스트하자:

10.0000000000000: Resource "start": Server Request: 2025-01-05T23:05:35.2352750Z (+307ms)
...
15.0000000000000: Event: load
5019.8999996185303: Resource "5seconds": Server Request: 2025-01-05T23:05:35.3907412Z (+462ms)

렌더링이 시작될 때 시간을 얻기 위한 초기 자원 요청이 있다. 5초 타임아웃에서 서버는 시간 변화 455ms를 표시했다. 구글봇 시간으로 빠른 5초다.

구글봇을 불릿 타임으로 만들 수 있다.

결론: 구글봇이 할 일이 없을 때 시계가 빨라지고 불릿 타임(bullet time)으로 간다.

이 테스트의 변형을 하자. 이번에는 서버가 5초 지연을 유발한다:

3.0000000000000: Server Start (HTML requested): 2025-01-05T23:24:19.974Z
10.0000000000000: Resource "5seconds": Server Request: 2025-01-05T23:24:20.1581075Z (+184ms)
11.0000000000000: Resource "5seconds": Server Delay: 5000
12.0000000000000: Resource "5seconds": Server Response: 2025-01-05T23:24:25.1553453Z (+5181ms)

구글봇이 네트워크 자원을 기다리는 동안 시간이 멈춘다. 100ms 서버 지연이 있는 여러 자원의 경우도 동일하다. 동기 요청이 차단하는 방식과 비동기 요청이 DCL(DOMContentLoaded) 이후 나타나는 방식에 주목:

10.0000000000000: Resource "sync1": Server Request: 2025-01-05T23:22:08.2030851Z (+372ms)
...
26.0000000000000: Event: DOMContentLoaded
27.0000000000000: Resource "async1": Server Request: 2025-01-05T23:22:08.4207167Z (+589ms)

결론: 네트워크 자원이 대기 중일 때 구글봇은 시계를 멈추어 페이지가 더 많은 실제 시간을 확보하도록 한다.

임계값에서의 정지: 구글봇이 실제 시간이 정점에 도달할 때 멈춘다

구글봇이 페이지를 무한정 로드하도록 두지는 않는다. 오랫동안 구글봇을 바쁘게 유지하면 어떻게 될까?

먼저 연속으로 로드되고 그 사이에 유휴 시간이 없는 15개 자원의 시퀀스를 유발하자:

3.0000000000000: Server Start (HTML requested): 2025-01-05T23:28:32.854Z
...
160.0000000000000: Resource "resource15": Server Request: 2025-01-05T23:28:42.3410490Z (+9487ms)
162.0000000000000: Resource "resource15": Server Response: 2025-01-05T23:28:42.8404948Z (+9986ms)

구글봇 시간은 약간 틱하지만 9,986ms의 실제 시간에서 162ms에만 도달한다. 일관된 테스트이므로 구글봇 시간이 실제 시간에서 얼마나 부드럽게 증가하는지 볼 수 있다:

계속할 수 있는지 보자:

3.0000000000000: Server Start (HTML requested): 2025-01-05T23:50:35.140Z
...
52.0000000000000: Resource "resource4": Server Response: 2025-01-05T23:50:56.4601614Z (+21320ms)
...
112.0000000000000: Resource "resource10": Server Response: 2025-01-05T23:51:27.2722370Z (+52132ms)
113.0000000000000: 100ms
121.0000000000000: Event: load
2010.0000000000000: 2 seconds
5009.9000000953674: 5 seconds

실제 시간 52,132ms에서 서버 요청이 멈추고 구글봇의 불릿 타임은 여전히 112ms였다.

그러나 구글봇은 계속 타임아웃을 트리거하고 목표 시간 5.25초에 도달했다:

js-performance.now: 5249.9000000953674

결론: 코드를 실행하고 네트워크 요청을 하면 구글봇 시계가 멈춘다. 이 중 약 52초의 실제 시간에서 플러그를 뽑고 모든 네트워크 요청을 취소한다. 그러나 계속 실행된다. 이 시점에서 할 일이 거의 없어서 시계가 목표인 5.25초에 도달할 기회를 얻고 시공간이 멈추고 스냅샷을 찍는다.

무한의 탐색: 구글봇 우주의 무한한 가능성

구글은 스크롤하지 않는다(스크롤 이벤트 확인), 하지만 스크롤처럼 추가된 콘텐츠를 감지하는 깊은 뷰포트를 가지고 있다고 알려져 있다.

설정 높이의 div를 추가하여 동적으로 깊어지는 페이지를 테스트했다. 많이 추가했고, 결국 매 구글봇 밀리초마다 추가되고 높이를 1000픽셀로 설정했다.

div를 추가하기 전 테스트 페이지의 초기 치수(count=0):

4.0000000000000: initial: {
  "count": 0,
  "window": {
    "innerWidth": 981,
    "innerHeight": 1742,
    "outerWidth": 412,
    "outerHeight": 732
  },
  ...
}

창, 화면 및 뷰포트의 세부 사항은 전문가가 아니다. 구글봇의 핵심은 페이지가 더 아래로 동적 콘텐츠 로드를 트리거하도록 프롬프트된다는 것이다.

구글봇이 2개 리사이즈 이벤트를 실행한다. 첫 번째, 구글봇 시간의 5초에서 이 리사이즈 이벤트를 실행했다:

5000.9000000953674: Event: resize
5001.9000000953674: resize: {
  "count": 1250,
  "window": {
    "innerWidth": 981,
    "innerHeight": 1742,
    "outerWidth": 1,
    "outerHeight": 1
  },
  ...
}

이는 창의 외부 치수를 1픽셀로 변경(이상함)하고 뷰포트 스케일을 0.42에서 1로 변경한다.

그 후 5.3초에 또 다른 리사이즈:

5299.9000000953674: Event: resize
5300.9000000953674: resize: {
  "count": 1325,
  "window": {
    "innerWidth": 981,
    "innerHeight": 1251074,
    ...
  },
  ...
}

그리고 쾅! 높이는 이제 100만 픽셀 이상이다. 나는 많이 추가했다. 백만 개는 충분하므로 더 이상 진행하지 않았다. 구글 행성에서 또 다른 폭발을 일으키고 싶지 않다.

더 현실적인 무한 스크롤 시나리오로 이동하자. 이는 종종 교점 관찰기(IntersectionObserver)를 사용하여 사용자가 섹션 끝에 있을 때를 감지한 후 반복되는 새 섹션을 그 후에 추가하도록 구현된다. 이 다음 테스트는 다음 섹션의 콘텐츠를 얻기 위해 자원 요청을 포함하는 시뮬레이션을 한다.

이것은 그리 흥미롭지 않았다. 첫 번째 리사이즈에서 첫 페이지가 표시 가능한 것으로 식별되었다. 자원을 로드했고 두 번째 페이지를 추가했다. 두 번째 리사이즈에서 표시 가능한 것으로 식별되었다. 자원을 로드하고 세 번째 페이지를 추가했지만 시간이 멈췄다. 교점 관찰기는 리사이즈 이벤트 후에만 실행 중인 것 같다.

관련. 100vh를 히어로 이미지로 사용하여 화면을 채우는 경우. 이미지가 매우 키가 크기 때문에 URL 검사 미리보기가 이상할 것이다(사용하는 뷰포트가 매우 크기 때문). 표시 가능한 콘텐츠가 항상 뷰포트 밖에 있기 때문에 SEO 순위 문제를 일으킬 수 있다고 의심한다. Martin은 이것에 대해 다소 확인했고 내가 관찰한 것을 제시했다. 그는 이것이 SEO와 구글이 콘텐츠를 보는 것에 문제가 아니라고 생각하지만, max-height를 추가하여 제한할 것을 조언한다.

캐싱 연대기: 공간과 시간 왜곡

페이지를 렌더링하는 데 필요한 자원을 크롤링하면 자원을 호스팅하는 호스트명의 크롤 예산이 깎인다. 이를 완화하기 위해 WRS(Googlebot의 웹 렌더링 서비스)는 페이지에서 참조하는 모든 자원(JavaScript 및 CSS)을 캐싱하려고 시도한다.

WRS 캐시의 TTL(Time To Live)은 HTTP 캐싱 지시어의 영향을 받지 않으며, 대신 WRS는 모든 것을 최대 30일 동안 캐싱하여 사이트의 크롤 예산이 다른 크롤 작업을 위해 보존되도록 돕는다.

이 캐싱은 실제 구글봇에서만 수행된다. 테스트 도구는 최신 자원으로 작업하여 정확한 결과를 얻기를 원한다.

간주곡: 구글봇의 크롤링과 렌더링 사이의 일시 중지 해독

구글은 먼저 HTML을 크롤링한 후 나중에 페이지를 렌더링하고 마지막으로 색인에 추가하는 방법을 공개한다.

요즘 그들은 크롤 렌더링 간 지연이 일반적으로 짧다고 말한다. 서버가 HTML을 제공하는 것부터 페이지가 첫 번째 자원을 로드할 렌더링까지 23초 간격을 보이는 예:

3.0000000000000: Server Start (HTML requested): 2025-01-05T21:06:20.911Z
10.0000000000000: Resource "start": Server Request: 2025-01-05T21:06:44.4748315Z (+23563ms)

디지털 공백: 구글봇 우주의 블랙홀 효과

실제 사이트에서 몇 가지 테스트를 추가하여 다른 정보를 발견할 수 있는지 확인했다.

구글봇에서 탈출하지 않는 자원 요청

URL 검사가 자원 오류를 보고하기도 한다. 대부분 "기타 오류(Other error)"로. 더 알아보기 위해 자원 기록에 performanceObserver(PerformanceObserver)를 사용하고 오류를 얻기 위해 fetch 요청을 가로챘다.

자원의 시간은 대부분 구글봇 시간이었지만 이상한 실제 시간 순간도 있었다. 신뢰할 만한 것은 없었지만 구글봇 내부에 약간의 실시간 지식이 있음을 나타냈다:

resource: {
  "name": "https://.../Resource?name=resource8",
  "entryType": "resource",
  ...
  "responseStart": 1325.7000002861023,
  "responseEnd": 10,
  ...
}

자원 요청이 상태 0을 반환하는 경우가 빈번했다. 이는 일반적으로 CORS 없는 크로스 오리진 요청 또는 완료 전에 취소된 요청을 의미한다. 글꼴 관련 자원, 404, robots.txt로 거부된 요청이 취소되는 것을 발견했다. 404의 상태 코드를 볼 수 없는 이유는 확실하지 않다.

결론: 구글봇 헤드리스 브라우저는 모든 요청을 가로채고 거부되거나 실패하거나 중요하지 않다고 생각하는 요청(예: 글꼴 관련)을 취소한다.

URL 검사 자원 보고서는 자신만의 방식으로 상태 정보를 얻어야 한다. 요청을 가로채는 코드 내의 로깅에서. 보고서에는 표기법만 다른 POST 요청 시리즈의 첫 번째만 보고되는 것과 같은 일부 특수성이 있다.

구글봇에서 탈출하는 구글 특정 자원

흥미롭게도 구글은 robots.txt를 통해 구글 애널리틱스를 거부하지 않는다. 기본 gtag 스크립트는 로드되지만 이후 이벤트 요청은 취소된다. 우리는 ga 쿠키가 설정되는 것도 본다.

광고 추적은 robots.txt로 차단되지만 GA4 doubleclick이 가끔 통과한다. 이는 페이지 자원 보고서에서 볼 수 있다.

Facebook은 태그를 로드하지만 이벤트는 robots.txt로 차단된다.

DIY 분석: 자신만의 구글봇 실험 수행

다음은 자신만의 테스트를 수행하기 위한 간단한 코드다. head 섹션 상단에 배치하고 htmlLog()를 호출하여 구글봇이 생성한 렌더링된 HTML에서 볼 수 있는 메시지를 추가한다.

<script type="text/plain" id="html-log">
</script>
<script>
    const htmlLogTag = document.getElementById("html-log");
    function htmlLog(message) {
        htmlLogTag.appendChild(document.createTextNode(message+'\n'));
    }
    htmlLog('User Agent: ' + navigator.userAgent);
    htmlLog('Browser Start (performance.timeOrigin): ' + (new Date(performance.timeOrigin)).toISOString());
    addEventListener("DOMContentLoaded", (event) => {
        htmlLog('Event: DOMContentLoaded');
    });
    addEventListener("scroll", (event) => {
        htmlLog('Event: scroll '+document.documentElement.scrollTop);
    });
    addEventListener("load", (event) => {
        htmlLog('Event: load');
    });
    addEventListener("visibilitychange", (event) => {
        htmlLog('Event: visibilitychange hidden='+document.hidden);
    });
    addEventListener("error", (event) => {
        htmlLog('Event: error '+JSON.stringify(event));
    });
</script>