GitHub 저장소 페이지에는 pushed_at이라는 타임스탬프가 노출됩니다. 이 값은 어떤 브랜치에든 푸시가 들어오면 바뀔 수 있습니다. 그래서 기본 브랜치의 최신 커밋 시각과 어긋날 수 있죠. 기본 브랜치 날짜는 저장소 관리 상태를 보여주는 신호일 뿐이며, 패키지 매니저가 실제로 설치하는 코드와 반드시 같지는 않습니다.
패키지 매니저는 보통 레지스트리의 배포본이나 모듈 버전을 기준으로 해석합니다. 그래서 이번 점검에서는 저장소 활동과 공개된 아티팩트를 따로 살펴봤습니다. 둘 중 하나는 최신이어도 다른 하나는 오래됐을 수 있기 때문입니다.
그래서 추천 목록에 아직 남아 있는 35개 저장소를 골라, GitHub 헤더에는 나오지 않는 숫자, 즉 기본 브랜치에서의 최신 커밋 날짜를 직접 확인했습니다.
결과는 분명했습니다. 35개 중 14개는 pushed_at이 최신 기본 브랜치 커밋보다 180일 이상 앞서 있었고, 최대 차이는 1,802일에 달했습니다. 이 14개 중 3곳에서는 봇이 실제 원인이라는 점도 확인됐습니다. 아카이브 여부와 사람의 활동을 제외하고 나면, 확인된 봇 사례는 9개 후보 중 2개로 줄었습니다. 더 중요한 발견은 저장소의 최신성과 공개 아티팩트의 최신성이 서로 다를 수 있다는 점입니다.
무엇을, 어떤 기준으로 측정했나

