인스타그램 크롤링은 왜 175시간짜리 작업이었나?
수집 대상은 디자인 참고용으로 골라 둔 인스타그램 레퍼런스 계정 121곳입니다. 카드뉴스를 올리는 계정, 앱 화면 스크린샷을 올리는 계정, 영상 위주 계정이 섞여 있었습니다. 목적은 이 계정들이 어떤 문장과 어떤 장면 구성으로 게시물을 만드는지 한곳에 모아 분석하는 일이었고, 그러려면 본문 전문과 캐러셀(한 게시물에 여러 장을 넘겨 보는 형식)의 모든 장이 필요했습니다.
문제는 규모였습니다. 프로필에 표시된 게시물 수를 더하니 62,830건이었습니다. 게시물 한 건을 열고 캡처하는 데 10초가 든다고 잡으면 약 175시간입니다(추정: 건당 10초 가정). 시간만의 문제도 아니었습니다. 로그인한 개인 계정으로 게시물 조회를 수만 번 해야 하는 방식이라, 계정 자체에 부담을 주는 구조였습니다. 그래서 수집을 시작하기 전에 규칙 하나를 정했습니다 — 실측 소요가 7일을 넘으면 계획을 다시 판단받는다.

처음 잰 숫자: 34건 중 23건의 본문이 잘려 있었다
첫 계획은 가벼웠습니다. 영상 위주 계정을 뺀 101곳에서 계정당 최근 게시물 4개, 캐러셀은 앞의 3장, 본문은 400자까지만 모으기로 했습니다. 샘플로 흐름을 먼저 보자는 판단이었습니다.
시작한 지 4분 만에 숫자가 이상하다는 게 드러났습니다. 모은 34건 가운데 23건은 본문이 400자에서 잘려 있었고, 15건은 캐러셀 3장을 꽉 채운 상태였습니다. 3장을 꽉 채웠다는 말은 4장 이후가 있을 가능성이 높다는 뜻입니다. 분석에 쓸 재료가 절반 이상 중간에서 끊겨 있었던 셈입니다. 운영자가 "게시물 수집은 당연히 이미지와 본문 전체 아니냐"고 되물었고, 본문 전문과 캐러셀 10장으로 기준을 바꿔 다시 시작했습니다.
곧이어 두 번째 수정이 왔습니다. 계정당 최근 4건이 아니라 레퍼런스 계정 전부를 전수로 모으라는 지시였습니다. 대상은 121곳 전부가 됐고, 영상 계정 20곳은 본문과 표지 1장, 나머지는 본문 전문과 캐러셀 전 장을 받기로 했습니다. 수집 순서는 카드뉴스 → 스크린샷 → 혼합 → 영상으로 잡았고, 게시물이 6,495건인 스크린샷 계정 하나는 맨 뒤로 뺐습니다.
이 시점에서 잰 숫자를 정리하면 이렇습니다. 전체 대상 62,830건, 캡처 방식 예상 소요 약 175시간, 첫 샘플 34건 중 잘림 23건과 3장 꽉 참 15건. 대안으로 계정당 상한 200건(합계 17,344건)도 계산해 봤지만, 전수 지시와 맞지 않아 7일을 넘길 때만 다시 고르기로 하고 접어 두었습니다.
측정 방법도 이때 정했습니다. 잘림은 본문 길이가 정확히 400자에서 멈춘 건수로, 장 수 부족은 캐러셀이 상한(3장)을 꽉 채운 건수로 셌습니다. 둘 다 "상한에 닿았다"는 신호일 뿐 잘림을 직접 증명하지는 않지만, 34건 중 23건이 한 값에 몰렸다면 우연보다 상한 탓으로 읽는 편이 자연스럽습니다. 이 셈법은 나중에 판정 스크립트의 다섯 번째 항목으로 그대로 옮겨 갔고, 그 가정이 뒤에서 한 번 더 문제를 일으킵니다.

