cURL로 파일 다운로드하는 방법: 플래그, 문제 해결, 스크립트

최종 업데이트: August 11, 2026
Hand-drawn file download flowing from a terminal window into a verified folder
AI 요약
리다이렉트, 인증, 재시도, 다운로드 재개 동작, 배치 스크립트, 검증, 일반적인 실패 유형까지 다루는 실전 cURL 다운로드 가이드.

저는 “그냥 파일 하나 받아서 끝내면 되는” 스크립트를 디버깅하느라 쓸데없이 많은 밤을 새운 적이 있습니다. 열에 아홉은 cURL이 제가 실제로 원한 동작이 아니라, 제가 시킨 그대로만 정확히 실행해서 생긴 문제였죠. "curl -O가 동작한다"와 "curl -O가 운영 환경에서도 안정적으로 동작한다" 사이에는 꽤 큰 차이가 있습니다.

이 가이드는 바로 그 차이를 메우기 위해 만들었습니다. cURL은 macOS, 대부분의 Linux 배포판, 그리고 Windows 10 이상에 기본 탑재되어 있어서, 아마 지금 이미 여러분 컴퓨터 안에도 들어 있을 겁니다. 하지만 조용히 실패하는 리다이렉트, 이유를 알 수 없는 403 에러, 그리고 “파일 하나 다운로드”에서 “터미널이 멈추지 않게 500개 파일 다운로드”로 넘어갈 때 생기는 복잡함까지 생각하면 막히는 지점이 정말 많습니다. 여기서는 꼭 알아야 할 플래그, 제가 실제로 쓰는 단계별 명령어, 가장 흔한 오류, 그리고 cURL로는 더 이상 해결할 수 없는 순간과 그때 무엇을 써야 하는지까지 차근차근 설명하겠습니다.

cURL이란 무엇이며, 왜 알아두면 좋을까?

cURL은 URL을 사용해 서버와 데이터를 주고받을 수 있는 무료 오픈소스 커맨드라인 도구입니다. HTTP, HTTPS, FTP, SFTP를 비롯한 수많은 프로토콜을 지원해서, bash 스크립트부터 Dockerfile, CI 파이프라인까지 정말 다양한 곳에서 볼 수 있습니다. 터미널에 입력하는 curl 명령은 내부적으로 libcurl이라는 C 기반 전송 라이브러리를 사용합니다. PHP의 cURL 확장이 대표적인 예고, Python의 인기 라이브러리 Requests는 libcurl이 아니라 urllib3 위에 만들어진 별도의 HTTP 클라이언트입니다.

작성 시점 기준 최신 안정 버전은 curl 8.21.0이며 2026년 6월에 출시되었습니다. 다만 OS에 기본 포함된 버전이 꼭 이 빌드는 아닐 수 있다는 점은 기억하세요. 배포판에 포함된 curl은 상위 프로젝트보다 몇 달, 때로는 그 이상 뒤처질 수 있으니, --parallel 같은 플래그가 실제로 지원되는지 가정하기 전에 curl --version으로 확인하는 편이 좋습니다.

왜 cURL로 파일을 다운로드할까? 대표적인 활용 사례

브라우저만으로도 파일 다운로드는 충분하지 않냐는 질문을 자주 받습니다. 솔직히 말하면, 자동화가 필요해지는 순간 브라우저는 한계를 드러냅니다.

활용 사례cURL이 강한 이유
CI/CD 파이프라인에서 바이너리 다운로드스크립트로 처리 가능하고 GUI가 필요 없음
API 응답이나 데이터 내보내기 가져오기커스텀 헤더, 인증, 출력 파이핑 지원
SSH 환경에서 대용량 다운로드 재개내장 재개 기능(-C -) 제공
정기 다운로드 자동화(cron 작업)가볍고 셸 스크립트와 잘 결합됨
인증 뒤에 숨은 파일 받기유연한 인증 플래그(기본 인증, 토큰, 쿠키, .netrc) 지원

브라우저 다운로드는 한 번 누르고 끝나는 수동 작업입니다. 반면 cURL은 같은 동작을 예약 작업으로 만들고, 파이프라인에 연결하고, 실패 시 재시도하고, 수백 대 서버에서 똑같이 실행할 수 있게 해줍니다. 핵심은 화려함이 아니라 반복 가능성입니다.

Hand-drawn flow from a web source to a downloaded file and local folder

파일 다운로드에 꼭 필요한 cURL 핵심 플래그

