BrowserOS: AI 에이전트 기반 오픈소스 웹 브라우저 완전 가이드
⏱️ 예상 읽기 시간: 18분
서론
웹 브라우저도 AI 시대에 맞춰 진화해야 한다면? BrowserOS는 바로 그 답입니다. 1994년 넷스케이프 이후 처음으로 브라우저를 처음부터 다시 상상하여, AI 에이전트 기반의 완전히 새로운 웹 브라우징 경험을 제공합니다.
70개 이상의 탭을 열어두고 브라우저와 싸우는 대신, “아마존 주문 내역에서 타이드 팟 주문해줘” 같은 간단한 명령으로 AI 에이전트가 자동으로 작업을 처리하게 할 수 있습니다.
BrowserOS의 혁신적 특징
🤖 AI 에이전트 중심 설계
BrowserOS는 AI 에이전트가 웹을 자동으로 탐색하고 작업을 수행하도록 설계되었습니다:
전통적 브라우저:
사용자 → 수동 클릭/타이핑 → 웹페이지
BrowserOS:
사용자 → AI 에이전트 → 자동 웹 작업 완료
🔒 로컬 및 보안 우선
- 모든 AI 처리가 로컬에서 실행
- 개인 데이터가 외부로 전송되지 않음
- 검색이나 광고 회사의 제품이 되지 않음
🚀 현대적 기능들
- MCP(Model Context Protocol) 지원
- 로컬 AI 채팅 통합
- 생산성 도구 내장
- 100% 오픈소스 (AGPL-3.0)
설치 및 환경 설정
시스템 요구사항
# 지원 운영체제
- macOS 10.15+
- Ubuntu 20.04+
- Windows 10+
# Python 요구사항
- Python 3.8 이상
- pip 패키지 관리자
# 하드웨어 권장사항
- RAM: 8GB 이상
- 디스크: 2GB 여유 공간
- GPU: CUDA 지원 GPU (선택사항, AI 가속용)
BrowserOS 설치
방법 1: GitHub 릴리스에서 설치
# 최신 릴리스 다운로드
curl -L https://github.com/browseros-ai/BrowserOS/releases/latest/download/browseros-installer.sh | bash
# 또는 수동 다운로드
wget https://github.com/browseros-ai/BrowserOS/releases/latest/download/browseros-linux.tar.gz
tar -xzf browseros-linux.tar.gz
cd browseros
./install.sh
방법 2: 소스 코드에서 빌드
# 리포지토리 클론
git clone https://github.com/browseros-ai/BrowserOS.git
cd BrowserOS
# Python 가상환경 생성
python -m venv browseros-env
source browseros-env/bin/activate # Windows: browseros-env\Scripts\activate
# 의존성 설치
pip install -r requirements.txt
# BrowserOS 실행
python main.py
방법 3: Docker로 실행
# Docker 이미지 빌드
docker build -t browseros .
# 컨테이너 실행
docker run -p 8080:8080 -v $(pwd)/data:/app/data browseros
# 브라우저에서 http://localhost:8080 접속
초기 설정
1. 환경 변수 설정
# .env 파일 생성
cat > .env << EOF
# AI 모델 설정
OPENAI_API_KEY=your_openai_key_here
ANTHROPIC_API_KEY=your_anthropic_key_here
# 로컬 AI 모델 설정 (Ollama 사용 시)
OLLAMA_HOST=http://localhost:11434
LOCAL_MODEL=llama3.2
# BrowserOS 설정
BROWSER_PROFILE_PATH=./profiles
DEBUG_MODE=true
LOG_LEVEL=INFO
# MCP 설정
MCP_SERVER_PORT=3000
MCP_ENABLED=true
EOF
2. 로컬 AI 모델 설정 (Ollama)
# Ollama 설치 (macOS)
brew install ollama
# Ollama 설치 (Linux)
curl -fsSL https://ollama.ai/install.sh | sh
# 모델 다운로드
ollama pull llama3.2
ollama pull qwen2.5:7b
# Ollama 서버 시작
ollama serve
3. 설정 파일 확인
# config.py 예제
import os
from pathlib import Path
class BrowserOSConfig:
# 기본 설정
APP_NAME = "BrowserOS"
VERSION = "0.18.0"
# AI 설정
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY")
OLLAMA_HOST = os.getenv("OLLAMA_HOST", "http://localhost:11434")
LOCAL_MODEL = os.getenv("LOCAL_MODEL", "llama3.2")
# 브라우저 설정
BROWSER_PROFILE_PATH = Path(os.getenv("BROWSER_PROFILE_PATH", "./profiles"))
DEFAULT_USER_AGENT = "BrowserOS/0.18.0 (AI-Powered Browser)"
# MCP 설정
MCP_SERVER_PORT = int(os.getenv("MCP_SERVER_PORT", 3000))
MCP_ENABLED = os.getenv("MCP_ENABLED", "true").lower() == "true"
# 보안 설정
ALLOW_INSECURE_CONNECTIONS = False
SANDBOX_MODE = True
# 디버그 설정
DEBUG_MODE = os.getenv("DEBUG_MODE", "false").lower() == "true"
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
config = BrowserOSConfig()
기본 사용법
1. BrowserOS 시작하기
# 기본 실행
from browseros import BrowserOS
import asyncio
async def main():
# BrowserOS 인스턴스 생성
browser = BrowserOS(
headless=False, # GUI 모드
profile_path="./my_profile"
)
# 브라우저 시작
await browser.start()
# 기본 페이지 로드
await browser.navigate("https://example.com")
print("BrowserOS가 성공적으로 시작되었습니다!")
# 브라우저 종료
# await browser.close()
# 실행
asyncio.run(main())
2. AI 에이전트와 상호작용
# AI 에이전트 기본 사용
from browseros.agents import WebAgent
from browseros.models import LocalAIModel
async def ai_browsing_example():
# 로컬 AI 모델 초기화
ai_model = LocalAIModel(
model_name="llama3.2",
host="http://localhost:11434"
)
# 웹 에이전트 생성
agent = WebAgent(
browser=browser,
ai_model=ai_model,
verbose=True
)
# AI 에이전트에게 작업 요청
result = await agent.execute_task(
"Google에서 'Python 튜토리얼'을 검색하고 첫 번째 결과를 열어줘"
)
print(f"작업 결과: {result.success}")
print(f"수행한 작업: {result.actions}")
print(f"최종 URL: {result.final_url}")
asyncio.run(ai_browsing_example())
3. 웹 페이지 스크래핑
# 고급 웹 스크래핑
from browseros.scrapers import SmartScraper
async def scraping_example():
scraper = SmartScraper(browser=browser)
# 특정 웹페이지에서 데이터 추출
await browser.navigate("https://news.ycombinator.com")
# AI를 사용한 스마트 스크래핑
data = await scraper.extract_data(
instruction="뉴스 제목, 점수, 댓글 수를 추출해줘",
format="json"
)
print("추출된 데이터:")
for item in data:
print(f"- {item['title']} (점수: {item['score']})")
asyncio.run(scraping_example())
고급 기능 활용
1. 자동화 스크립트 작성
# automation_scripts.py
from browseros.automation import AutomationScript
from browseros.selectors import SmartSelector
class AmazonOrderScript(AutomationScript):
"""아마존 자동 주문 스크립트"""
def __init__(self, browser, ai_model):
super().__init__(browser, ai_model)
self.name = "Amazon Auto Order"
self.description = "아마존에서 자동으로 상품을 주문합니다"
async def execute(self, product_name: str):
"""상품 자동 주문 실행"""
try:
# 1. 아마존 접속
await self.browser.navigate("https://amazon.com")
# 2. 로그인 확인
if not await self.is_logged_in():
await self.login()
# 3. 상품 검색
search_result = await self.search_product(product_name)
# 4. 상품 선택 및 주문
order_result = await self.place_order(search_result)
return {
"success": True,
"order_id": order_result.order_id,
"total_price": order_result.total_price
}
except Exception as e:
return {
"success": False,
"error": str(e)
}
async def is_logged_in(self):
"""로그인 상태 확인"""
selector = SmartSelector(self.ai_model)
login_elements = await selector.find_elements(
"로그인 버튼 또는 계정 메뉴"
)
# AI가 페이지를 분석하여 로그인 상태 판단
analysis = await self.ai_model.analyze_page(
"이 페이지에서 사용자가 로그인된 상태인지 확인해줘"
)
return "로그인됨" in analysis.result
async def login(self):
"""자동 로그인"""
# 로그인 페이지로 이동
await self.browser.click("a[href*='signin']")
# 로그인 정보 입력 (환경변수에서 가져오기)
await self.browser.type("#ap_email", os.getenv("AMAZON_EMAIL"))
await self.browser.click("#continue")
await self.browser.type("#ap_password", os.getenv("AMAZON_PASSWORD"))
await self.browser.click("#signInSubmit")
# 로그인 완료 대기
await self.browser.wait_for_selector("#nav-link-accountList")
async def search_product(self, product_name):
"""상품 검색"""
# 검색 박스에 상품명 입력
await self.browser.type("#twotabsearchtextbox", product_name)
await self.browser.click("#nav-search-submit-button")
# AI가 최적의 상품 선택
best_product = await self.ai_model.select_best_product(
instruction=f"{product_name}에 가장 적합한 상품을 선택해줘",
criteria=["평점", "가격", "리뷰 수", "브랜드"]
)
return best_product
async def place_order(self, product):
"""주문 진행"""
# 상품 페이지로 이동
await self.browser.click(product.link)
# 장바구니에 추가
await self.browser.click("#add-to-cart-button")
# 장바구니로 이동
await self.browser.click("#nav-cart")
# 결제 진행
await self.browser.click("name='proceedToRetailCheckout'")
# 배송 주소 확인
await self.confirm_shipping_address()
# 결제 방법 확인
await self.confirm_payment_method()
# 최종 주문
order_info = await self.place_final_order()
return order_info
# 사용 예제
async def main():
browser = BrowserOS()
await browser.start()
ai_model = LocalAIModel("llama3.2")
amazon_script = AmazonOrderScript(browser, ai_model)
# "타이드 팟" 자동 주문
result = await amazon_script.execute("Tide Pods")
if result["success"]:
print(f"주문 성공! 주문번호: {result['order_id']}")
else:
print(f"주문 실패: {result['error']}")
asyncio.run(main())
2. MCP (Model Context Protocol) 통합
# mcp_integration.py
from browseros.mcp import MCPServer, MCPTool
from browseros.agents import WebAgent
class WebScrapingTool(MCPTool):
"""MCP 기반 웹 스크래핑 도구"""
def __init__(self, browser):
super().__init__(
name="web_scraping",
description="웹페이지에서 데이터를 추출합니다"
)
self.browser = browser
async def execute(self, url: str, selector: str, data_type: str = "text"):
"""웹 스크래핑 실행"""
await self.browser.navigate(url)
if data_type == "text":
result = await self.browser.extract_text(selector)
elif data_type == "html":
result = await self.browser.extract_html(selector)
elif data_type == "attributes":
result = await self.browser.extract_attributes(selector)
else:
result = await self.browser.extract_text(selector)
return {
"url": url,
"selector": selector,
"data": result,
"timestamp": datetime.now().isoformat()
}
class AutomationTool(MCPTool):
"""MCP 기반 브라우저 자동화 도구"""
def __init__(self, browser, ai_model):
super().__init__(
name="browser_automation",
description="AI 에이전트를 사용한 브라우저 자동화"
)
self.browser = browser
self.agent = WebAgent(browser, ai_model)
async def execute(self, task: str, max_steps: int = 10):
"""자동화 작업 실행"""
result = await self.agent.execute_task(
task=task,
max_steps=max_steps,
return_detailed_log=True
)
return {
"task": task,
"success": result.success,
"steps": result.steps,
"final_state": result.final_state,
"execution_time": result.execution_time
}
# MCP 서버 설정
async def setup_mcp_server():
"""MCP 서버 설정 및 시작"""
browser = BrowserOS()
await browser.start()
ai_model = LocalAIModel("llama3.2")
# MCP 서버 생성
mcp_server = MCPServer(port=3000)
# 도구 등록
web_scraping_tool = WebScrapingTool(browser)
automation_tool = AutomationTool(browser, ai_model)
mcp_server.add_tool(web_scraping_tool)
mcp_server.add_tool(automation_tool)
# 서버 시작
await mcp_server.start()
print("MCP 서버가 포트 3000에서 시작되었습니다")
# 클라이언트 사용 예제
client = MCPClient("http://localhost:3000")
# 웹 스크래핑 요청
scraping_result = await client.call_tool(
"web_scraping",
{
"url": "https://example.com",
"selector": "h1",
"data_type": "text"
}
)
print(f"스크래핑 결과: {scraping_result}")
# 자동화 요청
automation_result = await client.call_tool(
"browser_automation",
{
"task": "GitHub에 로그인하고 새 리포지토리를 만들어줘",
"max_steps": 15
}
)
print(f"자동화 결과: {automation_result}")
asyncio.run(setup_mcp_server())
3. 생산성 도구 개발
# productivity_tools.py
from browseros.productivity import ProductivitySuite
from browseros.ai import TaskPlanner
class EmailAutomation:
"""이메일 자동화 도구"""
def __init__(self, browser, ai_model):
self.browser = browser
self.ai_model = ai_model
async def process_emails(self, email_provider="gmail"):
"""이메일 자동 처리"""
if email_provider == "gmail":
await self.browser.navigate("https://mail.google.com")
# 읽지 않은 이메일 찾기
unread_emails = await self.browser.find_elements(
".zA.zE" # Gmail 읽지 않은 이메일 클래스
)
processed_emails = []
for email in unread_emails[:10]: # 최근 10개만 처리
# 이메일 열기
await self.browser.click(email)
# AI가 이메일 내용 분석
email_content = await self.browser.extract_text(".ii.gt")
analysis = await self.ai_model.analyze_email(email_content)
# 분석 결과에 따른 자동 처리
if analysis.priority == "high":
await self.handle_high_priority_email(analysis)
elif analysis.category == "newsletter":
await self.handle_newsletter(analysis)
elif analysis.requires_response:
await self.draft_response(analysis)
processed_emails.append(analysis)
# 이메일 목록으로 돌아가기
await self.browser.press("u") # Gmail 단축키
return processed_emails
async def handle_high_priority_email(self, analysis):
"""긴급 이메일 처리"""
# 별표 표시
await self.browser.press("s")
# 중요 라벨 추가
await self.browser.press("l")
await self.browser.type("중요")
await self.browser.press("Enter")
# 슬랙으로 알림 (선택사항)
if hasattr(self, 'slack_webhook'):
await self.send_slack_notification(
f"긴급 이메일 도착: {analysis.subject}"
)
async def draft_response(self, analysis):
"""응답 초안 작성"""
# 답장 버튼 클릭
await self.browser.press("r")
# AI가 응답 초안 작성
draft = await self.ai_model.generate_email_response(
original_email=analysis.content,
context=analysis.context,
tone="professional"
)
# 초안 입력
compose_field = await self.browser.find_element("[contenteditable='true']")
await self.browser.type(compose_field, draft.content)
# 초안으로 저장 (자동 발송하지 않음)
await self.browser.press("Ctrl+s")
class TaskManager:
"""작업 관리 도구"""
def __init__(self, browser, ai_model):
self.browser = browser
self.ai_model = ai_model
self.task_planner = TaskPlanner(ai_model)
async def organize_daily_tasks(self):
"""일일 작업 정리"""
tasks = []
# 다양한 소스에서 작업 수집
# 1. 이메일에서 작업 추출
email_tasks = await self.extract_tasks_from_emails()
tasks.extend(email_tasks)
# 2. 캘린더에서 일정 가져오기
calendar_tasks = await self.extract_tasks_from_calendar()
tasks.extend(calendar_tasks)
# 3. 기존 TODO 앱에서 가져오기
todo_tasks = await self.extract_tasks_from_todo_apps()
tasks.extend(todo_tasks)
# AI가 작업 우선순위 정리
organized_tasks = await self.task_planner.organize_tasks(
tasks=tasks,
time_available="8 hours",
energy_level="high",
priorities=["urgent", "important", "easy_wins"]
)
# 정리된 작업을 노션이나 트렐로에 자동 업데이트
await self.update_task_management_system(organized_tasks)
return organized_tasks
async def extract_tasks_from_emails(self):
"""이메일에서 작업 추출"""
await self.browser.navigate("https://mail.google.com")
# 최근 이메일들 스캔
emails = await self.browser.find_elements(".zA")
tasks = []
for email in emails[:20]: # 최근 20개 이메일
await self.browser.click(email)
content = await self.browser.extract_text(".ii.gt")
# AI가 이메일에서 작업 추출
extracted_tasks = await self.ai_model.extract_tasks_from_text(
text=content,
context="email"
)
tasks.extend(extracted_tasks)
await self.browser.press("u") # 뒤로가기
return tasks
class ResearchAssistant:
"""리서치 어시스턴트"""
def __init__(self, browser, ai_model):
self.browser = browser
self.ai_model = ai_model
self.research_data = []
async def conduct_research(self, topic: str, depth: str = "comprehensive"):
"""자동 리서치 수행"""
research_plan = await self.ai_model.create_research_plan(
topic=topic,
depth=depth,
sources=["academic", "news", "industry", "social"]
)
results = {}
# 1. 학술 논문 검색
academic_results = await self.search_academic_papers(topic)
results["academic"] = academic_results
# 2. 뉴스 기사 검색
news_results = await self.search_news_articles(topic)
results["news"] = news_results
# 3. 업계 리포트 검색
industry_results = await self.search_industry_reports(topic)
results["industry"] = industry_results
# 4. 소셜 미디어 동향 분석
social_results = await self.analyze_social_trends(topic)
results["social"] = social_results
# AI가 모든 결과를 종합 분석
comprehensive_analysis = await self.ai_model.synthesize_research(
topic=topic,
sources=results,
research_plan=research_plan
)
# 결과를 마크다운 리포트로 생성
report = await self.generate_research_report(
topic=topic,
analysis=comprehensive_analysis,
sources=results
)
return report
async def search_academic_papers(self, topic):
"""학술 논문 검색"""
await self.browser.navigate("https://scholar.google.com")
search_box = await self.browser.find_element("#gs_hdr_tsi")
await self.browser.type(search_box, topic)
await self.browser.press("Enter")
# 상위 논문들 분석
papers = await self.browser.find_elements(".gs_rt a")
paper_data = []
for paper in papers[:10]: # 상위 10개 논문
paper_title = await self.browser.extract_text(paper)
paper_url = await self.browser.get_attribute(paper, "href")
# 논문 초록 추출
abstract = await self.extract_paper_abstract(paper_url)
paper_data.append({
"title": paper_title,
"url": paper_url,
"abstract": abstract,
"source": "academic"
})
return paper_data
# 생산성 도구 통합 사용
async def main_productivity_demo():
"""생산성 도구 데모"""
browser = BrowserOS()
await browser.start()
ai_model = LocalAIModel("llama3.2")
# 이메일 자동화
email_automation = EmailAutomation(browser, ai_model)
processed_emails = await email_automation.process_emails()
print(f"처리된 이메일: {len(processed_emails)}개")
# 작업 관리
task_manager = TaskManager(browser, ai_model)
organized_tasks = await task_manager.organize_daily_tasks()
print(f"정리된 작업: {len(organized_tasks)}개")
# 리서치 어시스턴트
research_assistant = ResearchAssistant(browser, ai_model)
research_report = await research_assistant.conduct_research(
topic="AI in Healthcare 2025",
depth="comprehensive"
)
print(f"리서치 리포트 생성 완료: {len(research_report)} 페이지")
asyncio.run(main_productivity_demo())
실전 프로젝트: 자동화 뉴스 수집기
전체 프로젝트 구조
automated_news_collector/
├── main.py # 메인 실행 파일
├── config.py # 설정 파일
├── models/
│ ├── __init__.py
│ ├── news_item.py # 뉴스 데이터 모델
│ └── summary.py # 요약 데이터 모델
├── scrapers/
│ ├── __init__.py
│ ├── base_scraper.py # 기본 스크래퍼
│ ├── tech_scraper.py # 기술 뉴스 스크래퍼
│ └── finance_scraper.py # 금융 뉴스 스크래퍼
├── ai/
│ ├── __init__.py
│ ├── summarizer.py # AI 요약기
│ └── categorizer.py # AI 분류기
├── output/
│ ├── __init__.py
│ ├── markdown_generator.py
│ └── email_sender.py
└── requirements.txt
핵심 구현
# main.py
import asyncio
from datetime import datetime
from browseros import BrowserOS
from scrapers.tech_scraper import TechNewsScraper
from scrapers.finance_scraper import FinanceNewsScraper
from ai.summarizer import NewsSummarizer
from ai.categorizer import NewsCategorizer
from output.markdown_generator import MarkdownGenerator
from output.email_sender import EmailSender
class AutomatedNewsCollector:
def __init__(self):
self.browser = None
self.scrapers = []
self.summarizer = None
self.categorizer = None
self.output_generators = []
async def initialize(self):
"""시스템 초기화"""
# BrowserOS 시작
self.browser = BrowserOS(
headless=True, # 백그라운드 실행
profile_path="./news_collector_profile"
)
await self.browser.start()
# AI 모델 초기화
ai_model = LocalAIModel("llama3.2")
self.summarizer = NewsSummarizer(ai_model)
self.categorizer = NewsCategorizer(ai_model)
# 스크래퍼 초기화
self.scrapers = [
TechNewsScraper(self.browser, ai_model),
FinanceNewsScraper(self.browser, ai_model)
]
# 출력 생성기 초기화
self.output_generators = [
MarkdownGenerator(),
EmailSender()
]
async def collect_news(self):
"""뉴스 수집 실행"""
all_news = []
# 각 스크래퍼에서 뉴스 수집
for scraper in self.scrapers:
try:
news_items = await scraper.scrape()
all_news.extend(news_items)
print(f"{scraper.__class__.__name__}에서 {len(news_items)}개 뉴스 수집")
except Exception as e:
print(f"{scraper.__class__.__name__} 오류: {e}")
# AI로 뉴스 분류 및 요약
processed_news = []
for news in all_news:
# 뉴스 카테고리 분류
category = await self.categorizer.categorize(news)
news.category = category
# 뉴스 요약
summary = await self.summarizer.summarize(news)
news.summary = summary
processed_news.append(news)
# 중복 제거 및 품질 필터링
filtered_news = self.filter_and_deduplicate(processed_news)
return filtered_news
def filter_and_deduplicate(self, news_list):
"""뉴스 필터링 및 중복 제거"""
seen_titles = set()
filtered = []
for news in news_list:
# 제목 유사성 체크 (간단한 방법)
title_words = set(news.title.lower().split())
is_duplicate = False
for seen_title in seen_titles:
seen_words = set(seen_title.lower().split())
# 70% 이상 단어가 겹치면 중복으로 판단
overlap = len(title_words & seen_words) / len(title_words | seen_words)
if overlap > 0.7:
is_duplicate = True
break
if not is_duplicate and len(news.title) > 10:
seen_titles.add(news.title)
filtered.append(news)
return filtered
async def generate_outputs(self, news_list):
"""다양한 형태로 출력 생성"""
results = {}
for generator in self.output_generators:
try:
output = await generator.generate(news_list)
results[generator.__class__.__name__] = output
except Exception as e:
print(f"{generator.__class__.__name__} 생성 오류: {e}")
return results
async def run_daily_collection(self):
"""일일 뉴스 수집 실행"""
try:
await self.initialize()
print(f"뉴스 수집 시작: {datetime.now()}")
# 뉴스 수집
news_list = await self.collect_news()
print(f"총 {len(news_list)}개 뉴스 수집 완료")
# 출력 생성
outputs = await self.generate_outputs(news_list)
print("출력 생성 완료")
return {
"collected_news": len(news_list),
"outputs": outputs,
"timestamp": datetime.now().isoformat()
}
except Exception as e:
print(f"뉴스 수집 중 오류 발생: {e}")
return {"error": str(e)}
finally:
if self.browser:
await self.browser.close()
# 스크래퍼 구현 예제
# scrapers/tech_scraper.py
from .base_scraper import BaseScraper
from models.news_item import NewsItem
class TechNewsScraper(BaseScraper):
def __init__(self, browser, ai_model):
super().__init__(browser, ai_model)
self.sources = [
"https://news.ycombinator.com",
"https://techcrunch.com",
"https://arstechnica.com"
]
async def scrape(self):
"""기술 뉴스 스크래핑"""
all_news = []
for source in self.sources:
try:
if "ycombinator" in source:
news = await self.scrape_hackernews()
elif "techcrunch" in source:
news = await self.scrape_techcrunch()
elif "arstechnica" in source:
news = await self.scrape_arstechnica()
all_news.extend(news)
except Exception as e:
print(f"{source} 스크래핑 오류: {e}")
return all_news
async def scrape_hackernews(self):
"""Hacker News 스크래핑"""
await self.browser.navigate("https://news.ycombinator.com")
# 뉴스 항목 선택
news_items = await self.browser.find_elements(".titleline > a")
news_list = []
for i, item in enumerate(news_items[:20]): # 상위 20개만
try:
title = await self.browser.extract_text(item)
url = await self.browser.get_attribute(item, "href")
# 상대 URL을 절대 URL로 변환
if url.startswith("item?"):
url = f"https://news.ycombinator.com/{url}"
# 점수와 댓글 수 가져오기
score_element = await self.browser.find_element(
f".athing:nth-child({(i+1)*3}) + tr .score"
)
score = await self.browser.extract_text(score_element) if score_element else "0 points"
news_item = NewsItem(
title=title,
url=url,
source="Hacker News",
score=score,
timestamp=datetime.now()
)
news_list.append(news_item)
except Exception as e:
print(f"Hacker News 항목 처리 오류: {e}")
continue
return news_list
# AI 요약기 구현
# ai/summarizer.py
class NewsSummarizer:
def __init__(self, ai_model):
self.ai_model = ai_model
async def summarize(self, news_item):
"""뉴스 요약 생성"""
try:
# 뉴스 내용 가져오기 (필요시)
if not news_item.content:
content = await self.fetch_article_content(news_item.url)
news_item.content = content
# AI로 요약 생성
prompt = f"""
다음 뉴스 기사를 3문장으로 요약해주세요:
제목: {news_item.title}
내용: {news_item.content[:1000]}...
요약:
"""
summary = await self.ai_model.generate_text(
prompt=prompt,
max_tokens=200,
temperature=0.3
)
return summary.strip()
except Exception as e:
return f"요약 생성 실패: {str(e)}"
async def fetch_article_content(self, url):
"""기사 본문 추출"""
# 이 부분은 별도의 브라우저 인스턴스나
# 기존 브라우저를 사용하여 구현
pass
# 출력 생성기
# output/markdown_generator.py
class MarkdownGenerator:
async def generate(self, news_list):
"""마크다운 뉴스 리포트 생성"""
# 카테고리별로 뉴스 그룹화
categorized_news = {}
for news in news_list:
category = news.category or "기타"
if category not in categorized_news:
categorized_news[category] = []
categorized_news[category].append(news)
# 마크다운 생성
markdown = f"# 일일 뉴스 요약 - {datetime.now().strftime('%Y년 %m월 %d일')}\n\n"
for category, news_items in categorized_news.items():
markdown += f"## 📰 {category}\n\n"
for news in news_items:
markdown += f"### {news.title}\n"
markdown += f"**출처**: {news.source}\n"
markdown += f"**링크**: [{news.url}]({news.url})\n"
if news.summary:
markdown += f"**요약**: {news.summary}\n"
markdown += "\n---\n\n"
# 파일로 저장
filename = f"daily_news_{datetime.now().strftime('%Y%m%d')}.md"
with open(filename, 'w', encoding='utf-8') as f:
f.write(markdown)
return {
"format": "markdown",
"filename": filename,
"content_length": len(markdown)
}
# 실행
async def main():
collector = AutomatedNewsCollector()
result = await collector.run_daily_collection()
print(f"뉴스 수집 결과: {result}")
if __name__ == "__main__":
asyncio.run(main())
성능 최적화 및 운영
1. 메모리 및 CPU 최적화
# performance_optimizer.py
import psutil
import asyncio
from browseros.optimization import PerformanceMonitor
class BrowserOSOptimizer:
def __init__(self, browser):
self.browser = browser
self.monitor = PerformanceMonitor()
async def optimize_performance(self):
"""성능 최적화 실행"""
# 1. 메모리 사용량 모니터링
memory_usage = psutil.virtual_memory().percent
if memory_usage > 80:
await self.cleanup_memory()
# 2. CPU 사용량 체크
cpu_usage = psutil.cpu_percent(interval=1)
if cpu_usage > 90:
await self.reduce_cpu_load()
# 3. 브라우저 탭 관리
await self.manage_browser_tabs()
# 4. 캐시 정리
await self.cleanup_cache()
async def cleanup_memory(self):
"""메모리 정리"""
# 사용하지 않는 탭 닫기
tabs = await self.browser.get_all_tabs()
for tab in tabs:
if not tab.is_active and tab.idle_time > 300: # 5분 이상 비활성
await tab.close()
# 가비지 컬렉션 강제 실행
import gc
gc.collect()
async def manage_browser_tabs(self):
"""브라우저 탭 관리"""
tabs = await self.browser.get_all_tabs()
# 탭이 너무 많으면 오래된 것부터 정리
if len(tabs) > 10:
sorted_tabs = sorted(tabs, key=lambda t: t.last_activity)
for tab in sorted_tabs[:-5]: # 최근 5개만 유지
await tab.close()
2. 에러 처리 및 복구
# error_handling.py
import asyncio
from contextlib import asynccontextmanager
class RobustBrowserSession:
def __init__(self, max_retries=3):
self.max_retries = max_retries
self.browser = None
@asynccontextmanager
async def get_browser(self):
"""안정적인 브라우저 세션 관리"""
try:
if not self.browser:
self.browser = await self.create_browser()
yield self.browser
except Exception as e:
print(f"브라우저 오류 발생: {e}")
await self.restart_browser()
yield self.browser
finally:
# 정리 작업은 세션 종료 시에만
pass
async def create_browser(self):
"""브라우저 생성"""
browser = BrowserOS(
headless=True,
error_recovery=True,
max_memory_mb=2048
)
await browser.start()
return browser
async def restart_browser(self):
"""브라우저 재시작"""
if self.browser:
try:
await self.browser.close()
except:
pass
self.browser = await self.create_browser()
async def safe_navigate(self, url, retries=None):
"""안전한 페이지 이동"""
if retries is None:
retries = self.max_retries
for attempt in range(retries):
try:
async with self.get_browser() as browser:
await browser.navigate(url)
return True
except Exception as e:
print(f"이동 실패 (시도 {attempt + 1}/{retries}): {e}")
if attempt == retries - 1:
raise
await asyncio.sleep(2 ** attempt) # 지수 백오프
return False
# 사용 예제
async def robust_automation_example():
session = RobustBrowserSession()
async with session.get_browser() as browser:
# 안전한 작업 수행
success = await session.safe_navigate("https://example.com")
if success:
# 추가 작업 수행
pass
3. 로깅 및 모니터링
# monitoring.py
import logging
import json
from datetime import datetime
from pathlib import Path
class BrowserOSLogger:
def __init__(self, log_level=logging.INFO):
self.setup_logging(log_level)
self.metrics = {}
def setup_logging(self, level):
"""로깅 설정"""
# 로그 디렉토리 생성
log_dir = Path("logs")
log_dir.mkdir(exist_ok=True)
# 로거 설정
logging.basicConfig(
level=level,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(
log_dir / f"browseros_{datetime.now().strftime('%Y%m%d')}.log"
),
logging.StreamHandler()
]
)
self.logger = logging.getLogger("BrowserOS")
def log_automation_start(self, task_name):
"""자동화 시작 로그"""
self.logger.info(f"자동화 작업 시작: {task_name}")
self.metrics[task_name] = {
"start_time": datetime.now(),
"steps": [],
"errors": []
}
def log_automation_step(self, task_name, step_description, success=True):
"""자동화 단계 로그"""
step_info = {
"timestamp": datetime.now(),
"description": step_description,
"success": success
}
if task_name in self.metrics:
self.metrics[task_name]["steps"].append(step_info)
if success:
self.logger.debug(f"[{task_name}] 단계 완료: {step_description}")
else:
self.logger.warning(f"[{task_name}] 단계 실패: {step_description}")
def log_automation_end(self, task_name, success=True, error=None):
"""자동화 종료 로그"""
if task_name in self.metrics:
end_time = datetime.now()
start_time = self.metrics[task_name]["start_time"]
duration = (end_time - start_time).total_seconds()
self.metrics[task_name]["end_time"] = end_time
self.metrics[task_name]["duration"] = duration
self.metrics[task_name]["success"] = success
if error:
self.metrics[task_name]["error"] = str(error)
self.logger.error(f"[{task_name}] 작업 실패: {error}")
else:
self.logger.info(f"[{task_name}] 작업 완료 (소요시간: {duration:.2f}초)")
def export_metrics(self, filename=None):
"""메트릭 데이터 내보내기"""
if not filename:
filename = f"metrics_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(filename, 'w', encoding='utf-8') as f:
json.dump(self.metrics, f, default=str, indent=2, ensure_ascii=False)
return filename
확장 및 커스터마이징
1. 플러그인 시스템
# plugins/base_plugin.py
from abc import ABC, abstractmethod
class BrowserOSPlugin(ABC):
"""BrowserOS 플러그인 기본 클래스"""
def __init__(self, name, version="1.0.0"):
self.name = name
self.version = version
self.enabled = True
@abstractmethod
async def initialize(self, browser, ai_model):
"""플러그인 초기화"""
pass
@abstractmethod
async def execute(self, *args, **kwargs):
"""플러그인 실행"""
pass
async def cleanup(self):
"""플러그인 정리"""
pass
# plugins/social_media_plugin.py
class SocialMediaAutomationPlugin(BrowserOSPlugin):
"""소셜 미디어 자동화 플러그인"""
def __init__(self):
super().__init__("SocialMediaAutomation", "1.0.0")
self.browser = None
self.ai_model = None
async def initialize(self, browser, ai_model):
self.browser = browser
self.ai_model = ai_model
async def execute(self, action, platform, content=None):
"""소셜 미디어 작업 실행"""
if platform == "twitter":
return await self.handle_twitter_action(action, content)
elif platform == "linkedin":
return await self.handle_linkedin_action(action, content)
else:
raise ValueError(f"지원하지 않는 플랫폼: {platform}")
async def handle_twitter_action(self, action, content):
"""트위터 작업 처리"""
await self.browser.navigate("https://twitter.com")
if action == "post_tweet":
# 트윗 작성
tweet_box = await self.browser.find_element("[data-testid='tweetTextarea_0']")
await self.browser.type(tweet_box, content)
# 트윗 버튼 클릭
tweet_button = await self.browser.find_element("[data-testid='tweetButtonInline']")
await self.browser.click(tweet_button)
return {"success": True, "action": "tweet_posted"}
elif action == "check_mentions":
# 멘션 확인
await self.browser.navigate("https://twitter.com/notifications/mentions")
mentions = await self.browser.find_elements("[data-testid='tweet']")
return {
"success": True,
"mentions_count": len(mentions),
"action": "mentions_checked"
}
# 플러그인 매니저
class PluginManager:
def __init__(self):
self.plugins = {}
self.browser = None
self.ai_model = None
async def initialize(self, browser, ai_model):
self.browser = browser
self.ai_model = ai_model
def register_plugin(self, plugin: BrowserOSPlugin):
"""플러그인 등록"""
self.plugins[plugin.name] = plugin
async def load_plugin(self, plugin_name):
"""플러그인 로드"""
if plugin_name in self.plugins:
plugin = self.plugins[plugin_name]
await plugin.initialize(self.browser, self.ai_model)
return plugin
else:
raise ValueError(f"플러그인을 찾을 수 없음: {plugin_name}")
async def execute_plugin(self, plugin_name, *args, **kwargs):
"""플러그인 실행"""
plugin = await self.load_plugin(plugin_name)
return await plugin.execute(*args, **kwargs)
# 사용 예제
async def plugin_example():
browser = BrowserOS()
await browser.start()
ai_model = LocalAIModel("llama3.2")
# 플러그인 매니저 초기화
plugin_manager = PluginManager()
await plugin_manager.initialize(browser, ai_model)
# 소셜 미디어 플러그인 등록
social_plugin = SocialMediaAutomationPlugin()
plugin_manager.register_plugin(social_plugin)
# 플러그인 사용
result = await plugin_manager.execute_plugin(
"SocialMediaAutomation",
action="post_tweet",
platform="twitter",
content="BrowserOS로 자동 트윗 테스트!"
)
print(f"플러그인 실행 결과: {result}")
2. API 서버 모드
# api_server.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional, Dict, Any
import asyncio
app = FastAPI(title="BrowserOS API", version="1.0.0")
# 요청 모델
class NavigationRequest(BaseModel):
url: str
wait_for_load: bool = True
class AutomationRequest(BaseModel):
task: str
max_steps: int = 10
return_screenshots: bool = False
class ScrapingRequest(BaseModel):
url: str
selector: str
data_type: str = "text"
# 글로벌 브라우저 인스턴스
browser_instance = None
@app.on_event("startup")
async def startup():
"""API 서버 시작 시 브라우저 초기화"""
global browser_instance
browser_instance = BrowserOS(headless=True)
await browser_instance.start()
@app.on_event("shutdown")
async def shutdown():
"""API 서버 종료 시 브라우저 정리"""
global browser_instance
if browser_instance:
await browser_instance.close()
@app.post("/navigate")
async def navigate(request: NavigationRequest):
"""페이지 이동 API"""
try:
await browser_instance.navigate(request.url)
if request.wait_for_load:
await browser_instance.wait_for_load()
return {
"success": True,
"current_url": await browser_instance.get_current_url(),
"title": await browser_instance.get_title()
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/automate")
async def automate_task(request: AutomationRequest):
"""AI 자동화 작업 API"""
try:
ai_model = LocalAIModel("llama3.2")
agent = WebAgent(browser_instance, ai_model)
result = await agent.execute_task(
task=request.task,
max_steps=request.max_steps
)
response_data = {
"success": result.success,
"steps": result.steps,
"final_url": result.final_url,
"execution_time": result.execution_time
}
if request.return_screenshots:
response_data["screenshots"] = result.screenshots
return response_data
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/scrape")
async def scrape_data(request: ScrapingRequest):
"""데이터 스크래핑 API"""
try:
await browser_instance.navigate(request.url)
if request.data_type == "text":
data = await browser_instance.extract_text(request.selector)
elif request.data_type == "html":
data = await browser_instance.extract_html(request.selector)
elif request.data_type == "attributes":
data = await browser_instance.extract_attributes(request.selector)
else:
data = await browser_instance.extract_text(request.selector)
return {
"success": True,
"data": data,
"url": request.url,
"selector": request.selector
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/status")
async def get_status():
"""브라우저 상태 확인 API"""
try:
current_url = await browser_instance.get_current_url()
title = await browser_instance.get_title()
return {
"status": "running",
"current_url": current_url,
"title": title,
"browser_version": browser_instance.version
}
except Exception as e:
return {
"status": "error",
"error": str(e)
}
# API 서버 실행
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
결론
BrowserOS는 웹 브라우징의 미래를 제시하는 혁신적인 플랫폼입니다. AI 에이전트와 함께하는 새로운 웹 경험을 통해:
🎯 핵심 가치
- 자동화된 생산성: AI가 반복적인 웹 작업을 대신 처리
- 개인정보 보호: 모든 AI 처리가 로컬에서 실행
- 완전한 커스터마이징: 오픈소스로 무한한 확장 가능
- 통합된 워크플로우: 웹 브라우징과 AI 도구의 완벽한 결합
🚀 활용 분야
- 개발자 도구: 자동화된 테스팅 및 스크래핑
- 마케팅 자동화: 소셜 미디어 및 콘텐츠 관리
- 연구 지원: 자동화된 정보 수집 및 분석
- 비즈니스 인텔리전스: 경쟁 분석 및 시장 조사
🔮 미래 전망
BrowserOS는 단순한 브라우저를 넘어서 AI 중심의 웹 운영 시스템으로 발전할 것입니다. 사용자는 더 이상 웹과 싸우지 않고, AI 에이전트와 협력하여 더 효율적이고 생산적인 온라인 경험을 누릴 수 있게 될 것입니다.
Chrome이 지난 10년간 그대로였다면, BrowserOS는 다음 10년의 웹 브라우징을 정의할 혁신적인 플랫폼입니다.
참고 자료:
- BrowserOS 공식 GitHub
- BrowserOS 공식 웹사이트
-
Star: 3.3k Forks: 209 License: AGPL-3.0 - 최신 릴리스: v0.18.0 (2025년 8월 1일)
관련 키워드: #BrowserOS
#AI에이전트
#웹자동화
#Chromium
#로컬AI
#MCP
#생산성도구