Botasaurus 리뷰: 4 MB 드라이버, 122 MB 설치 용량, 그리고 인용하면 안 되는 0.08ms

최종 업데이트: August 14, 2026
Botasaurus 리뷰: 4 MB 드라이버, 122 MB 설치 용량, 그리고 인용하면 안 되는 0.08ms
AI 요약

Botasaurus는 Omkar Cloud가 만든 Python 웹 스크래핑 프레임워크로, 스크래퍼를 만드는 데 필요한 기능을 한데 묶은 올인원 도구라고 소개합니다. 일반 함수에 @browser, @request, @task를 붙이면 브라우저 드라이버, 브라우저처럼 보이는 HTTP 클라이언트, 캐싱, 병렬 처리, 다양한 형식의 출력이 프레임워크 안에서 연결됩니다. 핵심은 메타 패키지라는 점입니다. pip install botasaurus는 하나의 라이브러리만 설치하는 것이 아니라, 여러 자체 패키지와 방대한 전이 의존성 트리를 함께 구성합니다. 제가 솔직하게 측정할 수 있었던 가장 흥미로운 부분도 바로 그 구조적 특성이었습니다.

Botasaurus는 Omkar Cloud가 만든 Python 웹 스크래핑 프레임워크로, 스크래퍼를 만드는 데 필요한 기능을 한데 묶은 올인원 도구라고 소개합니다. 일반 함수에 @browser, @request, @task를 붙이면, 프레임워크가 브라우저 드라이버, 브라우저처럼 동작하는 HTTP 클라이언트, 캐싱, 병렬 처리, 다양한 형식의 출력까지 알아서 연결해 줍니다. 핵심은 이게 메타 패키지라는 점입니다. pip install botasaurus는 하나의 라이브러리만 환경에 넣는 게 아니라, 여러 개의 자체 배포 패키지와 방대한 의존성 트리를 함께 깔아줍니다. 제가 가장 흥미롭게, 그리고 솔직하게 측정할 수 있었던 건 바로 이 구조적 특성이었습니다.

Botasaurus는 안티 디텍션을 강하게 내세우지만, 이번 리뷰는 그 부분을 건드리지 않았습니다. 저는 프레임워크가 무엇을 설치하는지, 무엇을 import하는지, 어떤 메서드를 제공하는지, 용량은 얼마나 되는지, 어떤 라이선스를 따르는지 등을 정리했을 뿐, 실제 방어 체계와 맞붙여 보지는 않았습니다. 아래의 모든 용량과 import 수치는 pip, python -c "import ...", 그리고 페이지를 가져오라고 지시하지 않은 상태에서 생성한 클래스 인스펙션 결과에서 나온 것입니다. 브라우저를 실제로 띄운 경우도 있었지만, 오직 제가 직접 작성해 127.0.0.1에서 서빙한 페이지에만 연결해, 드라이버가 스스로를 어떻게 드러내는지와 JavaScript로 구성되는 페이지에서 콘텐츠를 제대로 가져올 수 있는지만 확인했습니다. 어떤 라이브 웹사이트도 건드리지 않았고, 어떤 안티봇 서비스도 접속하거나 측정하지 않았으며, CAPTCHA도 전혀 다루지 않았습니다. 실제 웹사이트에서의 효과는 의도적으로 범위 밖으로 뺐습니다. 제가 직접 실행하지 않은 벤치마크인 척하는 것보다는 그 점을 분명히 하는 편이 낫기 때문입니다.

이런 전제를 깔고 보면, 가장 먼저 보이는 결론은 footprint 이야기이고, 결과는 꽤 무난합니다. 깨끗한 설치만으로도 44개 패키지에 걸쳐 122.3 MBsite-packages 디렉터리가 생깁니다. 전체의 중심에 있는 브라우저 드라이버는 약 4 MB 수준입니다. 즉, 프레임워크가 무거운 이유는 드라이버가 커서가 아니라, “올인원”이라는 말이 numpy, lxml, gevent, 그리고 HTML을 가져오는 일과 직접 관계없는 다른 여러 패키지까지 끌고 들어오기 때문입니다. 그리고 또 하나의 수치는 자주 장점처럼 인용되지만 사실은 조심해서 봐야 합니다. import botasaurus0.08 ms에 끝나는데, 이는 가벼운 프레임워크라는 뜻이 아니라 실제로는 거의 비어 있는 현관문에 가깝다는 의미입니다.

Botasaurus는 실제로 무엇인가

GitHub의 Botasaurus — omkarcloud/botasaurus — 는 제가 2026년 7월 14일 메타데이터를 확인했을 때 5,561개 스타, 486개 포크, 58개의 열려 있는 이슈를 가진 Python 프레임워크입니다. 제가 테스트한 버전은 메타 패키지인 botasaurus 4.0.97와 그 아래 엔진인 botasaurus-driver 4.0.92였습니다. 메타 패키지는 requires-python >=3.7을 요구하고, 드라이버는 >=3.5를 요구합니다. PyPI 분류는 3.11까지만 지원한다고 적혀 있습니다. 그런데 제 환경의 Python 3.14.2에서는 설치가 잘 되었고 import 스모크 테스트도 통과했습니다. 다만 이것은 이번 설치에 대한 증거일 뿐, 모든 기능의 호환성을 보장한다는 뜻은 아닙니다.

카테고리를 분명히 해두는 것이 중요합니다. 그래야 “좋다”의 기준이 정해지기 때문입니다. Botasaurus는 프레임워크 쪽에 가깝습니다. ScrapyCrawlee와 같은 계열이라고 보면 됩니다. 구조와 데코레이터, 관례를 받아들이는 대신, 주변 plumbing은 프레임워크가 맡아줍니다. 반면 nodriver 같은 집중형 드라이버는 Chrome DevTools Protocol 연결만 제공하고 최대한 빠져줍니다. Botasaurus는 드라이버를 포함하긴 하지만, 여기에 태스크 러너, 캐싱 계층, 출력 직렬화기, 요청 클라이언트까지 얹습니다. 즉, 드라이버를 사는 게 아니라, 드라이버가 내장된 의견 있는 워크플로우를 사는 셈입니다.