제가 하는 작업의 90%는 늘 비슷한 열여섯 개 정도의 플래그로 정리됩니다. 아래는 제가 예전에 누가 좀 정리해줬으면 했던 치트시트입니다. 실제 역할별로 묶었습니다.

출력 및 저장 관련 플래그

  • -O (--remote-name)은 URL 끝의 파일명을 그대로 사용해 저장합니다. 편리하지만 같은 이름의 파일이 있으면 조용히 덮어쓸 수 있습니다.
  • -o <filename> (--output)은 저장할 파일명을 직접 지정할 수 있게 해줍니다. 예: curl -o report.pdf https://example.com/downloads/file.pdf
  • -J (--remote-header-name)은 URL이 아니라 서버의 Content-Disposition 헤더에 적힌 파일명을 사용합니다. API 다운로드에서 유용하지만, 서버가 보내는 파일명은 신뢰할 수 없는 입력으로 간주해야 합니다. curl의 보안 가이드에서도 홈 디렉터리보다는 별도 폴더에 내려받으라고 권장합니다.

모든 다운로드에서 중요한 동작 플래그

  • -L (--location)은 HTTP 리다이렉트를 따라가도록 합니다. 이게 없으면 3xx 응답이 실제 파일이 아니라 작은 HTML 리다이렉트 페이지로 저장됩니다. 제가 보는 가장 흔한 “왜 다운로드가 깨졌지?” 실수입니다.
  • -C - (--continue-at -)은 중단된 다운로드를 끊긴 지점부터 다시 이어서 받습니다.
  • -s / -S는 조용히 실행하되 오류는 보여줍니다. 로그에 진행률 표시가 필요 없는 스크립트에 적합합니다.
  • --limit-rate 1M은 대역폭을 제한합니다. 공유 회선이나 제한형 네트워크에서 유용합니다.
  • --connect-timeout 10--max-time 300은 연결이 멈췄을 때 스크립트가 영원히 얼어붙지 않게 막아줍니다.
  • --retry 3--retry-delay 5는 일시적 실패가 발생했을 때 자동 재시도합니다. curl man page에 따르면, --retry-all-errors는 같은 요청을 반복해도 정말 안전할 때만 함께 쓰는 것이 좋습니다.

진행 상황 확인 및 디버깅 플래그

  • -#는 기본 통계 표 대신 단순한 진행 막대를 보여줍니다.
  • -v는 요청/응답 헤더를 포함한 상세 출력을 보여줍니다. 무언가 이상할 때 제가 가장 먼저 쓰는 옵션입니다.
  • -I (--head)는 응답 헤더만 가져옵니다. 큰 다운로드를 시작하기 전 사전 점검용으로 아주 좋습니다.
  • -w는 전송 후 커스텀 출력을 남길 수 있게 해줍니다. 예를 들어 curl -o /dev/null -s -w "%{http_code}\n" <url>처럼 상태 코드만 확인할 수 있습니다.

시작하기 전에

  • 난이도: 초급~중급(배치 처리와 인증 관련 부분은 조금 더 고급입니다)
  • 예상 소요 시간: 핵심 명령어를 따라 하는 데 약 15~20분
  • 준비물: 터미널(macOS Terminal, Linux 셸, 또는 Windows PowerShell/WSL), 설치된 curl(curl --version으로 확인), 그리고 테스트용 URL. 예시로는 안정적으로 접근 가능한 공개 GitHub 릴리스 자산을 사용하겠습니다.

cURL로 파일 다운로드하는 방법: 단계별 안내

1단계: 파일 하나 다운로드하기

가장 기본적인 형태는 다음과 같습니다. curl -O <url>은 원래 파일명으로 저장하고, curl -o myfile.zip <url>은 저장할 이름을 직접 바꿀 수 있습니다.

curl -LO https://github.com/curl/curl/releases/download/curl-8_21_0/curl-8.21.0.tar.gz

저는 이제 기본값으로 항상 -L을 붙입니다. 예외는 없습니다. 리다이렉트 하나 때문에 “다운로드”가 400바이트짜리 HTML 파일로 바뀌는 일을 너무 많이 겪었거든요. 터미널에서 진행 표시가 올라가다가, 현재 디렉터리에 파일이 떨어지는 것을 확인할 수 있을 겁니다.

명령이 성공하면 진행률이 100%에 도달하고 curl-8.21.0.tar.gz가 현재 폴더에 생성됩니다. 사용하기 전에 파일이 제대로 내려왔는지 확인하세요:

