browser-use: AI 에이전트가 웹 브라우저를 자유자재로 다루는 시대

browser-use: AI 에이전트가 웹 브라우저를 자유자재로 다루는 시대

웹 브라우저 자동화라고 하면 보통 Playwright나 Selenium으로 셀렉터를 하나하나 잡아가며 스크립트를 짜는 모습이 떠오릅니다. 버튼 위치가 바뀌면 셀렉터도 고쳐야 하고, 페이지마다 로딩 타이밍이 달라서 wait_for 코드를 여기저기 넣어야 하죠. 이런 작업이 번거로워서 “AI한테 그냥 시키면 안 되나?”라고 한 번쯤 생각해보신 적 있을 겁니다.

browser-use는 바로 그 발상에서 출발한 오픈소스 Python 라이브러리입니다. 자연어로 “해커뉴스에서 오늘의 인기 글 5개를 찾아줘”라고 지시하면 LLM이 직접 브라우저를 열고 페이지를 탐색하고 데이터를 뽑아옵니다. CSS 셀렉터도, XPath도 쓸 필요가 없어요.

GitHub 스타가 8만 개를 넘기며 AI 브라우저 자동화 분야에서 가장 주목받는 프로젝트가 된 browser-use를 설치부터 실전 활용까지 차근차근 살펴보겠습니다.

어떻게 동작하는 걸까?

browser-use는 크게 브라우저 제어, 페이지 해석, LLM 에이전트라는 세 레이어로 동작합니다.

맨 아래에는 Playwright 기반 브라우저 제어가 있습니다. 실제 Chromium을 띄워서 JavaScript가 잔뜩 들어간 SPA든 로그인이 필요한 페이지든 가리지 않고 처리해요.

그 위에 페이지 해석 레이어가 올라갑니다. 현재 페이지의 DOM에서 클릭 가능한 버튼이나 입력 필드, 링크를 뽑아내서 각각에 번호를 매기는 역할이에요. 원본 HTML을 통째로 LLM에 보내면 토큰이 너무 많이 소비되니까 핵심만 압축합니다. 멀티모달 모델을 쓰면 스크린샷도 함께 보내서 페이지를 시각적으로 파악할 수 있고요.

마지막으로 LLM 에이전트가 이 정보를 받아서 다음 행동을 결정합니다. “요소 [15]를 클릭한다”, “검색창에 텍스트를 입력한다” 같은 액션을 골라 실행하고 결과를 다시 관찰하는 루프를 반복하죠. 이 사이클이 작업 완료까지 계속됩니다.

결국 개발자는 “무엇을 해야 하는지”만 알려주면 되고 “어떻게 해야 하는지”는 LLM이 알아서 풀어나갑니다.

설치하기

Python 3.11 이상이 필요합니다. uv를 사용하면 가상환경 생성과 패키지 설치를 한 번에 할 수 있어요.

pip install uv
uv venv --python 3.12
source .venv/bin/activate

browser-use 패키지를 설치하고 브라우저 바이너리도 함께 받아줍니다.

uv pip install browser-use
uvx browser-use install

browser-use install 명령이 Chromium을 다운로드하는데, 처음 한 번만 실행하면 됩니다.

첫 번째 에이전트 만들기

가장 간단한 예제부터 시작해볼까요? .env 파일에 사용할 LLM 제공자의 API 키를 넣어두고 다음 코드를 실행합니다.

from browser_use import Agent, Browser, ChatBrowserUse
import asyncio

async def main():
    browser = Browser()
    agent = Agent(
        task="해커뉴스에서 Show HN 섹션의 1위 글 제목을 찾아줘",
        llm=ChatBrowserUse(),
        browser=browser,
    )
    result = await agent.run()
    print(result)

asyncio.run(main())

Agent에 자연어 taskllm을 넘기고 run()을 호출하면 끝입니다. 에이전트가 알아서 해커뉴스에 접속하고 Show HN 탭을 클릭한 뒤 첫 번째 글의 제목을 뽑아옵니다.