세 개의 데코레이터가 이 설계의 축소판입니다. 그리고 세 진입점 모두 실제로 존재하는 것을 확인했습니다. botasaurus.browser.browser, botasaurus.request.request, botasaurus.task.task는 모두 import 가능합니다. @browser는 당신의 함수를 인간처럼 보이게 설계된 브라우저 드라이버 위에서 실행합니다. @request는 브라우저처럼 보이도록 만든 가벼운 HTTP 클라이언트 위에서 실행합니다. @task는 앞의 둘 중 어느 쪽으로도 딱 잘라 분류되지 않는 작업을 위한 일반 래퍼입니다. 한 번 데코레이터를 붙이면 Botasaurus가 나머지 기계를 붙여 줍니다. 병렬 실행, 드라이버 재사용, 결과 캐싱, JSON/CSV/Excel/HTML 출력까지 포함해서요. 아이디어 자체는 꽤 일관됩니다. 다만 스크래퍼 주변에 이 정도 프레임워크가 필요한지는 별개의 취향 문제입니다. 결함이라기보다 선택의 문제에 가깝습니다.

제 평가와 그 한계

Botasaurus는 꽤 능숙하고, 구조도 잘 잡혀 있으며, 프레임워크가 해야 할 일을 합니다. 즉, 흔한 사용 사례를 짧게 만들어 줍니다. 데코레이터 방식도 깔끔합니다. MIT 라이선스는 정말 관대합니다. 설치도 별다른 문제 없이 됩니다. API 표면의 사용 편의성만 채점한다면 좋은 점수를 줄 수 있습니다.

다만 계속 마음에 걸리는 부분은, 이 프레임워크가 내세우는 대표 슬로건인 안티 디텍션은 누군가의 운영 방어를 실제로 상대해 보지 않고서는 책임 있게 평가할 수 없다는 점입니다. 드라이버에는 분명 안티 디텍션을 연상시키는 API가 존재합니다. 존재 여부는 확인했지만, 행동은 실제 타깃에서 시험하지 않았습니다. 그래서 제가 말할 수 있는 건 거기까지입니다. 보호된 사이트에 대보지도 않았고, 성공률도 측정하지 않았고, 메커니즘도 역공학하지 않았습니다. 따라서 그 중 어느 것도 암시하지 않겠습니다. 메서드는 클래스 안에 있습니다. 하지만 현실에서 무엇을 하는지는 이 리뷰의 범위를 넘어섭니다.

이후 내용은 기능, 설치, 리소스, 라이선스에 대한 조사와, 제가 직접 제어하는 페이지에서 드라이버가 무엇을 하는지에 대한 기록입니다. 이 도구에 대한 대부분의 리뷰보다 훨씬 좁은 주장이고, 바로 그 좁음이 포인트입니다.

스스로를 어떻게 드러내는가

Measured results chart: Default browser disclosures by stack

실제 방어 체계에 접근하지 않고도 답할 수 있는 질문이 하나 있습니다. Botasaurus가 브라우저를 구동할 때, 그 브라우저는 자신에 대해 무엇을 페이지에 알려줄까요? 저는 navigator.webdriver, user-agent, platform, languages, plugin과 hardware 수, window.chrome의 형태, Permissions API 응답, window와 screen의 기하 정보 등을 읽어내는 페이지를 만들었습니다. 그리고 이를 127.0.0.1에서 서빙한 뒤, Botasaurus, nodriver, 그리고 비교군으로 stock Playwright와 stock Puppeteer를 붙였습니다. 네 스택 모두 같은 Chrome 빌드(Chrome for Testing 151.0.7922.10) 를 사용했기 때문에, 차이가 있다면 브라우저가 아니라 라이브러리 차이입니다. headless와 headed 모드 모두에서 각각 세 번씩 실행했고, 아래 값들은 모두 세 번의 실행에서 일관됐습니다.

스택모드navigator.webdriverUser-agent 토큰navigator.languages
Botasaurus 4.0.92headlessfalseHeadlessChrome/151.0.0.0["en-US"]
Botasaurus 4.0.92headedfalseChrome/151.0.0.0["en-US"]
nodriver 0.50.3headless / headedfalseHeadlessChrome/151 / Chrome/151["en-US"]
Playwright 1.56.0headless / headedtrueHeadlessChrome/151 / Chrome/151["en-US","en"]
Puppeteer 24.16.0headless / headedtrueHeadlessChrome/151 / Chrome/151["en-US"]

차이는 어떤 비교군을 쓰느냐에 따라 달라집니다. stock Puppeteer와 비교하면 Botasaurus는 navigator.webdriver 값을 바꿨고, 언어 목록과 0 크기 창 기하 정보는 같았으며, user-agent는 버전 표기만 달랐습니다. stock Playwright와 비교하면 언어 목록과 창 기하 정보 차이도 있었습니다. nodriver와 비교하면 불리언 값과 언어 목록은 같았고, 여기 표에 나온 범위에서는 user-agent 표기만 달랐습니다. 이것은 안티 디텍션 점수가 아니라, 기본 노출 상태에 대한 관찰입니다.

여기서 조금 더 흥미로운 점은 단순히 false냐 아니냐가 아닙니다. 첫째는 그 값이 어떻게 설정되느냐입니다. 네 스택 모두에서 해당 속성은 여전히 Navigator.prototype의 브라우저 고유 native getter입니다. function get webdriver() { [native code] } 형태로 남아 있으며, 인스턴스에 자체 속성으로 심겨 있지도 않고, 대체 함수로 바뀌지도 않았습니다. 즉, Botasaurus는 페이지가 열린 뒤 속성을 덮어쓰는 방식이 아닙니다. 값은 브라우저 시작 시점에 결정되고, 속성 자체는 건드리지 않은 채 남겨 둡니다.

