"더 보기" 버튼 페이지네이션과 SEO: 구글 크롤러는 버튼을 누르지 않는다

목록을 '더 보기' 버튼으로 바꿨더니 글 49개 중 10개만 링크로 연결돼 있었다. 구글 크롤러가 버튼을 누르지 않는 이유를 구글 문서로 확인하고, 모든 글을 <a href> 링크로 잇는 방법을 정리했다.

목록을 바꿨을 뿐인데

이 블로그는 10월 7일에 목록 화면을 새로 만들면서 글을 처음에 10개만 보여주고, 나머지는 "더 보기" 버튼을 누르면 10개씩 더 보이게 바꿨다. 화면도 깔끔해지고 사용자 입장에서는 아무 문제가 없었다.

그런데 서치 콘솔에서 색인 상태를 조사하다가, 목록 페이지의 서버 HTML을 열어보고 이걸 발견했다.

목록전체 글HTML에 링크가 있는 글
한국어 (/)49개10개
영어 (/en)17개11개

나머지 글은 "더 보기"를 눌러야 화면에 나오는데, 구글 크롤러는 그 버튼을 누르지 않는다. 사람에게는 49개가 다 보이는 목록이, 크롤러에게는 10개짜리 목록이었던 것이다.


구글 크롤러는 정말 버튼을 누르지 않을까

"버튼을 안 누른다"는 말은 블로그마다 흔히 나오지만, 근거를 구글 문서에서 직접 확인해 봤다.

구글은 href 속성이 있는 <a> 요소로 된 링크만 안정적으로 따라간다. 클릭해야 내용이 바뀌는 자바스크립트 동작은 실행하지 않는다.

출처내용 (요약)
Google 검색 센터: 링크 권장사항일반적으로 구글은 href 속성이 있는 <a> 요소인 링크만 크롤링할 수 있다. href가 없거나 스크립트 이벤트로 링크처럼 동작하는 요소에서는 URL을 안정적으로 뽑아내지 못한다
Google 검색 센터: 페이지로 나누기, 점진적 페이지 로드"더 보기" 버튼과 무한 스크롤을 점진적 로드 방식으로 소개하면서, 검색엔진이 모든 콘텐츠를 찾을 수 있도록 각 페이지를 링크로 순서대로 연결하라고 권장한다
Google 검색 센터: 자바스크립트 SEO 기본사항Googlebot은 자바스크립트를 렌더링하지만, 링크는 href가 있는 <a>에서 찾는다
Search Engine Journal: Googlebot Doesn't Click on Buttons (영문 외부 기사)구글의 마틴 스플릿(Martin Splitt)이 Googlebot은 버튼을 클릭하지 않으니, 버튼 대신 일반 링크를 쓰라고 답한 내용을 다룬다

여기서 헷갈리기 쉬운 점이 있다. Googlebot은 자바스크립트를 실행해서 화면을 렌더링한다. 그래서 "자바스크립트로 만든 내용은 구글이 못 본다"는 말은 틀리다. 정확히는 페이지를 처음 열었을 때 렌더링되는 내용은 보지만, 사용자가 무언가를 눌러야 나오는 내용은 보지 못한다. "더 보기" 뒤의 글은 바로 이 경우다.


버튼과 링크, 무엇이 다른가

화면에서는 똑같이 생긴 "더 보기"라도 HTML이 다르면 크롤러에게는 완전히 다르게 보인다.

<!-- ❌ 크롤러가 따라갈 주소가 없다. 클릭해야만 글이 추가된다 -->
<button type="button" onclick="loadMore()">더 보기</button>

<!-- ❌ 링크처럼 보이지만 href가 없어서 주소를 뽑아낼 수 없다 -->
<span class="link" onclick="location.href='/page/2'">더 보기</span>

<!-- ✅ 크롤러가 /page/2 로 가서 다음 글 목록을 읽을 수 있다 -->
<a href="/page/2">더 보기</a>

이 블로그의 "더 보기"는 첫 번째 경우였다. <button>은 어떤 동작을 실행하는 요소이고, 어딘가로 이동하는 요소는 <a href>다. 둘의 차이는 의미 있는 HTML 쓰기 글에도 정리했다.


내 사이트도 같은 문제가 있는지 확인하기

가장 간단한 방법은 서버가 보내는 HTML에 글 링크가 몇 개 있는지 세는 것이다.

# 목록 페이지 HTML에서 글 주소(/ko/...)로 가는 링크 수 세기
curl -s https://iambilly-blog.vercel.app/ | grep -o 'href="/ko/[^"]*"' | sort -u | wc -l