ChatBrowserUse()는 browser-use 팀에서 제공하는 전용 모델인데요, 브라우저 자동화에 최적화되어 있어서 다른 범용 모델보다 3~5배 빠르다고 합니다. 물론 다른 모델도 자유롭게 쓸 수 있어요.

다양한 LLM 연동하기

browser-use의 큰 장점 중 하나는 특정 LLM에 종속되지 않는다는 점입니다. OpenAI, Anthropic, Google 등 원하는 모델을 골라 쓸 수 있어요.

# Anthropic Claude
from browser_use import Agent, ChatAnthropic

llm = ChatAnthropic(model="claude-sonnet-4-0", temperature=0.0)
agent = Agent(task="GitHub 트렌딩 페이지에서 오늘의 1위 저장소를 찾아줘", llm=llm)
await agent.run()
# OpenAI GPT
from browser_use import Agent, ChatOpenAI

llm = ChatOpenAI(model="gpt-4o")
agent = Agent(task="GitHub 트렌딩 페이지에서 오늘의 1위 저장소를 찾아줘", llm=llm)
await agent.run()
# Google Gemini
from browser_use import Agent, ChatGoogleGenerativeAI

llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash")
agent = Agent(task="GitHub 트렌딩 페이지에서 오늘의 1위 저장소를 찾아줘", llm=llm)
await agent.run()

로컬에서 돌리는 오픈소스 모델도 사용할 수 있습니다. Ollama로 모델을 실행하고 연결하면 API 비용 없이 browser-use를 쓸 수 있죠.

# Ollama 로컬 모델
from langchain_ollama import ChatOllama
from browser_use import Agent

llm = ChatOllama(model="qwen3:8b", num_ctx=32000)
agent = Agent(task="Wikipedia에서 Python 프로그래밍 언어 문서를 찾아 첫 문단을 요약해줘", llm=llm)
await agent.run()

다만 모델에 따라 성능 차이가 꽤 나요. GPT-4o나 Claude Sonnet 같은 대형 모델은 복잡한 다단계 작업도 잘 처리하지만 소형 모델은 간단한 탐색이나 데이터 추출 정도가 적당합니다.

브라우저 설정 조정하기

기본적으로 browser-use는 헤드리스 모드로 실행되어 브라우저 창이 보이지 않습니다. 에이전트가 뭘 하고 있는지 눈으로 확인하고 싶다면 headless=False로 바꿔주면 됩니다.

from browser_use import Agent, Browser, ChatBrowserUse

browser = Browser(
    headless=False,
    window_size={"width": 1280, "height": 720},
)

agent = Agent(
    task="아마존에서 맥북 에어 가격을 검색해줘",
    llm=ChatBrowserUse(),
    browser=browser,
)

await agent.run()
await browser.close()

이미 열려 있는 Chrome 브라우저에 연결하는 것도 가능합니다. 로그인해둔 사이트가 있다면 쿠키와 세션을 그대로 활용할 수 있어서 편리해요. CLI에서 browser-use --connectbrowser-use --profile 명령으로 실행 중인 Chrome에 붙을 수 있습니다.

커스텀 도구 만들기

browser-use가 진짜 강력해지는 건 커스텀 도구를 추가할 때입니다. 에이전트의 기본 액션(클릭, 입력, 스크롤 등)만으로는 부족한 경우가 있거든요. 예를 들어 수집한 데이터를 파일로 저장하거나, 외부 API를 호출하거나, 사람에게 확인을 받아야 할 때요.

@tools.action() 데코레이터로 함수를 등록하면 에이전트가 필요할 때 알아서 호출합니다.

from browser_use import Tools, Agent, ActionResult, ChatBrowserUse

tools = Tools()

@tools.action(description="수집한 데이터를 JSON 파일로 저장합니다")
def save_to_json(data: str, filename: str) -> str:
    import json
    with open(filename, "w") as f:
        f.write(data)
    return f"{filename}에 저장 완료"

agent = Agent(
    task="해커뉴스 상위 5개 글의 제목과 URL을 수집해서 hn_top5.json으로 저장해줘",
    llm=ChatBrowserUse(),
    tools=tools,
)