ls -lh curl-8.21.0.tar.gz

2단계: 파일을 다운로드하면서 이름 바꾸기

URL 끝에 적힌 이름이 아니라, 원하는 로컬 파일명으로 저장하고 싶다면 -o를 사용합니다:

curl -L -o curl-latest.tar.gz -S https://github.com/curl/curl/releases/download/curl-8_21_0/curl-8.21.0.tar.gz

여기서 -S는 스크립트의 다른 부분에서 -s를 썼더라도 오류 메시지가 다시 보이도록 해줍니다. 즉, -L -o <name> -S 조합은 사실상 제가 즐겨 쓰는 단일 파일 다운로드 기본형입니다.

3단계: 중단된 다운로드 이어받기

대용량 다운로드가 중간에 끊겼다면(와이파이 불안정, VPN 문제 등) 처음부터 다시 받을 필요가 없습니다. 아래처럼 실행하세요:

curl -C - -LO https://example.com/large-file.iso

주의할 점은, 이 기능은 서버가 바이트 범위 요청을 지원할 때만 동작한다는 것입니다. Accept-Ranges: bytes는 지원 가능성을 보여주는 좋은 신호이지만, 그 값이 없다고 해서 범위를 절대 못 받는다는 뜻은 아닙니다. 가장 확실한 확인 방법은 실제 범위 요청에 대한 서버의 응답입니다. 재개 가능한 응답이라면 보통 206 Partial Content와 유효한 Content-Range를 돌려줍니다. 이어받기 명령을 실행한 뒤 -v-D -로 상태를 확인하세요. 서버가 범위를 무시하거나 오프셋을 거부하면, 부분 파일이 안전하다고 가정하지 말고 의도적으로 다시 시작해야 합니다.

A resilient cURL download resumes after interruption and finishes with checksum verification

4단계: 진행 막대를 보며 받거나, 완전히 조용히 받기

터미널에서 보기 좋게 진행 상황을 보고 싶다면: curl -# -LO <url>. 스크립트나 cron 작업처럼 경고만 필요하고 잡음은 필요 없다면: curl -sS -LO <url>. 저는 수동 디버깅할 때를 제외하면 거의 항상 조용한 버전을 씁니다.

5단계: 다운로드 속도 제한하기

사무실 공용 회선에서 쓰거나, 영상 회의 중에 대역폭을 독점하는 사람이 되고 싶지 않을 때는 이렇게 제한합니다:

curl --limit-rate 1M -LO https://example.com/big-dataset.zip

단위는 초당 킬로바이트, 메가바이트, 기가바이트를 뜻하는 K, M, G를 사용합니다.

6단계: 파일과 함께 응답 헤더 저장하기

서버가 정확히 무엇을 돌려줬는지, 즉 콘텐츠 타입이나 캐시 헤더 같은 정보를 알아야 할 때가 있습니다. 그런데 터미널 출력을 어지럽히고 싶지는 않죠:

curl -L -D headers.txt -o file.zip https://example.com/file.zip

이 명령은 응답 헤더를 headers.txt에 저장하고, 실제 파일은 file.zip으로 내려받습니다. 콘텐츠 타입 불일치를 디버깅하거나 CDN이 정말 캐시를 쓰고 있는지 확인할 때 아주 유용합니다.

팁과 흔한 함정

  • 팁: 기본값은 항상 -L로 두세요. 함께 넣는다고 해서 손해 볼 이유가 전혀 없고, 저는 이걸 깜빡해서 몇 시간을 날린 적이 있습니다.
  • 팁: 스크립트에서는 다운로드 명령과 함께 --fail을 붙이세요. 그러면 2xx가 아닌 응답이 왔을 때 에러로 종료되고, 오류 페이지를 파일처럼 조용히 저장하는 일을 막을 수 있습니다.
  • 함정: -C ---remove-on-error는 함께 쓰지 마세요. curl 문서에서도 이 둘은 호환되지 않는다고 설명합니다. 이어받기는 부분 파일이 남아 있어야 가능하기 때문입니다.
  • 함정: -O는 경고 없이 파일을 덮어쓸 수 있습니다. 공유 디렉터리에서 여러 파일을 한꺼번에 받는다면 --output-dir로 저장 위치를 분리하세요.

cURL로 여러 파일과 배치 다운로드하기