둘째는 마케팅 문구를 제한하는 부분입니다. headless 모드에서 Botasaurus의 user-agent는 여전히 HeadlessChrome/151.0.0.0이라고 말합니다. stock Puppeteer와도 같고, stock Playwright와도 같습니다. headed로 실행하면 Chrome/151.0.0.0이 되는데, 이 또한 똑같습니다. Driver 생성자는 user_agent 파라미터를 받기 때문에, 커스텀 값을 넣는 것은 키워드 인자 하나면 충분합니다. 하지만 기본 설정만으로는 브라우저 자동화에서 가장 널리 알려진 자기 식별 문자열을 숨겨 주지 않습니다.

나머지는 네 스택 모두에서 거의 같았습니다. 이 사실을 분명히 말하는 이유는, 이야기를 더 좁혀 주기 때문입니다. 아래 속성들은 Botasaurus, nodriver, Playwright, Puppeteer 모두에서 동일했습니다.

속성네 스택 모두에서 동일한 값
platformMacIntel
vendorGoogle Inc.
Plugins5개
MIME types2개
pdfViewerEnabledtrue
논리 코어 수12개
보고된 메모리16 GB
터치 포인트0
window.chrome존재, app/csi/loadTimes 포함, runtime 없음
WebGL 렌더러 문자열네 스택 모두 동일

옛날에 자주 보이던 Permissions API와 Notification.permission의 불일치는 어디에도 나타나지 않았습니다. 네 스택 모두 defaultprompt로 일치했습니다. 또한 cdc_ 같은, 예전 WebDriver 계열에서 남아 있던 흔적도 documentwindow 어디에서도 발견되지 않았습니다.

배포 전에 꼭 알아둘 점이 하나 더 있습니다. Botasaurus는 122 MB가 넘지만 브라우저 자체를 번들링하거나 내려받지 않습니다. find_chrome_executable()는 머신에 이미 설치된 Chrome을 가리키는데, 제 환경에서는 /Applications/Google Chrome.app이었고 버전은 150.0.7871.187이었습니다. 그리고 그 버전이 그대로 user-agent에 드러납니다. 즉, 여러분의 환경이 가진 Chrome 버전이 그대로 외부에 보이는 셈입니다. 이 정도로 의견이 강한 프레임워크치고는 의외로 기본값은 꽤 무심합니다.

이것이 무엇인지, 그리고 무엇이 아닌지 분명히 해야 합니다. 이것은 자동화 스택이 아무도 숨기라고 지시하지 않았을 때 무엇을 노출하는지에 대한 기록입니다. 방어 측에 있으면 유용하고, 자체 도구가 무엇을 브로드캐스트하는지 알고 싶을 때도 유용합니다. 하지만 어떤 특정 서비스에 대해 그 정보가 실제로 중요한지의 여부를 보여 주는 수치는 아닙니다. 저는 그걸 테스트하지 않았고, 위 표의 어떤 행도 결과를 암시하는 것으로 읽히면 안 됩니다.

더 관대한 기본값으로 본 이 fixture

자기 자신을 드러내는 것과 정확한 HTML을 돌려주는 것은 다른 문제입니다. 저는 이 벤치마크 저장소의 다른 도구들과 동일한 세 가지 콘텐츠 클래스 fixture에 대해 Botasaurus를 돌렸습니다. 그래서 숫자는 다른 도구들과 비교 가능한 형태를 유지합니다. 페이지는 세 가지를 담고 있습니다. A는 서빙된 바이트 안에 리터럴로 들어 있는 정적 링크입니다. B는 파싱 도중 inline script가 만들어 내는 노드로, 마커와 URL이 조각에서 조립되므로 JavaScript를 실제로 실행해야만 보입니다. C는 load 이벤트가 끝난 800ms 후에 주입되는 노드입니다. 이것 역시 조각에서 조립됩니다. C는 적대적인 케이스입니다. load 시점에 읽으면 절대 보이지 않습니다.

스택기본 읽기명시적 대기 포함
Botasaurus 4.0.923개 중 2개 (A + B, C 누락)3개 중 3개
nodriver 0.50.33개 중 2개3개 중 3개
Playwright 1.56.03개 중 2개3개 중 3개
Puppeteer 24.16.03개 중 2개3개 중 3개

Botasaurus는 다른 강자들과 같은 지점에 도착합니다. driver.get() 뒤 곧바로 driver.page_html을 읽는 방식은 load 시점 스냅샷입니다. JavaScript는 제대로 실행합니다. B가 서빙된 바이트에는 존재하지 않는데도 페이지에 나타나기 때문입니다. 하지만 800ms 지연된 콘텐츠 C는 놓칩니다. driver.wait_for_element("#delayed-injected")를 추가하면 세 개를 모두 얻습니다. 세 번의 반복과 전체 세트의 세 번 실행 모두에서 안정적이었고, flake는 없었습니다.

더 흥미로운 부분은 각 스택의 기본 읽기가 어디까지 버티는지를 주입 지연별로 훑어볼 때 나타납니다.

C가 주입된 시점BotasaurusnodriverPlaywrightPuppeteer
0 ms발견발견발견발견
100 ms발견
200 ms발견
300 ms발견
400 ms 이상

다른 모든 스택은 load 이후 100ms 이상 지나서 주입되면 C를 놓칩니다. Botasaurus는 300ms에서도 여전히 잡아내고, 400ms에서야 포기합니다. 이건 Botasaurus가 프레임워크답게 동작한 결과입니다. 원인은 생성자에 그대로 드러나 있습니다. wait_for_complete_page_load=True가 기본값이기 때문에, get()가 단순 load 이벤트보다 의미 있게 더 늦게 반환됩니다. 수치로 보면, Botasaurus의 기본 읽기는 wall clock 기준 401–431ms 정도가 걸리는데, nodriver는 119–129ms, Puppeteer는 125–171ms 정도입니다.