세운 가설: 게시물을 열어야 전문을 얻고, 크롬은 등록만 하면 지킬 수 있다
처음 가설은 두 개였습니다. 첫째, 본문 전문과 캐러셀 전 장을 얻으려면 게시물을 하나씩 열어야 한다. 프로필 격자 화면에는 썸네일만 보이기 때문에, 전문은 게시물 상세 화면에서만 나온다고 생각했습니다. 이 가설이 맞으면 175시간을 받아들이거나 계정당 상한을 두는 수밖에 없었습니다.
둘째 가설은 운영 쪽이었습니다. 수집에 쓰는 크롬은 인스타그램에 로그인한 전용 프로필로 띄우고, 파이썬 수집기가 크롬 원격 디버깅 포트(CDP, 크롬을 코드로 조작하는 통로)로 붙어 조작합니다. 같은 PC에는 AI 코딩 에이전트 작업 창이 여러 개 떠 있고, 이 작업 창들이 쓰다 남은 크롬을 치우는 정리 기능을 공유합니다. 우리는 수집용 크롬 포트 9226을 "쓰는 중" 목록에 등록해 두면 정리 기능이 건드리지 않을 거라고 봤습니다.
세 가설은 당시에는 모두 그럴듯했습니다. 첫 번째는 화면에 보이는 것만 믿은 가정이었고, 두 번째는 "목록에 적으면 지켜진다"는 관리 도구의 겉모습을 믿은 가정이었습니다. 세 번째는 한 번 통과한 검사 규칙이 수집 방식이 바뀐 뒤에도 같은 뜻이라고 본 가정이었습니다. 셋 다 확인해 보기 전에는 틀렸다는 신호가 없었습니다.
판정 쪽에도 가설이 하나 숨어 있었습니다. 수집 결과를 검사하는 스크립트의 다섯 번째 항목은 "본문 길이가 정확히 400자인 게시물이 0건이어야 한다"였습니다. 옛 수집 방식이 400자에서 잘랐으니, 400자짜리가 남아 있으면 잘림이 남은 거라고 본 규칙입니다. 이 가정이 새 방식에서도 성립한다고 믿었습니다.
가설이 틀린 지점: 응답 안에 이미 다 있었고, 크롬은 30분 만에 다시 꺼졌다
첫 가설은 30분 판별 안에 무너졌습니다. 프로필 격자를 스크롤하면 페이지가 다음 게시물 묶음을 받아 오는데, 이때 오는 응답(PolarisProfilePosts 계열 요청의 결과)에 본문 전문, 캐러셀 전 장, 이미지의 서명 주소가 전부 들어 있었습니다. 한 계정에서 대조해 보니 22건 중 22건이 일치했고 장 수도 맞았습니다. 오히려 캡처 방식이 못 보던 게 드러났습니다. 한 게시물의 최다 장 수가 15장이어서, 캐러셀 10장 상한을 뒀다면 그 계정에서만 20건이 잘렸을 겁니다.
둘째 가설은 운영 중에 두 번 틀렸습니다. 21:40에 수집용 크롬이 옆 작업 창의 정리 기능에 꺼졌습니다. 포트를 "쓰는 중" 목록에 등록하고 다시 띄웠지만, 넣은 지 30분 만에 목록 항목이 다른 작업 창의 기록으로 덮어써졌고 22:14에 크롬이 두 번째로 꺼졌습니다. 등록은 했는데 그 등록이 유지되지 않았던 겁니다. 20초마다 목록을 다시 써 넣는 보조 프로세스도 잠시 돌려 봤지만, 이건 증상을 덮는 쪽이지 원인을 없애는 쪽이 아니었습니다.
셋째 가설인 판정 규칙도 틀렸습니다. 새 방식으로 모은 데이터에서 400자짜리 게시물 8건이 나왔고, 검사 스크립트는 이를 실패로 표시했습니다. 열어 보니 8건 모두 원래 400자인 정상 글이었습니다. 응답 원문을 그대로 받는 방식에는 400자에서 자르는 경로가 애초에 없었습니다.