단일 파일 예시는 시작에 불과합니다. 제가 실제로 만든 워크플로우, 예를 들어 야간 데이터 내보내기 수집이나 빌드 서버 간 바이너리 동기화 같은 작업에는 동시성이 필요했습니다. 그런데 대부분의 튜토리얼은 여기서 그냥 멈춥니다. 알아둘 만한 방법은 세 가지이고, 각각 복잡도가 조금씩 올라갑니다.

방법 1: 한 번의 cURL 명령에 여러 URL 넣기

가장 간단한 방법은 URL을 여러 개 나열하는 것입니다:

curl -LO https://example.com/a.zip -LO https://example.com/b.zip -LO https://example.com/c.zip

이 방법도 동작은 하지만 순차적으로 처리됩니다. cURL이 첫 파일을 완전히 마쳐야 다음 파일을 시작합니다. 파일이 세 개면 괜찮지만, 300개면 꽤 고통스럽습니다.

방법 2: --parallel로 병렬 다운로드하기(curl 7.66+)

curl 7.66부터는 --parallel(또는 -Z)을 추가해 여러 URL을 동시에 받을 수 있습니다:

curl --parallel --parallel-max 5 --remote-name-all \
  https://example.com/a.zip https://example.com/b.zip https://example.com/c.zip

알아둘 점이 하나 있습니다. 기본 parallel max는 실제로 50인데, 이는 대부분의 서버나 자신의 네트워크가 반가워할 수준보다 훨씬 높은 동시 연결 수입니다. 저는 기본값을 믿기보다 --parallel-max를 명시하고 보수적으로, 보통 4~8 정도로 잡습니다.

방법 3: URL 목록을 xargs와 Bash 루프로 처리하기

텍스트 파일에 URL이 잔뜩 들어 있을 때는 보통 xargs를 씁니다:

cat urls.txt | xargs -n1 -P 8 curl -O -L

혹은 각 작업을 더 세밀하게 제어하고 싶다면 백그라운드 프로세스를 이용한 bash 루프를 사용합니다:

while read -r url; do
  curl -O -L "$url" &
done < urls.txt
wait

맨 마지막의 wait가 중요합니다. 이게 없으면 백그라운드 다운로드가 끝나기 전에 스크립트가 종료됩니다.

wget이나 aria2를 써야 하는 경우

솔직하게 말하면, cURL이 항상 정답은 아닙니다. 전체 웹사이트 디렉터리를 미러링해야 한다면 wget -r이 재귀 크롤링을 기본으로 지원해서 cURL보다 훨씬 적합합니다. 하나의 아주 큰 파일을 최대한 빠르게 받기 위해 멀티소스·분할 다운로드가 필요하다면 aria2c가 실제로 더 빠릅니다.

도구가장 적합한 용도
cURL정밀한 작업, 스크립팅, 단일 파일 또는 소규모 일괄 다운로드, API 연동
wget재귀/미러링 사이트 다운로드, 단순한 대량 정적 파일 수집
aria2멀티소스/분할 다운로드, 대용량 파일 전송 속도 극대화

cURL의 강점은 예전부터 정밀함과 조합 가능성에 있었습니다. 파이핑, 스크립팅, 프로토콜 유연성이 핵심이지, 무식한 크롤링이 아닙니다.

인증이 필요한 파일을 cURL로 다운로드하는 방법

대부분의 cURL 튜토리얼은 -u user:pass에서 끝납니다. 하지만 그건 인터넷이 지금보다 단순하던 시절의 이야기입니다. 2026년에 제가 실제로 받는 파일은 REST API, 세션 기반 대시보드, CI 시스템에서 오고, 각각 다른 형태의 인증 정보를 요구합니다.

기본 인증(Basic Auth)

curl -u username:password -O https://legacy-server.example.com/file.zip

옛 방식의 FTP 서버나 단순한 HTTP 엔드포인트에는 무난합니다. 다만 비밀번호가 셸 히스토리와 프로세스 목록에 남을 수 있다는 점은 알아두세요. 민감한 작업에는 추천하지 않습니다.

Bearer / OAuth 토큰 인증

많은 가이드에서 충분히 다루지 않지만, 제가 요즘 가장 자주 쓰는 방식입니다:

curl -H "Authorization: Bearer $GITHUB_TOKEN" \
  -LO https://api.github.com/repos/curl/curl/releases/assets/12345

이건 비공개 GitHub 릴리스 자산을 가져올 때 쓰는 실제 패턴입니다. 자신의 토큰과 자산 ID로 바꾸면 됩니다. REST API와 OAuth2 보호 리소스는 이제 거의 이 방식을 사용합니다.