await agent.run()

사람 확인이 필요한 작업이라면 human-in-the-loop 패턴도 가능합니다.

@tools.action(description="사람에게 질문하고 답변을 받습니다")
async def ask_human(question: str) -> ActionResult:
    answer = input(f"{question} > ")
    return ActionResult(extracted_content=f"사람의 답변: {answer}")

에이전트가 판단이 어려운 상황에 부딪히면 이 도구를 호출해서 사람에게 물어봅니다. 민감한 작업을 자동화할 때 안전장치로 활용하기 좋죠.

커스텀 도구에서 브라우저 세션에 직접 접근하고 싶다면 browser_session 파라미터를 받으면 됩니다.

from browser_use import BrowserSession

@tools.action(description="특정 CSS 셀렉터의 요소를 클릭합니다")
async def click_by_selector(selector: str, browser_session: BrowserSession) -> ActionResult:
    page = await browser_session.must_get_current_page()
    elements = await page.get_elements_by_css_selector(selector)
    if not elements:
        return ActionResult(extracted_content="요소를 찾지 못했습니다")
    await elements[0].click()
    return ActionResult(extracted_content="클릭 완료!")

여기서 주의할 점이 하나 있는데요. 파라미터 이름이 반드시 browser_session이어야 합니다. browser-use가 이름 기반으로 의존성을 주입하기 때문에 browsersession 같은 다른 이름을 쓰면 주입이 안 됩니다.

보안이 중요한 도구라면 allowed_domains 옵션으로 특정 도메인에서만 실행되도록 제한할 수도 있어요.

@tools.action(
    description="뱅킹 폼을 작성합니다",
    allowed_domains=["https://mybank.com"],
)
def fill_bank_form(account_number: str) -> str:
    return f"계좌 {account_number} 폼 작성 완료"

Pydantic으로 구조화된 데이터 받기

웹에서 수집한 데이터를 깔끔하게 다루고 싶다면 Pydantic 모델이 좋습니다. 커스텀 도구의 파라미터 타입에 Pydantic 모델을 지정해두면 에이전트가 알아서 그 형태에 맞춰 데이터를 넘겨줘요.

from pydantic import BaseModel, Field

class Product(BaseModel):
    name: str = Field(description="상품명")
    price: int = Field(description="가격 (원 단위 정수)")
    url: str = Field(description="상품 페이지 URL")

@tools.action(description="상품 목록을 파일로 저장합니다")
def save_products(products: list[Product]) -> str:
    import json
    with open("products.json", "w") as f:
        json.dump([p.model_dump() for p in products], f, ensure_ascii=False)
    return f"{len(products)}개 상품 저장 완료"

LLM이 웹 페이지에서 데이터를 추출할 때 Product 스키마에 맞춰 파싱하고 타입 검증까지 자동으로 해줍니다. 문자열 파싱 코드를 직접 짜야 했던 옛날 스크래핑에 비하면 한결 편하죠.

CLI로 빠르게 테스트하기

코드를 짜기 전에 빠르게 실험해보고 싶을 때가 있죠. browser-use는 터미널에서 바로 브라우저를 조작할 수 있는 CLI도 제공합니다.

browser-use open https://news.ycombinator.com
browser-use state          # 현재 페이지 상태 확인
browser-use click 15       # 15번 요소 클릭
browser-use type "search query"  # 텍스트 입력
browser-use screenshot     # 스크린샷 촬영
browser-use close          # 브라우저 닫기

CLI가 명령어 사이에 브라우저를 계속 열어두기 때문에 반복 작업할 때 빠릅니다. AI 코딩 에이전트와 함께 사용하면 Claude Code나 Cursor 같은 도구가 CLI 명령어를 통해 브라우저를 조작할 수도 있어요.

기존 자동화 도구와 뭐가 다를까?

이미 Playwright나 Selenium 같은 훌륭한 자동화 도구가 있는데 browser-use를 써야 할 이유가 있을까요?