진짜 원인은 무엇이었나?
크롬이 꺼진 진짜 원인은 등록 여부가 아니라 포트 번호 자체였습니다. 정리 기능은 작업 창마다 나눠 주는 포트 대역을 관리하는데, 9226은 그 배정 대역 안에 있었습니다. 대역 안의 포트는 언젠가 다른 작업 창에 배정될 수 있는 자리라서, 목록에 한 번 적어 둬도 다른 작업 창이 자기 기록을 쓰는 순간 밀려납니다. 전용으로 지키려면 목록에 적는 게 아니라 대역 밖으로 나가야 했습니다. 이 사실은 "전용 포트는 배정 대역 밖에 있어야 한다"는 기존 회귀 테스트가 9226 등록을 실패로 잡으면서 확인했습니다.
21:58의 IndexError는 성격이 달랐습니다. 다시 띄운 크롬에서 수집기가 작업을 마친 탭을 닫았는데, 그게 마지막 탭이었습니다. 마지막 탭을 닫으면 크롬 창 자체가 사라지고, 다음 계정을 열려던 코드가 빈 탭 목록에서 첫 번째 탭을 찾다가 죽었습니다. 계정마다 새 탭을 여닫는 구조가 원인이었습니다.
동기화 중단은 경로 문제였습니다. 이 PC에는 여러 작업 창의 설정과 기록을 비공개 저장소로 복사하는 동기화 작업이 도는데, 복사 전에 비밀번호나 키 같은 비밀값이 섞였는지 검사합니다. 수집 원자료가 동기화 대상 폴더 안에 쌓이자, 수만 건의 남의 게시물 본문이 검사에 걸렸고 20:15부터 22:15까지 모든 작업 창의 동기화가 멈췄습니다. 수집기 한 대가 다른 모든 작업의 백업을 막은 셈입니다.
판정 오탐의 원인은 규칙이 잘림 자체가 아니라 옛 방식의 흔적을 재고 있었다는 점입니다. "400자짜리가 0건"은 옛 방식에서만 잘림의 신호였고, 새 방식에서는 그냥 우연히 400자인 글도 실패로 만드는 규칙이었습니다. 관련해서 스크롤 수집기가 일찍 멈추는 문제를 다룬 무한 스크롤 크롤러가 일찍 멈춘 이유도 같은 교훈을 남겼습니다 — 검사는 결과의 모양이 아니라 결함이 생기는 경로를 봐야 합니다.
네 원인에는 공통점이 있었습니다. 수집기 코드는 한 줄도 틀리지 않았는데, 수집기가 같은 PC의 다른 장치와 맞닿는 자리 — 포트 배정, 크롬 창 수명, 백업 경로, 검사 규칙 — 마다 서로 다른 가정을 하고 있었습니다. 정리 기능은 "대역 안의 포트는 언제든 회수해도 괜찮다"고 봤고, 수집기는 "내 크롬은 내가 끌 때까지 산다"고 봤습니다. 동기화는 "작업 폴더 안의 파일은 전부 우리 것"이라고 봤고, 판정기는 "수집 방식은 바뀌지 않는다"고 봤습니다. 그래서 고칠 곳도 수집기 안이 아니라 이 경계들이었습니다.