쿠키 기반 세션 인증

로그인하면 세션이 생성되는 웹앱이라면, 로그인할 때 쿠키를 저장하고 다운로드 시 다시 사용하면 됩니다:

curl -c cookies.txt -d "user=me&pass=secret" https://example.com/login
curl -b cookies.txt -O https://example.com/protected/file.zip

스크립트와 CI 환경에서 쓰는 .netrc 파일

무인 실행 작업에는 제가 가장 선호하는 방식입니다. ~/.netrc 파일(Windows에서는 _netrc)을 만드세요:

machine example.com
login myusername
password mypassword

chmod 600 ~/.netrc로 권한을 잠근 다음, 이렇게 참조합니다:

curl --netrc -LO https://example.com/protected-file.zip

장점은 자격 증명이 셸 히스토리나 스크립트 소스에 전혀 남지 않는다는 점입니다. CI/CD에서는 스크립트가 통째로 로그에 남는 경우가 많아서 정말 중요합니다.

인증 방식플래그/옵션가장 적합한 용도
기본 인증-u user:pass레거시 FTP, 단순 HTTP
Bearer 토큰-H "Authorization: Bearer <token>"REST API, OAuth2
쿠키 인증-b cookies.txt (+ 저장 시 -c)세션 기반 웹앱
.netrc 파일--netrc 또는 --netrc-fileCI/CD, 스크립트 환경

Hand-drawn progress blocks, retry arrow, and completed folder

흔한 cURL 다운로드 실패 해결하기

이 섹션은 제가 초보 시절에 정말 있었으면 좋았을 내용입니다. 거의 아무도 이 부분을 제대로 다루지 않거든요. “왜 내 curl 다운로드가 안 되지”는 실제로 자주 검색되는, 꽤 짜증 나는 질문이고, 원인만 알면 해결책은 대개 한 줄이면 끝납니다.

증상가능성 높은 원인해결 방법
curl: (60) SSL certificate problem자체 서명 또는 만료된 인증서--cacert <file> 또는 -k(개발용만)
403 Forbidden / 빈 파일서버가 기본 curl User-Agent를 차단-A "Mozilla/5.0..." 또는 -H "User-Agent: ..."
-C - 사용 시 0부터 재시작됨서버가 Range를 지원하지 않음curl -I <url>Accept-Ranges: bytes 확인
0바이트 파일이 저장됨리다이렉트를 따라가지 않음-L 플래그 추가
curl: (28) Operation timed out서버가 느리거나 네트워크 문제--connect-timeout 10 --max-time 300 + --retry 3
실제 파일 대신 HTML 페이지 저장페이지가 JavaScript 렌더링을 필요로 함curl은 JS를 실행 못함 — 아래 섹션 참고

SSL 인증서 오류: 의미와 해결 방법

오류 60은 curl이 서버의 SSL 인증서를 검증하지 못했다는 뜻입니다. 보통 자체 서명 인증서이거나, 만료됐거나, curl이 신뢰하지 않는 CA에서 발급된 경우입니다. 서버를 직접 관리한다면 올바른 CA 번들을 --cacert /path/to/ca.pem으로 지정하세요. -k(--insecure)는 검증을 완전히 건너뛰는데, 로컬 개발 환경에서는 괜찮지만 운영 환경이나 실제 사용자 데이터와 관련된 작업에서는 정말 피해야 합니다.

403 Forbidden과 빈 다운로드

놀랍게도 많은 서버가 curl/8.21.0처럼 표시되는 요청을 차단합니다. 기본 User-Agent 문자열이 봇이나 스크래퍼처럼 보인다고 판단하기 때문입니다. 이럴 땐 보통 브라우저인 척하는 것만으로 해결됩니다:

curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" -LO https://example.com/file.zip

전체 다운로드를 진행하기 전에 실제 응답이 무엇인지 확인하려면 저는 다음을 실행합니다: curl -o /dev/null -s -w "%{http_code}\n" <url>.

타임아웃, 재시도, 불안정한 연결 처리

제가 타투를 더 안 무서워했다면 팔에 새겨두고 싶을 정도로 자주 쓰는 명령입니다.

운영 스크립트에서 실제로 쓰는 제 기본 다운로드 명령은, 신뢰성을 높이는 플래그들을 전부 겹쳐 둡니다:

curl -L -C - --retry 5 --retry-delay 3 --connect-timeout 10 --max-time 600 --fail -O <url>