가장 큰 차이는 셀렉터 없이 동작한다는 점입니다. Playwright로 버튼을 클릭하려면 page.click('button.submit') 같은 셀렉터를 정확히 알아야 합니다. 사이트가 리뉴얼되면 셀렉터가 바뀌어서 스크립트가 깨지죠. browser-use는 LLM이 페이지를 이해하고 “제출 버튼”을 스스로 찾아서 클릭하기 때문에 사이트 구조가 좀 바뀌어도 적응할 수 있습니다.

반면 trade-off도 분명해요. LLM 추론이 매 단계마다 들어가니까 한 액션당 2~5초가 걸리고 API 호출 비용도 발생합니다. 간단한 작업도 5~20단계가 필요할 수 있고 복잡한 작업은 수십 단계를 거치면서 토큰이 꽤 소비되죠.

그래서 실무에서는 섞어 쓰는 경우가 많습니다. 예측 가능한 반복 작업 80%는 Playwright 스크립트로 빠르게 돌리고 페이지 구조가 자주 바뀌거나 복잡한 판단이 필요한 20%만 browser-use에 맡기는 거예요.

browser-use가 빛을 발하는 상황을 정리하면 이렇습니다.

  • 한 번만 하면 되는 데이터 수집이나 리서치 작업
  • 아직 구조를 파악하지 못한 새로운 사이트 탐색
  • 로그인 → 메뉴 이동 → 폼 작성 같은 긴 상호작용 시퀀스
  • 정확한 셀렉터를 짜는 것보다 자연어로 설명하는 게 빠른 경우

반대로 대량의 반복 스크래핑, 비용에 민감한 프로덕션 파이프라인, 100% 결정적(deterministic)인 결과가 필요한 테스트에는 전통적인 Playwright가 여전히 나은 선택입니다.

비용과 성능 최적화

browser-use를 실제로 운영하다 보면 비용과 속도가 제일 신경 쓰입니다. 매 단계마다 LLM API 호출이 일어나고 페이지 상태를 컨텍스트로 보내야 하니까요. 토큰 소비가 만만치 않아요.

max_steps 파라미터로 최대 단계 수를 제한해두면 작업이 꼬였을 때 토큰이 끝없이 빠져나가는 걸 막을 수 있습니다.

agent = Agent(
    task="...",
    llm=llm,
    max_steps=25,  # 기본값 100에서 줄여서 비용 제한
)
await agent.run()

모델 선택도 빼놓을 수 없어요. 간단한 탐색이나 데이터 추출에는 Gemini Flash 같은 가벼운 모델로 비용을 줄이고, 복잡한 다단계 작업에만 GPT-4o나 Claude Sonnet을 투입하는 식으로 나누면 됩니다.

마치며

browser-use는 브라우저 자동화의 진입 장벽을 많이 낮춰줍니다. 셀렉터를 일일이 잡고 타이밍을 맞추는 대신 자연어로 원하는 작업을 설명하면 LLM이 알아서 해결해주니까요. 커스텀 도구와 Pydantic 모델까지 조합하면 단순한 페이지 탐색을 넘어 데이터 수집 파이프라인도 만들 수 있습니다.

비용과 속도라는 현실적인 제약이 있고 LLM의 판단이 늘 완벽하지는 않습니다. 그래도 “셀렉터 짜는 시간보다 말로 설명하는 게 빠른” 상황이라면 한번 써볼 만해요. 프로토타이핑이나 일회성 리서치부터 시작해서 감을 잡아보시길 추천합니다.

이전에 소개한 agent-browser를 활용한 CLI 기반 브라우저 제어Playwright MCP를 활용한 AI 에이전트 브라우저 자동화와 함께 비교해보면 각 도구의 특성과 적합한 사용처를 더 잘 파악할 수 있을 거예요.

더 자세한 내용은 browser-use 공식 문서를 참고하세요.

This work is licensed under CC BY 4.0 CC BY

개발자를 위한 뉴스레터

달레가 정리한 AI 개발 트렌드와 직접 만든 콘텐츠를 전해드립니다.

Discord