조치: 응답 가로채기, 전용 포트 9252, 동기화 제외, 급증 검사
수집 경로는 응답 가로채기로 바꿨습니다. 수집기는 프로필 격자를 스크롤만 하고, 페이지가 받는 게시물 응답을 기록합니다. 클릭 0회, 새로 만드는 요청 0건입니다. 이미지는 응답에 들어 있는 서명 주소로 WSL(윈도우 안의 리눅스 환경)에서 CDN에 직접 받습니다. 로그인 없이 받혔고, 8병렬로 초당 약 15장을 내려받았습니다(로그 기준 대략치).
실행 구조는 세 조각으로 나눴습니다. 스크롤만 하며 응답을 적는 수집 스크립트, 적어 둔 서명 주소로 이미지를 받는 다운로드 스크립트, 그리고 계정을 순서대로 넘기며 둘을 번갈아 부르는 연쇄 실행 스크립트입니다. 수집과 다운로드를 떼어 놓은 이유는 실패의 성격이 달라서입니다. 수집은 로그인한 크롬이 있어야 하고, 다운로드는 크롬 없이 네트워크만 있으면 됩니다. 하나로 묶어 두면 크롬이 꺼지는 순간 이미지 받기까지 같이 멈춥니다. 서명 주소가 로그인 없이 받힌다는 점도 처음에는 몰랐던 사실이라, 예전에 적어 둔 "로그인해야 받힌다"는 운영 메모를 이때 고쳤습니다.
크롬은 전용 포트 9252로 옮겼습니다. 포트 설정 파일에 인스타그램 전용 포트로 등록하고, 정리 기능의 두 단계와 작업 창 포트 배정에서 모두 뺐습니다. 프로필 폴더는 원래 쓰던 폴더를 그대로 뒀습니다. 크롬의 프로필 폴더 지정과 포트 번호는 서로 무관해서, 포트만 바꾸면 로그인을 다시 할 필요가 없었습니다. 옮긴 뒤 회귀 테스트는 9건 중 9건 통과했습니다. 이미 돌고 있던 연쇄 실행이 윈도우 쪽 중계 포트 10226을 코드에 박아 쓰고 있어서, 연쇄를 멈추는 대신 중계 대상만 10226 → 9252로 교체했습니다.
수집기는 탭 하나를 계정 내내 재사용하고, 마지막 탭이면 닫지 않게 고쳤습니다. 크롬 조작 도구도 프로필이 2개 이상 있는 폴더를 열 때 마지막으로 쓴 프로필을 여는 방식으로 맞췄습니다.
동기화는 수집 원자료 폴더 두 곳을 제외 목록에 넣었습니다. 예전에 대량 원본 텍스트를 모았을 때 쓴 관례와 같은 방식입니다. 22:40 회차 동기화가 커밋까지 끝나는 것으로 재개를 확인했습니다.
판정 5번은 "400자 0건"에서 "400자 급증 검사"로 바꿨습니다. 400자 게시물 수를 이웃 길이 구간의 평균과 비교합니다. 새 데이터는 400자 8건 대 이웃 평균 13.9건으로 비율 0.58이라 급증이 아닙니다. 옛 캡처 방식 초판은 44건 중 18건이 400자에 몰려 있어서, 새 규칙이 실제 잘림을 잡는지 확인하는 양성 대조로 썼습니다.

기각한 대안 네 가지는 왜 버렸나?
첫째, 크롬을 대역 밖으로 옮기지 않고 목록 등록만 유지하는 안. 이미 한 번 해 봤고, 넣은 지 30분 만에 항목이 덮어써져 크롬이 두 번째로 꺼졌습니다. 실패로 확인한 안이라 다시 쓸 이유가 없었습니다.
둘째, 20초마다 목록을 다시 적는 보조 프로세스를 상시로 두는 안. 잠시 보조책으로 돌렸지만, 전용 포트의 기준은 포트 설정 파일의 전용 포트 목록 한곳에 두기로 하고 이 프로세스는 퇴역시켰습니다. 기준이 두 곳에 있으면 언젠가 둘이 어긋납니다.
셋째, 포트를 대역 밖으로 옮기면서 새 프로필 폴더를 만드는 안. 폴더 이름과 포트 번호가 일치해 깔끔하지만, 인스타그램에 다시 로그인해야 했습니다. 사람 손이 한 번 들어가야 하는 안이라 기각했습니다.
넷째, 판정 5번을 그대로 두고 8건을 예외 목록으로 빼는 안. 지금은 8건이지만 수집이 늘면 예외도 따라 늘고, 결국 예외 목록이 판정을 대신하게 됩니다. 판정이 의미를 잃는 길이라 버렸습니다.
재측정 결과: 23:28 기준 게시물 22,973건, 다운로드 실패 0
시험 단계에서 4계정 375건을 78초에 모았습니다. 이 속도로 계산한 전수 소요가 하루 안쪽이어서, 처음 정한 "7일 초과 시 재판단" 조건에 걸리지 않았고 그대로 전수 수집에 들어갔습니다. 캡처 방식 추정 175시간과 비교하면 같은 일을 하루 안에 끝내는 경로입니다.
운영 조치를 넣은 뒤로는 끊김이 없었습니다. 22:02 이후 계정이 연속으로 끝까지 수집됐고, 23:28 기준 숫자는 이렇습니다. 끝까지 간 계정 121곳 중 55곳, 게시물 22,973건, 캐러셀 장 104,497장, 내려받은 이미지 51,531장, 다운로드 실패 0건. 수집은 백그라운드 연쇄 실행으로 계속 돌고 있었습니다.
측정은 두 곳에서 했습니다. 소요 시간과 사고 시각은 수집기와 동기화 로그에서, 건수와 장 수는 수집 결과를 검사하는 스크립트에서 셌습니다. 사고 전후를 같은 스크립트로 셌기 때문에 숫자를 나란히 놓고 비교할 수 있습니다.
사고 전후를 나눠 보면 차이가 분명합니다. 조치 전에는 20:15부터 22:15까지 두 시간 동안 동기화가 막혔고, 크롬이 21:40과 22:14 두 번 꺼졌으며, 21:58에는 수집기가 오류로 죽었습니다. 조치를 넣은 뒤 22:02부터 23:28까지는 같은 종류의 사고가 한 건도 나지 않았고, 22:40 회차 동기화도 정상으로 돌아왔습니다. 판정 5번은 새 데이터 8건을 정상으로, 옛 초판 18건을 잘림으로 가려내 음성과 양성을 모두 맞혔습니다.