이 로컬 지연 주입 fixture에서는, 기본 스냅샷이 더 늦게 찍히는 대가로 네비게이션당 약 250ms를 지불한 셈이었습니다. 그 결과 load 이후 최대 300ms까지 주입된 콘텐츠를 잡아냈습니다. 하지만 이것이 Botasaurus가 모든 사이트에서 더 정확하다는 뜻은 아닙니다. 빠르게 스크래핑하되 명확한 wait 조건을 따로 두지 않는다면, 이 여유가 늦게 들어오는 노드를 놓치지 않게 해 줄 수 있습니다. 반면 네비게이션 수가 많거나 이미 정확한 조건을 기다리는 경우라면, 그냥 오버헤드입니다.

규모 감각을 위한 타이밍을 하나 더 보겠습니다. 브라우저를 띄우는 시간은 Botasaurus가 nodriver와 Puppeteer와 비슷했고, Playwright보다는 확실히 느렸습니다.

스택브라우저 실행 시간, 여러 번 측정
Botasaurus 4.0.92986–1151 ms
nodriver 0.50.3910–1583 ms
Puppeteer 24.16.0969–1008 ms
Playwright 1.56.0282–365 ms

그리고 wait_for_element()는 주입 지연이 300ms일 때까지는 추가 비용이 거의 없습니다. get() 자체가 이미 주입 이후 시점까지 도달해 있기 때문입니다. 하지만 400–800ms 지연에서는 약 1.42초, 1500ms 지연에서는 2.43초 정도까지 올라갑니다.

122 MB라는 질문: 메타 패키지는 실제로 무엇을 깔아 두는가

Measured results chart: Heaviest installed dependencies

가장 실용적인 건 이 산술입니다. 새 가상환경에 깨끗하게 pip install botasaurus를 하면 122.3 MB짜리 site-packages 트리가 만들어졌고, 44개 dist-info 패키지가 들어 있었습니다. 여기서 pip 자체만 빼면(10.9 MB, 이건 Botasaurus가 직접 요구한 게 아니라 venv 오버헤드에 가깝습니다) 프레임워크와 의존성만으로도 대략 111 MB입니다. 실제 브라우저 자동화를 수행하는 컴포넌트인 드라이버는 이 중 4 MB 정도입니다. 즉, 약 107 MB는 메타 패키지가 “이 정도는 있어야 한다”고 판단한 나머지입니다.

어디에 그렇게 들어갈까요? 가장 무거운 전이 의존성 다섯 개만으로도 대부분이 설명됩니다. 아래 각 행은 artifacts/raw/runs/resource_baseline.run1.jsoninstall_footprint.heaviest_deps_mb 항목이며, 마지막 합계는 파일에 들어 있는 값이 아니라 제가 더한 것입니다.

패키지디스크 사용량
numpy30.9 MB
lxml19.2 MB
botasaurus_requests12.6 MB
gevent11.3 MB
pygments8.4 MB
다섯 패키지 합계82.4 MB (30.9 + 19.2 + 12.6 + 11.3 + 8.4)

numpy가 가장 큰 항목이라는 점은 꽤 의외였습니다. 웹 페이지를 가져오고 파싱하는 도구 안에 선형대수 라이브러리가 들어 있다는 뜻이니까요. 물론 틀린 것은 아닙니다. 프레임워크는 유틸리티 의존성을 계속 쌓아 올리기 마련이고, 의존성 트리 어딘가에서 배열 연산이 필요할 수도 있습니다. 다만 이건 분명히 작업에 비해 기계가 너무 큽니다.

규모 감각을 위해 말하자면, 집중형 드라이버 nodriver는 같은 머신에서 6개 패키지에 걸쳐 약 17.2 MB입니다. 대략 7배 더 가볍다고 보면 됩니다. 이 수치는 이번 패키지에서 나온 게 아니라 nodriver 자신의 artifacts/raw/runs/resource_baseline.run1.jsoninstall_footprint.site_packages_total_mb 값이며, 같은 호스트에서 별도의 분산 실행으로 측정된 것입니다. 122.3 ÷ 17.2 = 7.1입니다. 어느 쪽도 결함은 아닙니다. 이것은 기능이 포함된 프레임워크와 집중형 드라이버 사이의 기계적 비용 차이입니다. 컨테이너 안에서는 이렇게 측정된 site-packages footprint가 애플리케이션 레이어에 직접 영향을 줍니다. 하지만 이것이 전체 이미지 크기는 아니며, 이번 테스트는 빌드 시간이나 콜드 배포 시간은 재지 않았습니다.

footprint와 관련해 한 가지 더 있습니다. 인스펙션 도중 from botasaurus.request import request를 처음 호출하자 약 12.8 MB 정도의 일회성 다운로드가 발생했습니다. 다만 캡처된 실행만으로는 이 파일과 목적지를 충분히 특정할 수 없어, 안정적인 설치 용량 증가분으로 보지는 않았습니다. 대신 이 코드 경로가 첫 사용 시 네트워크 접근을 요구할 수 있다는 점은 분명합니다. 에어갭 배포 전에 본인 이미지에서 미리 재현해 보는 것이 좋습니다.

거짓말을 하는 import 숫자

콜드 스타트 import 시간은 숫자를 대충 읽으면 틀리기 쉬운 지점입니다. 새 subprocess에서 일곱 번 측정했을 때, 최상위 import botasaurus의 중앙값은 0.08 ms였습니다. 이 수치만 떼어 말하면, 카테고리에서 가장 가벼운 프레임워크처럼 들립니다.