리다이렉트 추적, 재개, 3초 지연을 둔 5회 재시도, 10초 연결 타임아웃, 10분 전체 제한, 잘못된 HTTP 상태에서 강제 실패까지 — 제가 시행착오를 통해 반드시 넣게 된 것들을 한꺼번에 담은 조합입니다.

실제 자동화에서의 cURL: CI/CD 파이프라인, 파이핑, 스크립트 안전성

cURL 출력을 다른 도구로 파이핑하기

cURL은 반드시 디스크에 파일을 저장해야 하는 도구가 아닙니다. 다른 명령으로 바로 파이핑하는 것은 가장 과소평가된 기능 중 하나입니다:

curl -sL https://example.com/archive.tar.gz | tar xz
curl -s https://api.example.com/data | jq '.results'

다운로드와 압축 해제, 혹은 다운로드와 파싱을 한 줄로 끝낼 수 있습니다. 저는 단발성 데이터 수집 작업에서 이 패턴을 정말 자주 씁니다.

GitHub Actions와 CI/CD에서 cURL 사용하기

재시도 로직이 포함되고, 오류가 나면 분명하게 실패하는 최소한의 GitHub Actions 단계는 다음과 같습니다:

- name: Download binary
  run: |
    curl -L --fail --retry 3 --retry-delay 5 \
      -o app-binary "https://example.com/releases/app-binary"

토큰은 CI 시크릿에 저장하고 환경 변수로 참조하세요. 스크립트 안에 하드코딩하면 안 됩니다. 그리고 --fail(디버깅 시 오류 본문까지 보고 싶다면 --fail-with-body)을 사용해서 다운로드가 깨졌을 때 빌드도 함께 실패하도록 만드세요. 그렇지 않으면 망가진 파일을 받았는데도 조용히 성공한 것처럼 보일 수 있습니다.

curl | sh 보안 문제

개발자 포럼에서 거의 항상 나오는 주제이고, 그럴 만한 이유도 충분합니다. curl을 바로 sh로 넘긴다는 것은, 서버가 침해되지 않았고 연결이 변조되지 않았다는 전제를 바탕으로 검토하지 않은 원격 코드를 실행하는 것이기 때문입니다. 이것이 진짜 위험입니다. 과한 걱정이 아니라 공급망 보안 관점의 아주 현실적인 이슈죠.

더 안전한 방식은 먼저 내려받고, 스크립트를 확인하고, 제공된다면 체크섬이나 GPG 서명을 검증한 다음 실행하는 것입니다:

curl -sL https://example.com/install.sh -o install.sh
cat install.sh   # 실제로 내용을 읽어보세요
sha256sum install.sh   # 공개 체크섬이 있으면 비교
bash install.sh

rustup이나 Homebrew 같은 유명 설치 프로그램도 여전히 curl | sh 패턴을 사용합니다. 이런 경우는 유지 관리 주체와 배포 경로가 이미 널리 신뢰받는다는 이유로 일반적으로 받아들여집니다. 그래도 저는 스크립트를 훑어보는 데 10초 더 쓰는 편이, 나중에 믿으면 안 될 걸 믿었다는 사실을 뒤늦게 깨닫는 것보다 낫다고 생각합니다.

cURL만으로 부족할 때: JS 렌더링 페이지, 안티봇 사이트, 구조화 데이터

많은 분이 막히는 실패 유형이 하나 있습니다. 사실 사용자 잘못이 아닐 때가 많죠. curl -O를 일반 웹페이지처럼 보이는 곳에 실행했는데, 기대한 콘텐츠 대신 비어 있는 HTML 껍데기, Cloudflare 챌린지 페이지, 혹은 온갖 깨진 내용만 내려오는 경우입니다. cURL은 원래 하려던 일을 정확히 했습니다. 즉, 원시 HTTP 응답을 가져온 것이죠. 다만 JavaScript를 실행할 수도 없고, CAPTCHA를 풀 수도 없고, 안티봇 지문 시스템을 우회할 수도 없습니다. 그건 cURL의 버그가 아니라 애초에 맡은 일이 아닙니다.

현대 웹페이지에서 cURL이 실패하는 이유