이 숫자가 전체 글 수보다 훨씬 작다면, 나머지 글은 링크로는 닿을 수 없다는 뜻이다. 자바스크립트로 렌더링하는 사이트라면 서치 콘솔의 URL 검사 → 크롤링된 페이지 보기에서 구글이 렌더링한 HTML을 확인할 수도 있다. 어느 쪽이든 버튼을 눌러야 나오는 글은 거기에 없다.

또 하나의 확인 방법은 링크만 따라가는 크롤러를 돌려 보는 것이다. 이 블로그는 Nuxt의 빌드 크롤러(nitro.prerender.crawlLinks)가 홈에서 링크를 따라가며 페이지를 미리 만드는데, 고치기 전에는 이 크롤러가 찾은 페이지가 35개뿐이었다. 글 상세 페이지의 "함께 읽으면 좋은 글" 링크까지 다 따라가도 그 정도였다.


해결 방법 세 가지

방법어떻게어울리는 경우
번호 페이지네이션/page/2, /page/3처럼 페이지마다 실제 주소를 만들고 <a href>로 연결글이 수백 개 이상인 사이트
링크로 된 "더 보기""더 보기"를 <a href="/page/2">로 만들고, 자바스크립트가 있으면 클릭을 가로채서 그 자리에 글을 붙인다지금 화면(더 보기)을 유지하고 싶을 때
전체 글 목록 페이지모든 글을 링크로 나열한 페이지를 하나 만들고, 모든 페이지에서 그곳으로 링크글이 수십~수백 개인 블로그

두 번째 방법은 자바스크립트가 없어도 동작하는 링크를 먼저 만들고, 그 위에 자바스크립트로 더 나은 경험을 얹는 방식이다. 이때 /page/2 주소로 직접 들어가도 서버가 2페이지 글 목록을 실제로 보여줘야 한다. 주소만 있고 내용이 없으면 크롤러가 가도 소용이 없다.

이 블로그는 세 번째 방법을 골랐다. 글이 49개라 한 페이지에 다 들어가고, 목록 화면은 그대로 둘 수 있기 때문이다.

  • /archive(한국어), /en/archive(영어): 모든 글을 연도별 일반 링크로 나열
  • 모든 페이지 푸터와 목록의 "더 보기" 아래에 이 페이지로 가는 링크 추가

다시 빌드하자 크롤러가 한국어 49/49개, 영어 17/17개 글에 모두 도달했고, 미리 만든 페이지도 35개에서 159개로 늘었다. URL 검사에서도 /archive가 "URL이 Google에 등록되어 있음" 으로 확인됐다.


사이트맵이 있으면 괜찮지 않나?

이 블로그는 사이트맵에 모든 글이 들어가 있었다. 그러니 "더 보기" 문제가 있어도 구글은 사이트맵으로 글을 발견할 수는 있었다.

다만 사이트맵은 "이런 주소들이 있다"는 목록일 뿐이다. 사이트 안에서 링크로 연결되지 않은 글은 구글이 그 글이 얼마나 중요한지 판단할 단서가 적다. 구글 문서도 사이트맵과 별개로 모든 콘텐츠를 링크로 찾을 수 있게 하라고 권장한다. 사이트맵은 링크 구조를 보완하는 것이지 대신하는 것이 아니다.

한 가지 분명히 해 둘 점이 있다. 이 "더 보기" 문제는 10월 7일부터 10월 13일까지 있었다. 그 전부터 이 블로그의 색인 수가 적었던 건 다른 원인(예전 사이트맵 버그, 서버 에러 기간, 주소 이전)이 컸다. 그러니 "더 보기 버튼 때문에 색인이 안 됐다"고 말할 수는 없다. 다만 이 상태로 계속 뒀다면 새로 쓴 글들이 링크로는 발견되지 않는 구조였기 때문에, 원인 조사 중에 발견하고 바로 고쳤다.

예전 사이트맵 버그는 애드센스 ads.txt 경고를 받고 파헤치다가 찾은 진짜 색인 버그 글에, 서치 콘솔 상태 읽는 법은 서치 콘솔 "발견됨 / 크롤링됨 - 현재 색인이 생성되지 않음" 차이 글에 정리했다.


정리

기억할 것내용
크롤러가 따라가는 것href가 있는 <a> 링크
크롤러가 하지 않는 것버튼 클릭, 스크롤 같은 사용자 동작
확인 방법서버 HTML(또는 URL 검사의 렌더링된 HTML)에 글 링크가 몇 개 있는지 센다
해결번호 페이지네이션, 링크로 된 "더 보기", 전체 글 목록 페이지 중 하나로 모든 글이 링크로 닿게 한다

화면을 바꿀 때는 사람이 보는 화면만이 아니라 크롤러가 보는 HTML도 함께 바뀐다. 목록이나 메뉴처럼 다른 페이지로 이어지는 부분을 바꿨다면, 바꾼 뒤에 링크 수를 한 번 세어 보는 습관이 도움이 된다.

참고 자료