하지만 그렇지 않습니다. 이게 빠른 이유는 위에 거의 아무것도 없기 때문입니다. 최상위 botasaurus 패키지는 __version__도 없고, 공개 네임스페이스도 거의 비어 있습니다. import가 거의 일을 하지 않으니 거의 시간이 들지 않는 것입니다. CLI나 서버리스 콜드 스타트에서 실제로 중요한 숫자는 엔진 import입니다. from botasaurus_driver import Driver는 약 135 ms가 걸렸고, 여러 번 실행해도 몇 밀리초 범위 안에서 안정적이었습니다. 이게 실제로 페이지 하나도 가져오기 전에 내야 하는 고정 비용입니다. 그리고 드라이버 모듈이 import된 뒤의 resident memory는 약 29–30 MB 정도였습니다. 물론 Chrome 프로세스가 뜨기 전 기준입니다. 실제 브라우저를 띄우면 이보다 훨씬 커지지만, 저는 running browser 메모리는 측정하지 않았기 때문에 숫자를 붙이지 않겠습니다.

교훈은 작지만 분명합니다. import botasaurus가 즉시 끝난다는 사실은 프레임워크가 가벼워서가 아니라, 최상위 패키지가 비어 있기 때문입니다. 콜드 스타트를 계산할 때는 실제로 의존할 import를 재야 합니다.

API 형태: 거의 비어 있는 현관문 뒤의 99개 메서드

System diagram: API shape: behind a near-empty front door

엔진의 Driver 클래스는 99개의 공개 메서드를 제공합니다. 네비게이션, 요소 질의, 쿠키와 로컬 스토리지, 마우스와 키보드 동작, 스크린샷, 탭 관리, CDP passthrough, 파일 업로드까지 꽤 넓게 포괄합니다. 생성자는 18개의 파라미터를 받는데, 조절 가능한 표면을 잘 보여 줍니다. headless, proxy, profile, tiny_profile, block_images, block_images_and_css, wait_for_complete_page_load, chrome_executable_path, extensions, arguments, user_agent, window_size, lang 등 브라우저 래퍼에서 흔히 쓰는 조절 항목이 대부분 들어 있습니다.

하지만 최상위 형태에는 작은 함정이 있습니다. 해롭지는 않지만 실제로 존재합니다. import botasaurus를 하면 거의 비어 있는 네임스페이스만 들어옵니다. __version__도 없고, 최상위 공개 이름도 거의 없습니다. 실제로 쓰는 기능은 모두 서브모듈에 있습니다. from botasaurus.browser import browser, Driver, from botasaurus.request import request, from botasaurus.task import task처럼 가져와야 합니다. botasaurus.__version__을 로그에 찍으려 해도 찾을 수 없고, importlib.metadata를 써야 합니다. 이것이 무언가를 망가뜨리는 것은 아닙니다. 다만 많은 Python 개발자가 직감적으로 기대하는 배치와는 다르고, 이 구조를 알아두면 첫날의 헷갈리는 5분을 아낄 수 있습니다.

앞서 언급한 메서드들에 대해 문서 위치를 한 가지 짚자면, 이는 제가 확인한 범위 안에서도 충분히 말할 수 있습니다. 안티 디텍션 관련 이름을 가진 메서드들 가운데 2개만 코드 내부 docstring을 갖고 있습니다. 나머지는 이름만으로 자기 설명을 하고, 메서드별 상세 문서는 설치된 소스가 아니라 외부 문서 사이트에 있습니다. 이것은 품질 판단이 아니라 위치에 대한 메모입니다. 좋은 라이브러리 중에도 본문을 코드 밖에 두는 경우는 많습니다. 다만 소스를 읽고 메서드를 이해하는 워크플로우라면, 이 표면의 대부분은 이름만 알려 줄 뿐 그 이상은 말해 주지 않습니다.

라이선스: 드라이버까지 전부 MIT

메타 패키지와 botasaurus-driver는 모두 MIT를 선언하며, 표준 License :: OSI Approved :: MIT License 분류를 달고 있습니다. MIT는 매우 관대합니다. 카피레프트 의무가 없고, 자신의 코드를 공개할 필요도 없으며, 상용 채택에도 부담이 적습니다. 이는 AGPL-3.0으로 배포되는 인접한 안티 디텍트 드라이버 nodriver와 실제로 큰 차이를 만듭니다. AGPL은 네트워크 사용 조항 때문에 법무팀을 긴장시키는 카피레프트 라이선스입니다. 라이선스가 중요한 판단 기준이라면, Botasaurus의 MIT는 분명한 장점입니다.

다만 여기서도 메타 패키지 구조는 한 번 더 주의해야 합니다. Botasaurus와 그 자체 배포 패키지들에 적용되는 것은 분명 MIT입니다. 하지만 설치 과정에서 끌려 들어오는 약 40개의 전이 의존성 각각에 대해서까지 자동으로 보증하는 것은 아닙니다. 저는 Omkar Cloud가 배포하는 상위 패키지들의 MIT는 확인했지만, 트리 전체의 모든 의존성 라이선스를 일일이 감사하지는 않았습니다. 취미 프로젝트라면 이 차이가 별로 중요하지 않을 수 있습니다. 하지만 회사 내부에서 전체 트리를 도입하며 소프트웨어 BOM을 관리해야 한다면, 40개 패키지 트리는 반드시 자체 라이선스 스캐너에 한 번 태워 보아야 합니다. 문제가 있어서가 아니라, 제가 다 보지 않았고, 바로 그런 곳에 예상치 못한 라이선스가 숨어들기 쉽기 때문입니다.

장단점