요즘 싱글 페이지 앱은 종종 거의 비어 있는 HTML 뼈대만 반환하고, 실제 콘텐츠는 페이지가 로드된 뒤 JavaScript가 클라이언트 측에서 렌더링합니다. cURL은 그런 스크립트를 전혀 실행하지 않습니다. 게다가 Cloudflare나 Akamai 같은 시스템은 실제 브라우저처럼 보이지 않는 요청에 챌린지 페이지를 적극적으로 제공합니다. 같은 IP에서 cURL 요청을 반복하면 속도 제한을 먹거나 봇 트래픽으로 식별되는 일도 금방 생깁니다.

다음 단계: 개발자를 위한 AI 스크래핑 API

제 기준으로 cURL은 파일과 데이터 다운로드의 약 80%에 적합합니다. 정적 자산, API 응답, 그냥 HTTP 리소스로 제공되는 것들이죠. 문제는 나머지 20%입니다. JavaScript가 많은 페이지나 봇 방어가 있는 페이지에서는 개발자들이 헤더와 User-Agent 문자열을 붙잡고 몇 시간을 허비하다가 결국 완전히 다른 계층으로 넘어가는 모습을 많이 봤습니다.

바로 그 간극을 메우기 위해 제 팀은 여러분이 많이 아시는 Chrome 확장 프로그램과 함께 Thunderbit를 만들었습니다. 개발자용으로는 Thunderbit Open API가 POST /distill을 제공해 URL에서 깨끗한 LLM용 Markdown을 반환합니다. 페이지 렌더링은 서비스가 처리합니다. 또 POST /extract는 읽기 쉬운 텍스트 대신 실제 필드 데이터가 필요할 때 스키마에 맞는 구조화 JSON을 돌려줍니다. Claude나 Cursor의 에이전트가 작업 중간에 thunderbit_distillthunderbit_extract를 호출할 수 있는 MCP 서버도 있고, 터미널에서 cURL처럼 사용할 수 있는 CLI(npx @thunderbit/thunderbit-cli distill <url>)도 있습니다. 예를 들어 JSON 출력을 jq로 넘길 수 있습니다. thunderbit distill <url> --format json | jq -r '.data.markdown'처럼 쓰면 되고, --format markdown 출력은 텍스트 도구나 파일로 바로 보내면 됩니다.

비교해 보면 차이는 분명합니다. JS로 렌더링되는 상품 페이지에 cURL을 보내면 대부분 비어 있는 <div id="root"></div>만 돌아올 수 있습니다. 반면 같은 페이지를 thunderbit distill로 처리하면 렌더링된 콘텐츠가 깔끔한 Markdown으로 나옵니다. Distill은 URL당 1 크레딧, Extract는 URL당 20 크레딧입니다. 현재 엔드포인트별 제한도 다릅니다. Batch Distill은 작업당 최대 100개 URL을 지원하고, Batch Extract는 하나의 공통 스키마로 최대 50개 URL을 받을 수 있습니다. 운영용 큐 크기를 정하기 전에 최신 API 문서를 확인하세요.

개념이 아직 익숙하지 않다면, 저희가 정리한 웹 스크래핑이 실제로 무엇을 의미하는지 설명한 글이 좋은 출발점이 될 것입니다. 또 코딩 없이 하는 웹 스크래핑 가이드는 터미널을 쓰지 않는 팀원들도 이해할 수 있도록 같은 문제를 비개발자 관점에서 설명합니다. 이 분야 도구를 넓게 비교한 자료로는 최고의 AI 웹 스크래퍼도 함께 정리해 두었습니다.

빠른 참고용: cURL 다운로드 치트시트

작업명령어
기본 다운로드curl -LO <url>
사용자 지정 파일명curl -L -o myfile.zip <url>
다운로드 재개curl -C - -LO <url>
오류만 보이게 조용히 실행curl -sSL -O <url>
병렬 다운로드curl --parallel --parallel-max 5 -O <url1> -O <url2>
Bearer 토큰 인증curl -H "Authorization: Bearer <token>" -LO <url>
스크립트용 추천 다운로드curl -LO --retry 5 --retry-delay 3 --max-time 600 --fail <url>
추출 도구로 파이핑curl -sL <url> | tar xz

결론 및 핵심 정리

cURL로 파일을 다운로드하는 일은 curl -O 한 줄로 시작하면 거의 끝난 것처럼 보입니다. 하지만 진짜 실력은 그 아래에 있습니다. 언제 -L을 붙여야 하는지, 언제 처음부터 다시 받는 대신 이어받아야 하는지, 내 작업에 어떤 인증 방식이 맞는지, 그리고 기대한 파일 대신 403이나 빈 HTML 껍데기가 나타났을 때 무엇을 해야 하는지 아는 것이죠. 저도 이 모든 패턴을 각각 한 번씩은 써봤습니다. 보통은 그 중요성을 몸으로 배운 직후였습니다.