공식 참고 문서: GitHub repository API.
여기에 나온 모든 수치는 2026-07-27 UTC 15:44~15:53 사이에 라이브 API 응답에서 읽어 캐시한 값입니다. 35행 데이터셋, 저장소 목록, 가공된 행, 그리고 artifacts/에 있는 수집/가공 스크립트가 점검에 사용한 입력값과 변환 코드를 그대로 보존합니다.
데이터는 4개 범주로 수집했습니다. 다만 레지스트리와 활동 조회는 모두 동일한 4회 호출이 아니라, 조건에 따라 선택적으로 수행했습니다.
GET /repos/{owner}/{repo}— 스타 수,archived,pushed_at, 라이선스,default_branch.GET /repos/{o}/{r}/commits?sha={default_branch}&per_page=1— 기본 브랜치의 최신 커밋. 저장소 관리 상태를 나타내는 신호로 사용.GET /repos/{o}/{r}/activity?per_page=30— 위 두 값이 어긋나는 모든 저장소에서, 실제로 무엇이pushed_at을 움직였는지 확인.GET /repos/{o}/{r}/releases와 PyPI 및 npm 레지스트리 — 마지막으로 아티팩트가 언제 배포됐는지 확인. 사실 이것이 더 중요했습니다.
staleness_days는 기본 브랜치 커밋 시점부터 기준 시점까지 지난 일수입니다. pushed_at과 그 커밋 사이의 차이는, 즉 이 점검에서 말하는 착시의 크기입니다. 180일을 넘으면 표시했습니다.
결과를 바꾼 두 가지 원칙도 분명히 밝혀야 합니다.
패키지의 출처는 추정하지 않고, 반드시 검증했습니다. README에 어떤 저장소가 언급되어 있다고 해서 그게 곧 그 저장소의 패키지는 아닙니다. 매핑은 레지스트리의 repository/project_urls 필드 또는 저장소 안에 커밋된 manifest로 확인된 경우만 인정했습니다. 그 테스트를 통과하지 못한 그럴듯한 매핑 6개는 다운로드 수에 의도적으로 포함하지 않았습니다.
그중 하나는 이 규칙 전체를 설명할 만큼 중요합니다. curl-cffi는 월 35,763,529회 다운로드되며, 멀리서 보면 lwthiker/curl-impersonate의 Python 바인딩처럼 보입니다. 그런데 그 저장소는 875일째 멈춰 있습니다. 여기에 curl-cffi를 붙였으면 newspaper3k보다 44배나 큰 숫자가 나왔겠지만, 그건 사실이 아니었습니다. curl-cffi의 PyPI 메타데이터는 lexiforest/curl_cffi를 가리키고, 이는 별도의 활발히 유지되는 프로젝트로 2026-04-03에 마지막 배포가 있었습니다. 여기서 가장 화려한 숫자는 틀린 숫자였습니다.
일곱 번째 사례는 더 이상합니다. steel-dev/steel-mcp-server는 자체 package.json에 @steel-dev/mcp-server를 적어두었지만, npm은 404를 반환합니다. 애초에 공개되지 않았으므로 “아직 설치되고 있다”고 말할 수조차 없습니다.
숫자를 얻을 수 없으면, 없다고 적었습니다. Go, JVM, .NET, PHP 도구는 PyPI나 npm에 존재하지 않으므로 N/A (no PyPI/npm package)로 표기했습니다. 35개 중 17개는 GitHub Releases를 전혀 내지 않았습니다. 이것도 누락이 아니라 none으로 기록했습니다.
이 필드들은 일부러 하나의 “건강 점수”로 뭉개지 않았습니다. 오래된 기본 브랜치, 최근의 보조 브랜치, 없는 GitHub Release, 오래된 레지스트리 아티팩트는 각각 다른 질문에 답합니다. 세부 증거는 35행 데이터셋, 저장소 입력값, 가공된 레코드에 함께 있습니다. 이들은 프로젝트가 살아 있는지 여부를 판정하는 4표가 아니라, 다음 점검을 어디서 시작할지 정하는 트리아지 신호로 읽어야 합니다.
먼저, 샘플링의 한계부터
이 목록은 제가 “명성이 남아 있는 채로 사실상 멈춰 있는” 것으로 의심한 도구들을 손으로 모은 것입니다. 스크래핑 생태계를 대표하는 무작위 표본이 아닙니다. 따라서 “35개 중 31개가 오래됐다”는 생태계 전체 비율이 아니라, 제가 표본을 얼마나 잘 골랐는지에 가까운 수치입니다. 흥미로운 결과는 단순한 오래됨 개수가 아닙니다. 이런 현상을 겨냥해 고른 표본에서도, 제가 시험한 특정 메커니즘이 설명하는 경우는 소수였고, 확실히 입증되는 경우는 그보다 더 적었다는 점입니다.
착시는 실제였고, 가장 극단적인 사례도 확인됐다
sjdirect/abot은 2,308스타를 가진 .NET 크롤러입니다. GitHub는 2026-07-17에 푸시가 있었다고 보고했는데, 이는 기준일보다 10일 전입니다. 하지만 기본 브랜치는 마지막으로 건드려진 시점이 2021-08-09였습니다.
즉, 1,802일 차이입니다. 5년입니다. 헤더에는 “지난주”라고 보입니다.
35개 중 14개가 180일이 넘는 차이를 보였습니다.
| 저장소 | 차이(일) | 기본 브랜치 마지막 변경 | pushed_at |
|---|---|---|---|
sjdirect/abot | 1,802 | 2021-08-09 | 2026-07-17 |
dragnet-org/dragnet | 1,520 | 2021-05-09 | 2025-07-08 |
paquettg/php-html-parser | 1,376 | 2020-11-01 | 2024-08-09 |
seomoz/simhash-py | 1,159 | 2020-03-12 | 2023-05-15 |
internetarchive/wayback | 1,039 | 2021-04-27 | 2024-03-01 |
Rhizome-Conifer/conifer | 1,013 | 2023-10-12 | 2026-07-22 |
kohlschutter/boilerpipe | 856 | 2015-08-30 | 2018-01-03 |
scrapinghub/splash | 819 | 2022-05-05 | 2024-08-02 |
tomnomnom/waybackurls | 756 | 2022-04-05 | 2024-05-01 |
geziyor/geziyor | 689 | 2024-08-12 | 2026-07-02 |
crawlab-team/crawlab | 488 | 2024-10-09 | 2026-02-10 |
ArchiveTeam/wpull | 468 | 2023-01-16 | 2024-04-29 |
yasserg/crawler4j | 396 | 2020-10-03 | 2021-11-04 |
apache/any23 | 381 | 2022-06-03 | 2023-06-20 |
14개 중 14개가 아니라, 35개 중 14개입니다. 실제로 존재하고, 알아둘 가치도 있지만, 처음부터 그 현상을 포함하도록 고른 표본에서는 소수였습니다.
봇은 3개 저장소에서 확인됐고, 필터링 후엔 2개가 남았다
이런 이야기는 늘 dependabot을 떠올리게 합니다. 그래서 각 문제 저장소의 activity feed를 가져와, 마지막 기본 브랜치 커밋 이후에 푸시된 ref를 전부 분류했습니다. “이후”가 중요합니다. 마지막 커밋보다 앞선 이벤트는 차이를 키운 원인과 무관하고, 전체 피드를 그냥 세면 질문 자체가 달라지기 때문입니다.
커밋 이후 기준으로 봤을 때, 봇이 원인인 사례는 3개가 확인됐습니다. scrapinghub/splash(post-commit 이벤트 4개 중 4개가 dependabot/pip/*), geziyor/geziyor(5개 중 5개가 dependabot/go_modules/*), apache/any23(16개 중 16개가 dependabot/maven/*). 이 셋 중 any23는 공식적으로 아카이브 상태이므로 필터된 집합에는 들어가지 않습니다. 그래서 다른 조건도 모두 만족하는 확인 사례는 2개만 남습니다.
명백히 틀린 경우는 2개였고, 둘 다 봇 이야기보다 더 흥미롭습니다.
dragnet-org/dragnet의 1,520일 차이는 mp/py3.10이라는 브랜치를 사람이 푸시해서 생겼습니다. 병합되지 않은 Python 3.10 포팅 작업이었습니다. 누군가 살려보려다 멈춘 것이죠. 이것은 자동화된 잡음이 타임스탬프를 부풀린 것이 아니라, 실패한 복구 시도의 생생한 기록입니다. 오히려 데이터셋 전체에서 가장 유용한 신호라고도 할 수 있고, “dependabot이 원인”이라는 설명은 이 사실을 지워버립니다.
혼합된 사례이면서 둘 중 더 큰 경우는 2개였습니다. crawlab-team/crawlab은 12,250스타를 가진, 이 표본에서 두 번째로 스타가 많은 저장소입니다. main 기준으로는 488일 차이가 납니다. activity feed에는 dependabot 브랜치도 있고, 사람이 develop과 test로 푼 24개의 post-commit 푸시도 있습니다. 헤더만 보면 2026년 2월이라 건강해 보이고, main만 보면 2024년 10월에 멈춘 것처럼 보입니다. 둘 다 틀렸습니다. 개발은 기본 브랜치 밖으로 이동했을 뿐입니다. 이런 상황은 프로젝트에서 종종 일어나지만, GitHub 요약 화면은 그걸 표현하지 못합니다. sjdirect/abot도 또 다른 혼합 사례입니다. 헤더의 pushed_at을 만든 푸시는 실제로 dependabot이었지만, 2024년에 사람이 upgrade1을 푸시했기 때문에 나중에 필터된 집합에서 빠집니다.
Rhizome-Conifer/conifer는 애매한 사례였고, 저도 처음엔 잘못 읽었습니다. 기본 브랜치는 master가 아니라 main이며, main은 2023-10-12 이후로 멈춰 있습니다. activity feed에서 main 관련 이벤트는 2025년 1월의 브랜치 생성 하나뿐인데, 이는 브랜치 이름 변경과 잘 맞습니다. 한편 한 계정이 2026-07-22, 기준일보다 5일 전에 conifer-twilight와 twilight/read-only에 푸시를 했습니다. 분명한 사람의 활동이지만, “활발히 개발 중”이라고 보기엔 근거가 부족합니다. 단 한 명이 read-only라는 이름의 브랜치들에 작업한 것만으로도, 계속 개발 중이라기보다 관리된 종료에 더 가깝다고 볼 수 있습니다. 말할 수 있는 것은 더 좁지만 여전히 중요합니다. 이 1,013일 차이는 봇 잡음이 아니며, 그렇다고 곧바로 폐기 증거도 아닙니다.
원인을 알 수 없는 경우는 7개였습니다. php-html-parser, simhash-py, internetarchive/wayback, boilerpipe, waybackurls, wpull, crawler4j는 모두 검증된 차이를 보였지만 activity feed는 비어 있었습니다.
가장 그럴듯한 설명은 보존 기간입니다. GitHub activity feed는 무한정 과거까지 돌아가지 않으니까요. 하지만 캐시는 대부분의 경우 이를 반박합니다. 이 123개 응답 가운데 가장 오래된 이벤트는 2023-03-10이고, 이 7개 중 5개는 pushed_at이 그 범위 안에 충분히 들어옵니다. php-html-parser는 2024-08-09, wpull은 2024-04-29, waybackurls는 2024-05-01, internetarchive/wayback은 2024-03-01, simhash-py는 2023-05-15입니다. 이 시점을 움직인 무언가가 피드에 나왔어야 하는데 보이지 않았습니다. 보존 기간으로 설명되는 건 boilerpipe(2018)와 crawler4j(2021)뿐입니다.
따라서 정직한 결론은 더 얇습니다. 7개 저장소 모두 차이는 사실로 확인됐지만, 그 원인은 확정되지 않았습니다. 엔드포인트는 아무것도 반환하지 않았고, 그중 5개는 왜 그런지 말할 수 없습니다. “dependabot이 원인”은 이 7개 모두에 대해 추정일 뿐입니다.
14개 문제 저장소를 집계하면 다음과 같습니다.
부풀려진 pushed_at의 원인 | 저장소 수 | 해당 저장소와 근거 |
|---|---|---|
| 봇이 원인으로 확인됨 | 3 | scrapinghub/splash(post-commit 4개 중 4개가 dependabot/pip/*), geziyor/geziyor(5개 중 5개가 dependabot/go_modules/*), apache/any23(16개 중 16개가 dependabot/maven/*) — any23는 아카이브 상태라, 다른 조건까지 모두 만족하는 것은 2개만 남음 |
| 봇과 사람의 활동이 섞임 | 2 | crawlab-team/crawlab(dependabot 브랜치 + 사람이 develop과 test로 푼 24개의 post-commit 푸시), sjdirect/abot(헤드라인 pushed_at을 만든 푸시는 실제로 dependabot이었지만, 2024년에 사람이 upgrade1을 푸시함) |
| 완전히 틀린 경우 — 사람 작업뿐, 봇 브랜치 없음 | 2 | dragnet-org/dragnet(post-commit 이벤트 3개, 봇 브랜치 0개) — 사람이 mp/py3.10을 푸시한 것. Rhizome-Conifer/conifer(post-commit 이벤트 30개, 봇 브랜치 0개) — 한 계정이 2026-07-22에 conifer-twilight와 twilight/read-only로 푸시함. 위에서 말했듯 conifer가 폐기됐는지는 여전히 애매하지만, 어떤 봇도 pushed_at을 부풀린 건 아니라는 점은 분명함 |
| 원인 미확정 — activity feed 비어 있음 | 7 | php-html-parser, simhash-py, internetarchive/wayback, boilerpipe, waybackurls, wpull, crawler4j |
합계는 14입니다. 이 표는 pushed_at을 움직인 것이 무엇인지만 분류할 뿐, 프로젝트가 버려졌는지까지 독립적으로 증명하지는 않습니다.
전체 필터를 통과한 것은 무엇이며, “통과”가 뜻하는 것
원래 주장에는 네 가지가 동시에 필요합니다. 1년 이상 오래됐고, pushed_at은 180일 이상 부풀려졌으며, 아카이브 상태가 아니고, 그 부풀림이 사람 작업 때문이라는 증거도 없어야 합니다. 35개 후보 중 9개가 이 네 조건을 모두 통과했습니다. 아래 표는 그 9개와, 특히 중요한 제외 사례 2개를 함께 보여줍니다.
| 저장소 | 네 조건 모두 충족? | 봇이 부풀렸다는 긍정적 증거 |
|---|---|---|
splash | 예 | 예 — post-commit 이벤트 4개 중 4개가 dependabot/pip/* |
waybackurls | 예 | 어느 방향으로도 증거 없음 |
crawler4j | 예 | 어느 방향으로도 증거 없음 |
geziyor | 예 | 예 — 5개 중 5개가 dependabot/go_modules/* |
php-html-parser | 예 | 어느 방향으로도 증거 없음 |
boilerpipe | 예 | 어느 방향으로도 증거 없음 |
wpull | 예 | 어느 방향으로도 증거 없음 |
internetarchive/wayback | 예 | 어느 방향으로도 증거 없음 |
simhash-py | 예 | 어느 방향으로도 증거 없음 |
any23 | 아니오 — 아카이브됨 | 예 — 16개 중 16개가 dependabot/maven/*, 이번 점검 전체에서 가장 강한 확인 사례 |
abot | 아니오 — 기록에 사람 푸시(upgrade1, 2024)가 있음 | 혼합 — 헤드라인 pushed_at을 만든 푸시는 실제로 dependabot이었음 |
여기서 숫자 하나는 필터가 담지 못하는 단서를 필요로 합니다. 이 9개 중 봇이 실제로 부풀렸다는 긍정적 증거가 있는 것은 splash와 geziyor 둘뿐입니다. 나머지 7개는 어느 쪽 증거도 없어 네 번째 조건을 통과한 사례입니다. 통과한 사례이지, 확인된 사례는 아닙니다. 그리고 이번 점검에서 가장 강한 확인인 any23(dependabot 이벤트 16/16)은 저장소가 아카이브 상태라 제외되었습니다.
또한 1,802일 사례인 abot은 이 9개 안에 없습니다. 기록에 사람의 푸시가 있기 때문에 네 번째 조건을 충족하지 못했습니다. 즉, 데이터셋에서 가장 극적인 착시는 그 현상을 보여주는 메커니즘의 순수한 사례가 아닙니다.
35개 중 21개는 GitHub가 오래됨을 그대로 보여줬다
제가 세운 가설에 가장 큰 타격을 준 발견은 이것이었습니다. 14개 저장소는 차이가 정확히 0이었고, 7개는 180일 미만이었습니다. 35개 후보 중 21개는 pushed_at이 곧 마지막 기본 브랜치 커밋이었습니다. GitHub가 뭔가를 숨긴 건 아닙니다.
표본에서 가장 죽어 보이는 것들도 포함하면 이렇습니다.
| 저장소 | 스타 수 | 오래된 정도(일) | 차이 |
|---|---|---|---|
Janpot/microdata-node | 57 | 1,866 | 0 |
1e0ng/simhash | 1,037 | 1,606 | 21 |
ekzhu/SetSimilaritySearch | 603 | 1,384 | 0 |
GerbenJavado/LinkFinder | 4,431 | 834 | 0 |
hakluke/hakrawler | 5,099 | 582 | 0 |
lavague-ai/LaVague | 6,388 | 551 | 0 |
my8100/scrapydweb | 3,411 | 522 | 0 |
getomni-ai/zerox | 12,258 | 432 | 0 |
scrapinghub/frontera | 1,332 | 415 | 0 |
BuilderIO/gpt-crawler | 22,374 | 384 | 0 |
BuilderIO/gpt-crawler는 스타가 22,374개이고, 헤더도 2025-07-07 이후 같은 말을 계속하고 있습니다. 숨겨진 건 없고, 설치량은 계속 유지되고 있습니다.
그래서 결론은 더 좁아집니다. GitHub는 일부 사례에서만 오래됨을 가리고 있으며, 대부분의 경우에는 그것을 명확히 보여주지만 설치는 계속됩니다. 왜 계속되는지는 이 데이터로는 답할 수 없습니다. 여기의 수치는 사용자가 아니라 설치량을 세기 때문입니다. 하지만 UI를 바꿔도 더 큰 쪽, 즉 두 번째 집단은 해결되지 않습니다.
저장소 활동과 공개 아티팩트는 서로 어긋날 수 있다
데이터셋에서 가장 인상적인 한 행은 프레임 자체를 무너뜨립니다.
codelucas/newspaper는 스타가 15,126개이고 활성 상태입니다. 마지막 기본 브랜치 커밋은 2026-07-21이며, 기준일인 2026-07-27보다 며칠 전입니다. 게다가 작성자도 유지관리자였습니다. 저장소 수준의 검사는 모두 통과합니다.
하지만 모두가 설치하는 패키지는 newspaper3k 0.2.8이며, 2018-09-28에 배포됐습니다. 그것도 2,858일 전입니다. 그런데 월 813,513회 다운로드됩니다.
기본 브랜치는 최신이지만, PyPI 아티팩트는 2018년 이후 한 번도 배포되지 않았습니다. 이것은 릴리스 간 격차를 보여줄 뿐, 왜 배포가 멈췄는지나 파이프라인이 깨졌는지는 설명하지 못합니다. 이런 위험은 저장소만 보는 점검으로는 놓치기 쉽습니다. pip install newspaper3k 뒤 실제로 실행되는 것은 레지스트리 아티팩트이기 때문입니다.
패키지 기준으로 보면 패턴은 곳곳에 있습니다. 저장소 연결이 검증된 17개 패키지 중 16개가 1년 넘게 새로 배포되지 않았고, 그 16개가 전체 230만 건 중 약 228만 건의 월간 설치를 차지합니다.
| 패키지 | 월간 설치 수 | 마지막 배포 | 패키지 경과일 |
|---|---|---|---|
newspaper3k | 813,513 | 2018-09-28 | 2,858 |
tls-client | 790,305 | 2024-02-02 | 905 |
simhash | 317,615 | 2022-03-03 | 1,606 |
microdata-node | 204,025 | 2020-05-11 | 2,267 |
@modelcontextprotocol/server-puppeteer | 127,232 | 2025-05-12 | 440 |
extract-thinker | 10,927 | 2025-06-09 | 412 |
SetSimilaritySearch | 7,984 | 2022-10-11 | 1,384 |
frontera | 4,709 | 2019-04-05 | 2,669 |
zerox | 3,303 | 2025-05-20 | 432 |
scrapydweb | 1,163 | 2025-02-16 | 525 |
lavague | 606 | 2024-08-05 | 720 |
splash | 333 | 2020-06-16 | 2,231 |
dragnet | 213 | 2019-04-16 | 2,658 |
@builder.io/gpt-crawler | 137 | 2025-01-23 | 549 |
lmnr-index | 120 | 2025-06-05 | 416 |
simhash-py | 113 | 2017-03-22 | 3,413 |
tls-client는 따로 볼 만합니다. 저장소는 905일째 멈춰 있는데도 월 790,305회 설치됩니다. 그리고 이 분야에서는 최신성을 유지하는 것이 거의 전부입니다. 브라우저의 TLS 동작은 계속 바뀌고, 이를 따라가지 못한 라이브러리는 2024년 초의 가정 위에서 돌아가게 됩니다.
이 표에는 두 가지 주의점이 있습니다. 레지스트리 다운로드 수에는 CI 실행과 미러가 포함되고 중복 제거도 되지 않으므로, 사람 수가 아니라 설치량을 측정합니다. 또한 집계 창의 종료일도 서로 같지 않습니다. npm은 2026-07-24를 기준으로 하고, pypistats는 조회 시점에 상대적이기 때문입니다. 그래서 전체 합계는 약간 어긋난 월들의 합이며, 숫자 자릿수까지 딱 맞는 값으로 읽어서는 안 됩니다. “약 228만” 정도로 보는 것이 맞습니다.
알아둘 만한 이름 충돌
internetarchive/wayback은 죽은 Java OpenWayback으로, 1,916일째 멈춰 있습니다. 반면 PyPI의 wayback은 완전히 다른 프로젝트인 edgi-govdata-archiving/wayback이며, 기준일 5주 전인 2026-06-19에 0.5.1을 배포한 건강한 프로젝트입니다. 이름은 같지만 상태는 정반대고, 서로 관련도 없습니다. 이것은 거부된 6개 매핑 중 하나였고, 실제 사용자에게 가장 위험한 경우이기도 합니다. 이름을 검색하면 둘 다 나오지만, 어느 쪽인지 페이지 어디에도 분명히 적혀 있지 않습니다.
아카이브됐고 deprecated됐지만, 그래도 월 127,232회 설치된다
표본의 6개 저장소에는 archived: true가 붙어 있고, GitHub는 이를 전체 폭 배너로 보여줍니다. 처음엔 “크게 경고해도 사람들은 무시한다”는 증거라고 생각했습니다. 하지만 캐시는 이 이야기보다 더 나쁩니다.
공식 참고 문서: npm download-count API documentation.
공식 참고 문서: npm deprecation documentation.
@modelcontextprotocol/server-puppeteer는 modelcontextprotocol/servers-archived에서 월 127,232회 설치됩니다. 그런데 npm의 repository 필드는 **null**입니다. 패키지 페이지에서 저장소로 돌아가는 링크가 아예 없으니, 배너를 “건너뛴” 설치자라는 말도 성립하지 않습니다. 이 패키지를 받는 대부분의 사람은 애초에 그 저장소에 도달하는 경로가 없었습니다.
npm이 실제로 제공하는 것은 deprecation 경고입니다. 이 패키지의 최신 버전에는 deprecated: "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."가 들어 있고, npm은 이를 설치 시 터미널에 출력합니다. 즉, 경고는 사용자가 있는 그 자리에서 전달됩니다. 그럼에도 월 127,232회의 설치가 계속됩니다. 배너보다 더 강한 발견이며, 시사점도 다릅니다. 신호가 없는 게 아니라, 설치 로그라는 벽 속에서 아무도 읽도록 강제되지 않은 채 도착하고 있을 뿐입니다.
browserbase/mcp-server-browserbase는 깔끔한 종료가 어떤 모습인지 보여줍니다. 마지막 기본 브랜치 커밋인 2026-07-20의 메시지는 문자 그대로 **“Mark repository as archived and unmaintained (#198)”**였습니다. 유지관리자들은 이를 직접 알리고 날짜도 남겼으며 API에도 표시했습니다. 다만 20,389회의 설치 수는 신중하게 읽어야 합니다. npm 집계 창이 2026-06-25부터 2026-07-24까지이므로, 30일 중 26일은 아카이브 커밋 이전입니다. 이 수치는 주로 공지 이전 수요를 반영할 뿐, 공지 이후의 반응을 말해주지는 않습니다. 다음 한 달쯤 뒤에 다시 봐야 비로소 무언가를 말할 수 있습니다.
스타 57개, 월 204,025회 설치
Janpot/microdata-node는 스타가 57개뿐이지만, 2020-05-11에 배포된 릴리스에서 월 204,025회 다운로드됩니다.
스타 57개짜리 microdata-node는 레지스트리 규모에 비해 저장소 가시성이 매우 낮습니다. 설치 대비 스타 비율 3,579:1은 간접 의존성, CI 반복 실행, 미러, 또는 직접적인 머신 소비와 잘 맞습니다. 이번 점검은 의존성 그래프를 수집하지 않았기 때문에 그중 무엇인지 고를 수 없습니다.
이 행은 간접 노출을 점검하라는 신호이지만, 진짜 전이적 사용을 입증하려면 reverse-dependency나 lockfile 근거가 필요합니다. 이번 점검에는 그 증거가 포함되지 않았습니다.
오래된 것과 깨진 것은 다르다
정직한 점검이라면 이것을 분명히 말해야 합니다. 여기서는 아무것도 실제 사이트에서 동작하는지 테스트하지 않았습니다. 무엇이 누구를 “죽었다”고 판정하는 게 아니라, 누가 아직 관리되고 있는지를 보는 것입니다.
일부는 그냥 끝난 프로젝트일 뿐입니다. SetSimilaritySearch는 집합 유사도 알고리즘을 구현하며, 이런 건 낡아도 썩지 않습니다. simhash는 2007년 논문입니다. boilerpipe의 콘텐츠 추출 알고리즘은 2026년에도 2015년과 똑같이 동작합니다. 현대 페이지에서 정확도가 어떻든, 코드가 당신 밑에서 조용히 변질되는 일은 없습니다.
썩는 것은 반대편이 계속 움직이는 것들입니다.
- 브라우저 자동화 — Chrome이 새 버전으로 갈 때마다 깨질 수 있습니다.
- 브라우저를 모방하는 HTTP 클라이언트 — 브라우저가 바뀌면 고정된 라이브러리는 더 이상 맞지 않습니다.
tls-client가 여기에 해당합니다. - 사이트별 파서와 사이트별 추출 규칙 — 사이트가 리디자인되면 그건 곧 버그입니다.
- 서드파티 API를 감싼 모든 것 — 공급사가 스키마를 바꾸면 그 사실을 운영 중에 알게 됩니다.
- LLM을 감싼 모든 것 — 모델 폐기 속도는 그 어떤 것보다 빠릅니다.
따라서 “1,606일 오래됐다”는 어떤 범주에는 빨간 경보이고, 해시 유틸리티에는 거의 무의미합니다. 여기서는 어떤 깨짐도 테스트하지 않았고 그에 대한 주장도 하지 않습니다. 하지만 자신의 의존성을 이 범주별로 정리하는 일은 공짜이고, 단순한 오래됨 숫자보다 훨씬 도움이 됩니다.
실제로 질문에 답하는 4가지 점검

그중 어느 것도 저장소 헤더가 아닙니다.
| # | 점검 항목 | 어디서 읽나 | 무엇을 잡아내나 |
|---|---|---|---|
| 1 | 기본 브랜치의 마지막 커밋 | GET /repos/{owner}/{repo}/commits?sha={default_branch}&per_page=1 | 화면에 보이지 않는 숫자 |
| 2 | 아티팩트의 마지막 배포 시점 | pypi.org/pypi/{pkg}/json 또는 registry.npmjs.org/{pkg} → 최신 버전과 업로드 날짜 | newspaper3k를 잡아내는 건 이것뿐이고, 1번으로는 절대 안 됩니다. npm의 deprecated 필드도 함께 읽으세요. @modelcontextprotocol/server-puppeteer가 자신을 알리는 방식입니다. |
| 3 | archived 플래그 | 저장소 응답의 한 필드. 명확하고 공짜입니다. | 다만 저장소에 도달할 수 있을 때만 도움이 됩니다. repository: null인 패키지는 그 길을 막습니다. |
| 4 | 1번과 2번의 차이 | — (위 둘로부터 계산) | 최신 커밋과 3년 된 릴리스를 가진 저장소는 그냥 차가운 저장소와는 다른 실패입니다. 유지관리자는 존재하지만 배포를 멈춘 것입니다. 이것은 눈을 뜨고 결정해야 할 사안이지, 그 자체로 경고표시는 아닙니다. 같은 논리는 crawlab에도 역으로 적용됩니다. 결론을 내리기 전에 작업이 기본 브랜치가 아닌 곳으로 이동했는지 확인하세요. |
1, 2, 3번 점검은 빠른 트리아지로 돌리면 됩니다. 그다음에는 저장소 메타데이터가 없거나, 패키지 매핑이 애매하거나, 활동이 기본 브랜치 밖으로 이동했거나, 레지스트리 아티팩트가 저장소와 어긋날 때 더 깊게 보십시오. 인증되지 않은 GitHub 제한과 레지스트리 지연을 생각하면 1초 약속은 적절하지 않습니다.
점검 결과 차가운 도구가 하나라도 나오고, 그것이 자주 바뀌는 범주라면 이 영역의 유지보수 대안은 이미 우리 테스트에도 정리되어 있습니다. dragnet와 boilerpipe가 하던 콘텐츠 추출에는 Trafilatura, 크롤링 프레임워크에는 Scrapy나 Crawlee, LLM 중심 추출에는 Crawl4AI와 Firecrawl, 그리고 복원력이 중요할 때는 Scrapling을 보세요. 더 넓은 범위는 우리의 오픈소스 스크래퍼 피라미드에 정리되어 있습니다. 이들은 모두 1차 리뷰입니다. 우리 추천을 포함해 어떤 권고도 믿기 전에, 직접 4가지 점검을 돌려보세요.
이 데이터의 한계
- 샘플 선택: 버려졌을 가능성이 의심되는 도구를 손으로 고른 목록입니다. 전체 생태계 비율로 읽을 수 없습니다.
- 깨짐 테스트 없음: 35개 도구 중 어느 것도 실제 사이트에서 실행하지 않았습니다. 오래됨은 유지보수 신호이지 기능 판정이 아닙니다.
- 다운로드 수에는 기계가 포함됨: CI, 미러, 중복 제거 없음, 종료일도 서로 다름. 사용자 수가 아니라 설치량입니다. 그리고 의사결정도 아닙니다.
- 원인 불명 7건은 여전히 불명: activity feed가 비어 있었고, 그중 5개는 보존 기간으로도 설명되지 않았습니다. 빈칸을 인기 있는 추측으로 채우는 것보다 그대로 두는 편이 낫습니다.
staleness_days는 커밋 날짜를 사용: 히스토리를 다시 쓰거나 과거 날짜로 바꾸면 왜곡될 수 있습니다. 그런 현상은 발견되지 않았지만, 그렇다고 아예 없었다는 뜻은 아닙니다.- 기준일은 하나뿐: 2026-07-27입니다. 이 글을 읽는 시점에는 몇몇 저장소가 이미 움직였을 수 있습니다. 특히
newspaper는 꾸준히 커밋됩니다. 제 날짜를 인용하지 말고, 4가지 점검을 다시 돌리세요.
관리형 서비스가 이 그림을 바꾸는 지점
여기 있는 모든 점검이 필요한 이유는, 셀프 호스팅 라이브러리를 쓰는 순간 오래됨을 당신이 직접 떠안기 때문입니다. 고정된 HTTP 클라이언트가 최신 브라우저처럼 동작하지 않게 되면, 그 사고는 언제 터지든 결국 당신의 일이 됩니다.
작성자 주: Thunderbit는 우리가 제공하는 관리형 스크래핑 제품입니다. 관리형 서비스는 일부 유지보수 책임을 공급사로 옮기지만, 커버리지, 응답 시간, 락인, 공급사 지속성도 리스크 모델의 일부가 됩니다. 이번 저장소 점검에서 Thunderbit은 평가하지 않았습니다.
정직한 트레이드오프는 이렇습니다. 소스 코드를 직접 보고, 버전을 고정하고, 새벽 2시에 스스로 고칠 수 있는 능력은 포기하게 됩니다. 하지만 이미 스크래퍼를 운영 중인 팀이라면 오픈소스 경로가 종종 더 맞는 선택입니다. 그리고 그 선택을 가정이 아니라 결정으로 바꾸는 방법이 바로 이 4가지 점검입니다.
웹 데이터 추출을 위해 Thunderbit 사용해 보기
짧은 요약
GitHub가 버려진 저장소를 숨긴다는 걸 증명하려고 목록을 만들었습니다. 착시는 35개 중 14개에서 실제였고, 한 사례는 특히 극적입니다. sjdirect/abot은 2021년부터 멈춘 기본 브랜치에 대해 지난주 푸시가 있었다고 보이며, 차이는 1,802일입니다.
하지만 메커니즘은 이야기보다 좁습니다. 9개 저장소가 주장을 위해 필요한 네 조건을 모두 통과했지만, 그중 2개만 — splash와 geziyor — 봇이 부풀렸다는 긍정적 증거가 있었습니다. 나머지는 증거가 없을 뿐입니다. 두 개의 문제 저장소는 사람이 프로젝트를 살리려다 실패한 경우입니다. 하나인 crawlab은 스타가 12,250개이고, 그냥 개발을 develop으로 옮겼습니다. 7개는 activity feed가 비어 있었고, 그중 5개는 보존 기간으로도 설명되지 않아서 원인이 추정이 아니라 미확정입니다. 그리고 35개 중 21개는 GitHub가 오래됨을 정확히 보여줬습니다.
데이터셋에서 가장 나쁜 사례는 저장소 수준 점검을 모두 통과합니다. codelucas/newspaper는 2026-07-21에 커밋됐고, newspaper3k는 2018-09-28 이후 마지막 배포 상태였지만 그 달에만 813,513회 설치됐습니다. 표본 전체를 보면 1년 넘게 새 배포가 없는 16개 패키지가 약 228만 회의 월간 설치를 차지합니다.
초기 트리아지로는 기본 브랜치 커밋 날짜, 레지스트리 릴리스 날짜, archived 플래그, npm deprecation 필드를 확인하세요. 그다음 패키지와 저장소의 연결 여부를 검증하고, 기본 브랜치 밖으로 개발이 옮겨갔는지 확인한 뒤 결론을 내리십시오.
웹 데이터 추출을 위해 Thunderbit 사용해 보기 Get Started Free
FAQ
pushed_at은 무엇이고, 왜 “마지막 업데이트”를 뜻하지 않나요?
pushed_at은 GitHub API에서 저장소 페이지의 활동 타임스탬프로 쓰이는 필드입니다. 어떤 브랜치에든 푸시가 들어오면 갱신됩니다. 반면 최신 기본 브랜치 커밋은 저장소 관리 상태를 보여주는 한 신호일 뿐이고, 패키지 매니저는 보통 레지스트리 아티팩트나 해석된 모듈 버전을 설치합니다. 이번 점검에서는 35개 중 14개 저장소가 이 두 GitHub 날짜 사이에 180일 이상의 차이를 보였습니다.
항상 dependabot이 그 타임스탬프를 부풀리나요?
아니요. 오히려 그것이 민담에서 가장 약한 부분이었습니다. 마지막 기본 브랜치 커밋 이후에 발생한 이벤트만 세면, 봇이 원인인 것은 14개 중 3개로 확인됩니다(splash 4/4, geziyor 5/5, any23 16/16). 2개는 완전히 틀렸습니다. dragnet의 차이는 사람이 병합되지 않은 Python 3.10 포팅을 푸시해서 생겼습니다. 또 2개는 혼합 사례입니다. 그중 crawlab은 사람이 develop과 test로 24번 푸시한 반면 main은 그대로였습니다. 그리고 7개는 activity feed가 아예 비어 있어 원인을 알 수 없었고, 그중 2개만 보존 기간으로 설명됩니다.
오래된 저장소면 도구가 깨졌다는 뜻인가요?
이 증거만으로는 그렇지 않습니다. 여기서는 어떤 도구도 실제 사이트에서 실행하지 않았습니다. 오래됨이 중요한 정도는 대상이 얼마나 빨리 변하느냐에 따라 다릅니다. 브라우저 자동화, 브라우저 동작을 모방하는 HTTP 클라이언트, 사이트별 파서, API/LLM 래퍼는 빨리 낡지만, SetSimilaritySearch나 simhash 같은 알고리즘 라이브러리는 몇 년이 지나도 멀쩡할 수 있습니다. 이 샘플에서 가장 극적인 사례는 tls-client로, 905일째 멈춘 저장소에서 월 790,305회 설치됩니다.
저장소는 활성인데 패키지는 왜 죽어 있을 수 있나요?
그게 바로 codelucas/newspaper이고, 이번 점검에서 가장 중요한 발견입니다. 기본 브랜치는 기준일 며칠 전인 2026-07-21에 커밋됐지만, PyPI의 newspaper3k는 2018-09-28의 0.2.8이 마지막 배포였고, 지금도 월 813,513회 다운로드됩니다. 저장소 수준 점검은 모두 통과하지만, 실제 설치하는 아티팩트는 8년 전 것입니다. 커밋 로그와는 별도로 레지스트리의 최신 배포일을 꼭 확인하세요.
아카이브 저장소면 이런 문제를 해결할 수 있나요? GitHub에 배너가 있잖아요.
그렇지 않습니다. @modelcontextprotocol/server-puppeteer가 그 이유를 보여줍니다. npm의 repository 필드는 null이라 패키지에서 아카이브 저장소로 연결되는 링크가 없고, 그래서 사용자가 배너를 보지도 못합니다. npm이 대신 제공하는 것은 패키지의 deprecated 문자열 — “Package no longer supported” — 이며, 이는 설치 시 출력됩니다. 그런데도 월 127,232회 설치됩니다. browserbase/mcp-server-browserbase는 마지막 커밋에서 종료를 제대로 알렸고, 20,389회의 설치 중 대부분은 그 커밋 이전에 발생했습니다. 따라서 이 숫자만으로는 어느 쪽도 단정하기 어렵습니다.
내 의존성을 빠르게 확인하려면 어떻게 하나요?
기본 브랜치 커밋 날짜, 레지스트리 버전/업로드 날짜, npm deprecation 필드, 저장소 archived 플래그부터 확인하세요. 그다음 패키지-저장소 매핑을 검증하고, 활동이 기본 브랜치 밖으로 이동했는지 살펴보고, 노출이 전이적인지 판단하려면 dependency graph나 lockfile을 확인하세요. 관련 없는 Java와 PyPI의 wayback 프로젝트처럼 이름이 겹치는 사례가 있으므로, 이런 추가 점검은 꼭 필요합니다.