장점:

  • @browser / @request / @task의 세 데코레이터 설계가 깔끔하고, 세 진입점이 모두 실제로 존재해 흔한 작업을 짧게 만들어 준다.
  • 메타 패키지와 드라이버 모두 MIT 라이선스라서, 비슷한 기능의 AGPL-3.0 드라이버와 뚜렷이 대비된다. 관대하고 상용 친화적이다.
  • 드라이버 표면이 넓다. 99개의 공개 메서드와 18개 파라미터 생성자가 일반적인 브라우저 자동화 요구를 충분히 커버한다.
  • Python 3.14.2와 3.12.13에서 설치 및 import 스모크 테스트를 통과했으며, 분류 목록(3.11까지)보다 최신 버전에서도 동작했다. 다만 전체 런타임 호환성까지 입증한 것은 아니다.
  • 제가 측정한 스택들 중 기본 읽기 정확도 창이 가장 넓다. load 후 300ms에 주입된 콘텐츠도 잡아냈고, nodriver·Playwright·Puppeteer는 모두 100ms에서 놓쳤다. wait_for_complete_page_load=True가 실제로 일을 하고 있다.
  • 기본적으로 navigator.webdriverfalse로 보고하며, stock Puppeteer와 stock Playwright는 true를 보고한다. 하지만 속성 패치는 하지 않았고, descriptor는 브라우저의 native getter 그대로다.
  • 캐싱, 병렬성, 드라이버 재사용, JSON/CSV/Excel/HTML 출력이 프레임워크에 기본 포함되어 있다.

단점:

  • 디스크 용량이 무겁다. 44개 패키지에 걸쳐 122.3 MB이며, 집중형 드라이버보다 대략 7배 무겁다. numpy(30.9 MB)와 lxml(19.2 MB) 같은 의존성이 주된 원인이다.
  • 안심시키는 듯한 0.08 ms 최상위 import는 오해를 부른다. 실제로 의존하는 엔진 import는 약 135 ms이고, import 후 메모리는 브라우저가 뜨기 전인데도 29–30 MB 수준이다.
  • 더 넓은 기본 읽기 창은 공짜가 아니다. 같은 페이지, 같은 Chrome 기준으로 navigate-and-read가 119–129 ms인 가벼운 드라이버보다 401–431 ms가 걸린다.
  • headless 실행 시에도 user-agent는 기본적으로 HeadlessChrome를 그대로 노출한다. user_agent 생성자 파라미터는 있지만 자동으로 설정되지는 않는다.
  • 122 MB짜리 설치인데도 브라우저는 포함하지 않는다. 호스트에 이미 깔린 Chrome을 그대로 사용하므로, 외부에 드러나는 브라우저 버전도 설치된 환경에 따라 달라진다.
  • @request의 첫 사용에서 약 12.8 MB짜리 일회성 다운로드가 발생했다. 다만 이 항목은 안정적인 footprint 증가분으로 확정할 만큼 캡처되지 않았다.
  • 최상위 패키지가 거의 비어 있고 __version__도 제공하지 않는다. 실제 API와 버전 정보는 더 눈에 잘 띄지 않는 곳에 있다.
  • 안티 디텍션 이름을 가진 메서드 대부분은 코드 내부 docstring이 없어, 소스를 읽어도 이름만 보이고 동작은 바로 드러나지 않는다.

이 수치들의 범위를 벗어나는 부분, 따라서 여기서 테스트하지 않은 것들은 다음과 같습니다. 실제 안티봇 효과, 페이지별 메모리, 프록시와 프로필 처리, 대규모 처리량, 그리고 macOS arm64 이외의 플랫폼입니다. footprint와 import 수치는 브라우저를 전혀 띄우지 않은 상태에서 측정했고, 회수율과 노출 수치는 오직 127.0.0.1의 fixture와만 대화한 브라우저에서 얻었습니다.

누구에게 맞고, 누구는 피해야 하나

Botasaurus는 프레임워크를 원하는 사람에게 잘 맞습니다. 빈 파일에서 스크래핑 프로젝트를 시작하면서 구조를 직접 조립하기보다 기존 구조를 받아들이고 싶고, 진입점은 데코레이터로 처리하고, 캐싱과 병렬성은 맡기고, 출력 writer까지 기본 포함이면 좋겠다면, 이건 일관된 MIT 라이선스 옵션입니다. MIT는 관대하지만, 사용 및 배포 모델에 대한 일반적인 컴플라이언스 검토는 여전히 필요합니다. 이미 Scrapy나 Crawlee식 사고방식에 익숙한 팀이라면 구조가 낯설지 않을 것입니다.

반대로, 배포 대상이 size-sensitive하다면, 적어도 한 번 더 생각해 보아야 합니다. numpy와 gevent가 들어 있는 122 MB 설치는, 실제로 필요한 것이 “브라우저를 구동하고 몇 개 필드를 긁어오는 것”뿐이라면 슬림한 컨테이너에 넣기엔 꽤 큰 편입니다. 집중형 드라이버는 주변 plumbing을 직접 작성하는 대가로 훨씬 작은 무게로 자동화를 제공합니다. 그리고 제가 일부러 테스트하지 않은 안티 디텍션 효과를 판단해야 한다면, 이 도구는 아예 피하는 편이 맞습니다. 제가 확인도 반박도 하지 않은 마케팅 주장에 의존하게 되니까요.

대안과 Thunderbit의 위치

먼저 솔직한 프레이밍부터 하겠습니다. Botasaurus는 무료이고, MIT 라이선스이며, 셀프 호스팅입니다. 인프라는 여러분이 운영하고, 업데이트도 여러분이 관리하고, 전체 의존성 트리 — 44개 패키지 전부 — 를 여러분이 책임집니다. 패치, 라이선스 준수, 그리고 미래 버전에서 numpy가 무엇을 할지까지 포함해서요. 많은 팀에게는 이런 소유권이 바로 원하는 것이고, 단순 원가만 놓고 보면 관리형 서비스보다 “이미 가지고 있는 프레임워크”가 낫습니다.