cURL은 여전히 단연코 제가 가장 먼저 선택하는 도구입니다. 단순한 파일 다운로드와 스크립트 가능한 HTTP 작업에는 빠르고, 어디에나 있고, 셸 파이프라인과도 아주 잘 어울립니다. 하지만 JavaScript로 렌더링된 페이지나 안티봇 장벽에 부딪히면, 그건 플래그를 더 붙여서 해결할 cURL 문제가 아니라 다른 계층이 필요한 신호입니다. 바로 그 지점에서 Thunderbit 같은 API가 터미널 밖으로 나가지 않고도 일을 이어받습니다.

치트시트를 북마크해 두고, 다음에 불안정한 다운로드를 받을 때 재시도·이어받기 명령을 한 번 써보세요. 그리고 cURL이 결국 깨진 내용만 돌려주는 벽에 부딪힌다면, 다음 단계가 어떻게 생겼는지 이미 아실 겁니다. Thunderbit의 가격 페이지에는 현재 크레딧 기준이 정리돼 있으니 실제로 어떤 비용이 드는지 확인해 보세요. 읽는 것보다 보는 게 편하다면 YouTube 채널에서 실습 영상을 볼 수도 있습니다.

cURL로 파일 다운로드할 때 자주 묻는 질문

cURL로 파일을 다운로드하면서 원하는 이름으로 저장하려면 어떻게 하나요?

원하는 파일명을 뒤에 붙여 -o를 사용하세요: curl -L -o yourname.ext <url>. 리다이렉트 때문에 다운로드가 꼬이지 않도록 -L도 함께 넣는 것이 좋습니다.

실패한 cURL 다운로드를 어떻게 이어받나요?

curl -C - -LO <url>을 실행하면 됩니다. 다만 서버가 range 요청을 지원해야 합니다. 먼저 curl -I <url>로 확인하고, 응답에 Accept-Ranges: bytes가 있는지 보세요.

로그인이 필요한 파일도 cURL로 받을 수 있나요?

네, 대표적으로 네 가지 방법이 있습니다. 기본 인증(-u user:pass), Bearer 토큰(-H "Authorization: Bearer <token>"), 쿠키 기반 세션(-b cookies.txt), 그리고 스크립트 환경용 .netrc 파일입니다. 각 방식의 적합한 상황은 위의 인증 섹션을 참고하세요.

파일 다운로드에서 cURL과 wget의 차이는 무엇인가요?

cURL은 더 많은 프로토콜을 지원하고, 스크립팅·파이핑·정확한 단일 파일 또는 소규모 배치 다운로드에 더 적합합니다. wget은 재귀 크롤링과 사이트 전체 미러링에 강해서, 정적 사이트를 대량으로 가져올 때 더 좋습니다.

왜 cURL이 실제 파일 대신 HTML 페이지를 다운로드하나요?

보통 두 가지 이유가 있습니다. -L 플래그를 빼먹어서 서버가 다른 곳으로 리다이렉트했거나, 페이지가 실제 콘텐츠를 JavaScript로 렌더링해야 하는데 cURL은 그걸 실행할 수 없기 때문입니다. 두 번째 경우에는 cURL 플래그를 더 추가할 게 아니라 렌더링 가능한 도구가 필요합니다.

더 알아보기

Ke
Ke
Thunderbit CTO | 시니어 데이터 사이언티스트 & ML 전문가 머신러닝과 데이터 과학 분야에서 약 10년에 가까운 경험을 쌓아온 Ke Shen은 컬럼비아 대학교 출신이며, 전 Walmart Labs의 시니어 데이터 사이언티스트였습니다. Python, R, Java, 통계 분야에서 동료들에게도 인정받는 깊은 전문성을 바탕으로, 복잡한 AI 알고리즘을 이론에서 실제 운영 수준의 아키텍처로 전환하는 데 필요한 실전 인사이트를 공유합니다.
Topics
cURL 파일 다운로드커맨드라인 자동화안정적인 파일 전송
목차
Thunderbit · AI 웹 데이터 에이전트

원클릭 내 모든 페이지에서 데이터 추출

25만 명 이상의 사용자에게 신뢰받는
무료 플랜 이용 가능
AI를 사용하여 데이터 추출
Google Sheets, Airtable 또는 Notion으로 데이터를 쉽게 전송하세요
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week