Blogger 피드 max-results=150인데 35개만 왔다: 끝까지 받는 페이지네이션
답부터 말하면 Blogger 공개 피드의 max-results는 전체 글 수를 보장하지 않았다.
2026년 9월 28일 측정에서 이 블로그는 totalResults=86을 알렸지만, max-results=150 응답에는 JSON과 Atom 모두 35개 entry만 들어 있었다.
해결은 totalResults와 실제 entry 수를 따로 읽고 start-index를 넘기는 것이다.
10개씩 순회한 최종 측정에서는 86개 고유 글을 모두 회수했다.
150을 요청했는데 왜 35개만 왔나?
처음에는 150이 전체 86개보다 크니 한 번에 끝날 것으로 봤다.
그런데 JSON 응답의 openSearch$totalResults는 86, entry 배열 길이는 35였다.
Atom도 같은 결과였다.
max-results 값을 바꿔 보니 경계가 더 분명했다.
35까지는 요청한 수만큼 왔지만, 36부터는 35개에 멈췄다.
| 형식 | max-results | totalResults | 실제 entry |
|---|---|---|---|
| JSON | 1 | 86 | 1 |
| JSON | 10 | 86 | 10 |
| JSON | 25 | 86 | 25 |
| JSON | 35 | 86 | 35 |
| JSON | 36 | 86 | 35 |
| JSON | 50 | 86 | 35 |
| JSON | 100 | 86 | 35 |
| JSON | 150 | 86 | 35 |
| Atom | 150 | 86 | 35 |
문제는 itemsPerPage도 요청값 150으로 표시된다는 점이다.
이 값만 믿으면 실제 배열이 짧다는 사실을 놓친다.
결국 검증 기준은 요청값이 아니라 len(entry)다.
주문서에 150개라고 적혀 있어도 상자에 35개만 들었다면, 세어 볼 것은 주문서가 아니라 상자다.
다만 피드는 이유를 적은 송장을 함께 주지 않는다.
35개가 Blogger의 공통 상한인가?
아니다.
같은 날 공개 Blogspot 두 곳의 JSON 피드에 max-results=150을 보냈다.
Blogger 공식 블로그는 전체 540개 중 150개, Google Blog는 전체 3,374개 중 150개를 반환했다.
따라서 35개를 Blogger 전체의 고정 상한이라고 말할 수 없다.
이 블로그에서 재현된 응답 특성이다.
본문 크기 때문이라고 단정하기도 어렵다.
max-results=150 JSON 응답은 약 234만 바이트였지만, 본문을 뺀 summary 피드는 약 11만 바이트인데도 35개만 왔다.
응답 바이트 제한인지, 블로그별 설정인지, 피드 구현의 다른 조건인지는 이번 측정으로 확인하지 못했다.
start-index로 어떻게 끝까지 받나?
max-results=150을 유지한 채 실제 반환 수만큼 이동해도 된다.
이번 측정은 start-index=1에서 35개, 36에서 18개, 54에서 33개를 받아 합계 86개가 됐다.
하지만 페이지 크기가 35라고 고정하면 안 된다.
안전한 쪽은 작은 페이지를 요청하고, 매번 실제 entry 수와 ID를 확인하는 방식이다.
import json
from urllib.parse import urlencode
from urllib.request import urlopen
base = "https://cd4761.blogspot.com/feeds/posts/default"
start, page_size = 1, 10
posts = {}
while True:
query = urlencode({
"alt": "json",
"max-results": page_size,
"start-index": start,
})
with urlopen(f"{base}?{query}") as response:
feed = json.load(response)["feed"]
entries = feed.get("entry", [])
if not entries:
break
for entry in entries:
posts[entry["id"]["$t"]] = entry
start += len(entries)
total = int(feed["openSearch$totalResults"]["$t"])
if start > total:
break
print(len(posts))
이 코드는 2026년 9월 28일 최종 측정에서 86을 출력했다.
이 글이 발행된 뒤에는 글 수가 늘어 다른 숫자가 나온다.
확인할 것은 출력값이 그 시점의 totalResults와 같은지다.
start += page_size가 아니라 실제 반환된 len(entries)만큼 이동하는 것이 핵심이다.
Blogger 피드 수집보다 발행 흐름이 필요하다면 Claude Code + Blogger 자동화에 별도로 정리했다.
공개 수집 경로가 바뀔 때의 운영 기준은 엔드포인트는 죽는다 — X·Threads·Google Trends 무료 수집을 유지하는 규율 3가지에서 다뤘다.
공식 문서는 어디까지 말하나?
Google의 GData 공통 쿼리 문서는 max-results를 최대 검색 결과 수로 설명하고, 매우 큰 값을 주면 전체 피드를 받을 수 있다고 적는다.
동시에 start-index는 일반적인 커서가 아니며, 중간에 삽입이나 삭제가 있으면 여러 페이지의 합이 한 번의 큰 요청과 같다고 보장하지 않는다고 경고한다.
현재 Blogger API v3의 Posts: list 문서는 nextPageToken과 pageToken으로 다음 페이지를 잇는다.
API 키를 쓸 수 있는 수집기라면 변하는 공개 피드의 숫자 인덱스보다 이 방식을 우선할 만하다.
다만 공식 문서에서 이 블로그의 35개 반환을 설명하는 수치 상한은 찾지 못했다.
문서의 의미는 “큰 숫자 하나면 항상 끝난다”가 아니라, 실제 응답과 다음 페이지를 확인해야 한다는 쪽으로 읽는 편이 맞다.
어떤 조건에서 결론이 뒤집히나?
Blogger가 피드 구현을 바꿔 같은 요청에서 전체 글을 모두 반환하면 이번 35개 경계는 더 이상 재현되지 않는다.
글 수와 본문 구성이 다른 블로그에서는 이미 150개가 반환됐으므로, 35를 상수로 코드에 넣으면 안 된다.
글이 발행되거나 삭제되는 동안 start-index를 순회하면 중복이나 누락이 생길 수도 있다.
공식 문서도 이 한계를 명시한다.
변동이 없는 시점에 수집하고 ID를 중복 제거한 뒤, 필요하면 다시 한 번 대조해야 한다.
결국 기준은 max-results에 넣은 숫자가 아니다.totalResults, 실제 entry 수, 고유 ID 수를 함께 비교하고, 모자라면 다음 start-index를 요청하면 된다.
결론 · 요청값보다 실제 응답
max-results에 큰 숫자를 넣는 것만으로는 Blogger 공개 피드를 끝까지 받았다고 볼 수 없다.
판단 기준은 totalResults와 실제 entry 수, 고유 ID 수가 맞는지다.
지금 수집 코드를 열어 짧은 페이지네이션과 ID 중복 제거를 넣고, 마지막에 두 수를 대조하면 된다.
확인 범위
공개 피드와 공식 문서는 2026년 9월 28일 KST에 확인했다.
로그인, Blogger 편집기, 비공개 API 키는 사용하지 않았다.
86, 35, 18, 33은 모두 측정 당일 값이다.
글 수가 바뀌면 숫자도 바뀌므로, 직접 수집할 때는 totalResults와 고유 ID 수가 같은지부터 확인하면 된다.


댓글
댓글 쓰기