오픈소스 안에서의 비교는 형태로 보는 것이 좋습니다. Botasaurus처럼 프레임워크 쪽에 있다면 Scrapy와 Crawlee가 먼저 비교 대상입니다. 둘 다 성숙했고, 의견이 분명하며, 각자 관례를 갖고 있습니다. 페이지에서 크롤러의 구조가 아니라 LLM-ready Markdown만 뽑고 싶다면 Crawl4AI와 콘텐츠 중심 도구인 Trafilatura가 더 직접적입니다. Python과 안티 디텍트 감성을 유지하되 메타 패키지보다 가벼운 쪽을 원한다면 Scrapling을 볼 만하고, 컴파일된 언어가 가능하다면 Go 라이브러리 Colly는 JavaScript 렌더링을 포기하는 대신 속도와 아주 작은 footprint를 얻습니다. Botasaurus를 포함한 어떤 브라우저 구동형 옵션이든, Playwright와 Puppeteer 비교에서 설명한 비용 구조를 그대로 물려받습니다. 실제 브라우저는 돌리는 비용이 결코 싸지 않습니다. 이것이 바로 주변 프레임워크가 무게를 가지는 이유입니다.

관리형 API는 같은 파이프라인의 다른 지점에 있습니다. Botasaurus가 셀프 호스팅 개발 스택이라면, Thunderbit는 같은 개발자를 겨냥한 관리형 스택을 판매합니다. Open API는 두 개의 엔드포인트로 구성됩니다. POST /distill(1 크레딧)은 렌더링과 안티봇 처리를 서버 측에서 맡기고 페이지를 깔끔한 LLM-ready Markdown으로 돌려줍니다. 브라우저도, 의존성 트리도 따로 준비할 필요가 없습니다. POST /extract(20 크레딧)은 사용자가 정의한 JSON Schema를 기준으로 구조화된 JSON을 반환하며, 페이지가 실제로 필요한 브라우저 수준에 따라 renderModenone, basic, full로 설정할 수 있습니다. 두 엔드포인트 모두 최대 100개 URL까지 한 번에 처리하는 배치 버전이 있습니다. 에이전트와 코딩 어시스턴트를 위한 MCP 서버도 있고, thunderbit_suggest_fields는 무료로 페이지가 어떤 필드를 드러내는지 미리 알려주므로 비용을 쓰기 전에 살펴볼 수 있습니다. 크론과 CI용으로는 npx @thunderbit/thunderbit-cli를 통한 CLI도 제공합니다. 이런 것들을 건드리고 싶지 않은 비개발자라면 Chrome 확장 프로그램이 노코드 도구로 같은 엔진을 실행합니다. 또한 Thunderbit YouTube 채널에는 흔히 쓰는 워크플로우에 대한 설명이 잘 정리되어 있습니다.

결국 차이는 어떤 도구가 더 좋은가가 아니라, 일이 어디에 놓이느냐입니다. Botasaurus는 프레임워크, 브라우저 플릿, 의존성, 인프라, 유지보수를 전부 사용자의 선 안쪽에 둡니다. 요청당 벤더 비용은 없지만, 컴퓨트, 대역폭, 프록시, 운영 비용은 여전히 듭니다. 관리형 API는 렌더링과 스키마 형태의 출력을 대신 처리해 주고, 호출당 과금을 합니다. 이건 가격 페이지에서 셀프 호스팅 구조와 직접 비교해 볼 수 있습니다.

웹 데이터 추출을 위해 Thunderbit 사용해 보기

결론

한 번에 다 해결되는 Python 프레임워크를 원하고, 그 의존성 footprint를 감당할 수 있다면 Botasaurus는 충분히 괜찮은 후보입니다. 세 데코레이터 설계는 깔끔하고, 드라이버 표면도 넓으며, 분류 목록보다 새로운 Python 버전에서도 설치와 import 스모크 테스트를 통과했습니다. 제 로컬 fixture에서는 기본 스냅샷이 load 후 300ms에 주입된 콘텐츠도 잡아냈고, 다른 테스트 스택들은 100ms에서 놓쳤습니다. 다만 그것은 fixture 결과일 뿐 일반적 순위는 아닙니다.

하지만 주장도 정확하게 봐야 합니다. 이건 122 MB, 44개 패키지짜리 설치입니다. 드라이버는 약 4 MB이고, 나머지는 numpy, lxml, gevent 등이 차지합니다. 집중형 드라이버보다 대략 7배 무거우며, 그 무게는 컨테이너 이미지와 콜드 배포 시간에 그대로 반영됩니다. 0.08 ms짜리 최상위 import는 가벼운 프레임워크의 증거가 아니라, 비어 있는 현관문일 뿐입니다. 실제로 비용을 치르는 건 약 135 ms짜리 엔진 import입니다. 관대한 기본 읽기는 네비게이션마다 약 250 ms를 더 씁니다. 그리고 제가 실제로 답할 수 있었던 기본 노출 측면에서는 마케팅보다 이야기가 훨씬 좁습니다. stock Puppeteer와 다른 불리언 하나만 달라졌고, headless user-agent는 여전히 HeadlessChrome라고 말하며, 제가 측정한 다른 속성은 모두 네 스택에서 동일했습니다. 이 도구를 팔아 주는 안티 디텍션 문구는 이번 리뷰가 점수를 매기지 않은 부분입니다. 메서드가 존재한다는 것, 제가 제 머신의 페이지에서 드라이버를 구동해 보았다는 것, 거기까지만 확인하고 일부러 멈췄습니다. footprint는 알고, 달콤하게 들리는 import 숫자는 무시하고, stealth 마케팅은 열린 질문으로 남겨 둔다면, Botasaurus는 프레임워크가 하는 일을 정확히 해 주는 무난한 도구입니다. featherweight 드라이버를 기대했다면 docker build 시간에서 놀랄 수 있습니다.

웹 데이터 추출을 위해 Thunderbit 사용해 보기 Get Started Free

FAQ

Botasaurus는 무료인가요, 그리고 어떤 라이선스인가요? 네, 무료이고 MIT 라이선스입니다. botasaurus 메타 패키지와 botasaurus-driver 엔진 모두 OSI 승인 MIT 분류를 가지고 있습니다. MIT는 관대하므로 카피레프트 의무가 없고 상용 사용에도 친화적입니다. 이는 AGPL-3.0으로 배포되는 유사한 안티 디텍트 드라이버와 비교할 때 꽤 큰 차이입니다. 다만 한 가지 주의할 점이 있습니다. MIT는 Omkar Cloud가 만든 자체 패키지에 적용되는 것이지, 설치 과정에서 함께 들어오는 약 40개의 전이 의존성까지 자동으로 보증하는 것은 아닙니다. 따라서 회사 차원의 전체 트리 도입 전에 자체 라이선스 스캔을 돌리는 것이 좋습니다.