남는 한계는 무엇인가?
급증 검사는 "잘림이 있으면 400자에 몰린다"는 가정 위에 서 있습니다. 다른 길이에서 자르는 결함이 생기면 이 검사는 못 잡습니다. 지금 경로는 응답 원문을 그대로 받으니 그런 결함 경로는 없다고 보지만, 이건 추정입니다(추정: 자르는 코드가 없다는 구조 근거만 있고 전수 대조는 안 함).
포트와 폴더 이름이 어긋난 것도 남은 비용입니다. 크롬은 9252 포트로 뜨는데 프로필 폴더 이름에는 9226이 붙어 있습니다. 사람이 나중에 보면 헷갈릴 수 있어 포트 설정 파일 주석과 운영 메모에 이유를 적어 두었습니다. 로그인을 한 번 아끼는 대신 이름의 일관성을 내준 선택입니다.
가장 무거운 한계는 이미 지나간 일입니다. 동기화 제외를 넣기 전 17:15 회차에 팔로우 목록과 프로필 원문이 비공개 저장소에 이미 커밋돼 있었습니다. 앞으로의 복사는 막았지만, 저장소 이력에서 지우는 일은 되돌릴 수 없는 작업이라 별도 판단으로 남겨 두었습니다. 수집기를 새로 돌릴 때는 원자료 폴더가 백업·동기화 경로 안에 있는지부터 확인하는 게 맞습니다.
수집 자체도 아직 끝나지 않았습니다. 23:28 시점에 121곳 중 55곳까지 갔고, 나머지 계정과 마지막 순서로 미룬 영상 계정 20곳은 연쇄 실행이 이어서 처리합니다. 전수가 끝났다고 말하려면 계정별 프로필 표시 게시물 수와 실제로 받은 게시물 수를 한 번 더 대조해야 하고, 이 마무리 판정은 다음 작업으로 넘겨 두었습니다. 속도 추정이 시험 4계정 375건에서 나온 값이라, 게시물이 6,495건인 큰 계정에서도 같은 속도가 나오는지는 아직 확인 전입니다.
정리하면, 속도 문제는 수집 방식을 바꿔서 풀었고 사고 네 건은 전부 수집 코드 밖, 즉 같은 PC를 나눠 쓰는 다른 작업과의 경계에서 났습니다. 크롤러를 여러 자동화와 한 PC에서 함께 돌린다면 포트 대역, 탭 수명, 동기화 경로, 판정 규칙의 가정을 먼저 점검해 보길 권합니다. 비슷한 수집·자동화 구성을 검토 중이라면 상담에서 구성부터 같이 볼 수 있습니다.