Botasaurus 설치 용량은 얼마나 되며, 왜 import botasaurus는 즉시 끝나는 것처럼 보이나요? 깨끗한 상태에서 pip install botasaurus를 하면 제 환경에서는 44개 패키지에 걸친 122.3 MB의 site-packages 트리가 생겼습니다. 브라우저 드라이버 자체는 약 4 MB뿐이고, 무게는 폭넓은 의존성 트리를 끌고 들어오는 메타 패키지에서 나옵니다. 대표적인 것은 numpy(30.9 MB), lxml(19.2 MB), botasaurus_requests(12.6 MB), gevent(11.3 MB), pygments(8.4 MB)입니다. 같은 머신에서 보면 nodriver 같은 집중형 드라이버보다 대략 7배 무겁습니다. 이것은 결함이 아니라 “배터리 포함”의 비용이며, 컨테이너 이미지 크기에서 가장 크게 체감됩니다. import 시간이 footprint를 숨기고 있습니다. import botasaurus는 약 0.08 ms로 측정되지만, 그 이유는 최상위 패키지가 거의 비어 있기 때문입니다. __version__도 없고 공개 이름도 거의 없어서 import가 할 일이 거의 없습니다. 실제 비용이 드는 import는 엔진인 from botasaurus_driver import Driver로, 약 135 ms가 걸리고, 그 뒤 브라우저가 뜨기 전 기준 resident memory는 29–30 MB 정도입니다. 서버리스 콜드 스타트를 계산하려면, 빈 최상위 import가 아니라 엔진 import를 재야 합니다.

Botasaurus는 자기 자신에 대해 무엇을 드러내며, 실제 안티봇 시스템과는 테스트했나요? 앞부분은 측정했고, 뒷부분은 의도적으로 하지 않았습니다. 127.0.0.1에서 서빙한 페이지에 같은 Chrome 빌드로 접속했을 때 navigator.webdriverfalse로 나옵니다. stock Playwright와 stock Puppeteer는 둘 다 true를 보고합니다. 이 값은 속성을 패치해서 만든 것이 아니라 브라우저 시작 시점에 설정된 것입니다. descriptor는 여전히 Chrome의 native getter입니다. 이 불리언 외에는 거의 모든 항목이 비교군과 정확히 일치했습니다. platform 문자열, 5개 플러그인, 12개 코어, 16 GB 보고 메모리, window.chrome의 형태, Permissions API의 일치, 그리고 documentwindow에 남은 cdc_ 스타일 흔적도 없었습니다. headless 실행에서는 user-agent에 여전히 HeadlessChrome/151.0.0.0이 찍히며, stock controls와 같습니다. Driver 생성자는 user_agent 파라미터를 받지만, 기본값은 아무것도 해 주지 않습니다. 효과에 대해서는 어떻냐고요? 저는 라이브 사이트에 드라이버를 한 번도 대보지 않았고, 안티봇 서비스에 접속하지도 않았으며, CAPTCHA도 건드리지 않았습니다. 드라이버에는 안티 디텍션 이름이 붙은 메서드 묶음이 있고 존재는 확인했지만, 어떤 타깃에서도 호출하지 않았고, 동작을 시험하지 않았고, 성공률도 측정하지 않았으며, 메커니즘도 설명하지 않았습니다. 위의 노출 표는 스택이 무엇을 말하는지 보여 줄 뿐, 누가 듣는지 또는 그에 대해 무엇을 하는지는 말해 주지 않습니다.

Botasaurus는 JavaScript로 렌더링되는 콘텐츠를 제대로 처리하나요? 네, 기본값은 생각보다 관대합니다. 세 개의 콘텐츠 클래스가 있는 fixture에서 driver.get()driver.page_html을 바로 읽으면 800ms 주입 지연 기준으로 3개 중 2개만 잡힙니다. JavaScript는 제대로 실행하지만, 아주 늦게 들어오는 콘텐츠는 읽기 전에 지나가 버립니다. 반면 driver.wait_for_element()를 쓰면 3개 중 3개를 모두 얻습니다. 핵심 차이는 기본 읽기가 어디서 멈추느냐입니다. Botasaurus는 load 후 300ms에 주입된 콘텐츠를 아직 잡아내지만, nodriver·Playwright·Puppeteer는 모두 100ms에서 놓칩니다. 그 이유는 생성자의 wait_for_complete_page_load=True이고, 대가로 네비게이션당 약 250ms가 더 듭니다.

Botasaurus를 설치한 뒤 실제로 어떻게 import하고 사용하나요? 아마 생각하시는 방식과는 조금 다릅니다. 최상위 botasaurus 네임스페이스가 거의 비어 있기 때문에 실제 API는 서브모듈에 있습니다. from botasaurus.browser import browser, Driver, from botasaurus.request import request, from botasaurus.task import task처럼 가져와야 합니다. 일반 함수를 @browser, @request, @task로 데코레이션하면 프레임워크가 주변의 드라이버, 캐싱, 출력 처리를 맡습니다. botasaurus.__version__은 없으니, 실행 중인 빌드를 로그에 남기고 싶다면 importlib.metadata를 사용해야 합니다.

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

1회 클릭 안에 어떤 페이지든 데이터 추출

250,000명+ 사용자가 신뢰
무료 플랜 제공
웹페이지에서 스프레드시트까지
필요한 내용을 설명하세요 — Thunderbit의 AI Agent가 수집하고 Excel, Google Sheets, Airtable, Notion으로 내보냅니다. 시작은 무료입니다.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week