Browser Use 최신버전 업데이트 및 프로필 기능 유지

This commit is contained in:
imnyang 2025-06-11 19:50:10 +09:00
commit 2ee917408f
3 changed files with 56 additions and 100 deletions

View file

@ -11,7 +11,7 @@ def launch_browser_with_profile():
if __name__ == "__main__": if __name__ == "__main__":
browser, page, playwright = launch_browser_with_profile() browser, page, playwright = launch_browser_with_profile()
page.goto("https://example.com") page.goto("https://google.com")
print("Browser launched with user data profile.") print("Browser launched with user data profile.")
# 브라우저가 열린 상태를 유지 # 브라우저가 열린 상태를 유지

View file

@ -1,24 +0,0 @@
# run uv run playwright open https://google.com/ --user_data_dir=~/.config/browseruse/profiles/default in shell
from playwright.sync_api import sync_playwright
import os
user_data_dir = os.path.expanduser("~/.config/browseruse/profiles/default")
with sync_playwright() as p:
browser = p.chromium.launch_persistent_context(
user_data_dir=user_data_dir,
headless=False,
)
page = browser.new_page()
page.goto("https://google.com")
# ctrl + c to exit
print("Press Ctrl+C to exit...")
try:
while True:
pass # Keep the script running
except KeyboardInterrupt:
print("Exiting...")
finally:
browser.close()

118
main.py
View file

@ -3,6 +3,7 @@ import json
import os import os
import csv import csv
import argparse import argparse
from pathlib import Path
import requests import requests
import time import time
from typing import List from typing import List
@ -12,17 +13,10 @@ from langchain_google_genai import ChatGoogleGenerativeAI
from langchain.callbacks.base import BaseCallbackHandler from langchain.callbacks.base import BaseCallbackHandler
from browser_use import ( from browser_use import (
Agent, Agent,
Browser,
BrowserConfig,
BrowserSession, BrowserSession,
BrowserProfile, BrowserProfile,
Controller, Controller,
) )
from browser_use.browser.context import BrowserContext, BrowserContextConfig
from playwright.async_api import async_playwright
# from lib import browser_config
# from lib.browser_config import browser_config_kwargs
from lib.is_html import is_html_url from lib.is_html import is_html_url
from lib.read_txt import read_lines_between from lib.read_txt import read_lines_between
from lib.prompt import extend_planner_system_message from lib.prompt import extend_planner_system_message
@ -48,24 +42,18 @@ class QuotaExhaustedHandler(BaseCallbackHandler):
time.sleep(120) time.sleep(120)
def create_llm_with_retry(): def CreateChatGoogleGenerativeAI(model: str):
"""재시도 로직이 포함된 LLM 생성""" """재시도 로직이 포함된 LLM 생성"""
if model == "fallback":
print("⚠️ Fallback 모델을 사용합니다. Envorinment 변수를 확인하세요.")
print("⚠️ Model Gemini-2.0-flash-lite를 사용합니다.")
model = "gemini-2.0-flash-lite"
return ChatGoogleGenerativeAI( return ChatGoogleGenerativeAI(
model=os.getenv("GOOGLE_MODEL"), model=model,
max_retries=10, # 최대 재시도 횟수 증가 max_retries=10, # 최대 재시도 횟수 증가
request_timeout=180, # 타임아웃 시간 증가 (3분) model_kwargs={
callbacks=[QuotaExhaustedHandler()], "request_timeout": 120, # 타임아웃 시간 증가 (2분)
# API 호출 간격 조정 },
temperature=0.1,
)
def create_planner_llm_with_retry():
"""플래너용 재시도 로직이 포함된 LLM 생성"""
return ChatGoogleGenerativeAI(
model=os.getenv("GOOGLE_PLANNER_MODEL"),
max_retries=10, # 최대 재시도 횟수 증가
request_timeout=180, # 타임아웃 시간 증가 (3분)
callbacks=[QuotaExhaustedHandler()], callbacks=[QuotaExhaustedHandler()],
# API 호출 간격 조정 # API 호출 간격 조정
temperature=0.1, temperature=0.1,
@ -82,24 +70,18 @@ class OAuthList(BaseModel):
oauth_providers: List[OAuth] oauth_providers: List[OAuth]
async def clean_resources(agent, session, browser, playwright): async def clean_resources(agent=None, session=None):
"""리소스를 정리하는 함수""" """리소스를 정리하는 함수"""
try: if agent:
await agent.close() try:
except Exception as e: await agent.close()
print(f"⚠️ 에이전트 리소스 정리 실패: {e}") except Exception as e:
try: print(f"⚠️ 에이전트 리소스 정리 실패: {e}")
await session.close() if session:
except Exception as e: try:
print(f"⚠️ 세션 리소스 정리 실패: {e}") await session.close()
try: except Exception as e:
await browser.close() print(f"⚠️ 세션 리소스 정리 실패: {e}")
except Exception as e:
print(f"⚠️ 브라우저 리소스 정리 실패: {e}")
try:
await playwright.stop()
except Exception as e:
print(f"⚠️ Playwright 리소스 정리 실패: {e}")
# ── URL별로 Browser를 새로 띄우는 함수 ── # ── URL별로 Browser를 새로 띄우는 함수 ──
@ -141,11 +123,20 @@ async def scan_one_url(url: str, skip_html_check: bool = False):
else: else:
print("🔗 No proxy configured, using direct connection.") print("🔗 No proxy configured, using direct connection.")
# 2) Browser + Context 생성 # user_data_dir 설정
playwright = await async_playwright().start() user_data_path = Path("./data/user_data").resolve()
browser = await playwright.chromium.launch( user_data_path.mkdir(parents=True, exist_ok=True)
# BrowserProfile에 모든 설정 포함
profile = BrowserProfile(
disable_security=True,
stealth=True,
headless=False,
user_data_dir=str(user_data_path),
viewport={"width": 1600, "height": 900},
# 프록시 설정
proxy={"server": proxy_url} if proxy_url else None, proxy={"server": proxy_url} if proxy_url else None,
headless=False, # headless 모드 사용 여부 # 추가 args
args=[ args=[
"--disable-web-security", "--disable-web-security",
"--disable-features=VizDisplayCompositor", "--disable-features=VizDisplayCompositor",
@ -153,31 +144,20 @@ async def scan_one_url(url: str, skip_html_check: bool = False):
"--disable-features=IsolateOrigins,site-per-process", "--disable-features=IsolateOrigins,site-per-process",
"--disable-popup-blocking", "--disable-popup-blocking",
"--disable-dev-shm-usage", "--disable-dev-shm-usage",
f"--lang=" + os.getenv("LANG", "en_US"), f"--lang={os.getenv('LANG', 'en_US')}",
"--ignore-certificate-errors", "--ignore-certificate-errors",
"--ignore-ssl-errors", "--ignore-ssl-errors",
"--allow-running-insecure-content", "--allow-running-insecure-content",
"--restore-last-session" "--restore-last-session",
], ],
) )
os.makedirs("./data", exist_ok=True) # BrowserSession에 profile 전달
profile = BrowserProfile(
stealth=True,
headless=False, # headless 모드 사용 여부
user_data_dir="./data/user_data",
viewport={"width": 1600, "height": 900},
)
# BrowserSession 생성 시 headless 옵션을 명시적으로 설정
context = await browser.new_context()
session = BrowserSession( session = BrowserSession(
browser_context=await browser.new_context(), browser_profile=profile,
) )
# 3) Agent, Controller 생성 # Agent 생성
initial_actions = [ initial_actions = [
{"open_tab": {"url": target_url}}, {"open_tab": {"url": target_url}},
] ]
@ -190,15 +170,16 @@ async def scan_one_url(url: str, skip_html_check: bool = False):
try: try:
agent = Agent( agent = Agent(
browser_session=session, browser_session=session,
browser_profile=profile,
browser_context=context,
initial_actions=initial_actions, initial_actions=initial_actions,
task=f"Navigate to the login page, and collect the OAuth provider buttons and their login URLs. Ignore Passkey.", task=f"Navigate to the login page, and collect the OAuth provider buttons and their login URLs. Ignore Passkey.",
llm=create_llm_with_retry(), llm=CreateChatGoogleGenerativeAI(
planner_llm=create_planner_llm_with_retry(), os.getenv("GOOGLE_MODEL") or "fallback"
),
planner_llm=CreateChatGoogleGenerativeAI(
os.getenv("GOOGLE_PLANNER_MODEL") or "fallback"
),
controller=controller, controller=controller,
extend_planner_system_message=extend_planner_system_message, extend_planner_system_message=extend_planner_system_message,
retry_delay=180, # 재시도 간격을 3분으로 증가
) )
except Exception as e: except Exception as e:
print(f"⚠️ Agent 생성 실패: {e}") print(f"⚠️ Agent 생성 실패: {e}")
@ -206,7 +187,7 @@ async def scan_one_url(url: str, skip_html_check: bool = False):
if "ResourceExhausted" in str(e) or "429" in str(e): if "ResourceExhausted" in str(e) or "429" in str(e):
print("⚠️ API 쿼터 문제로 인한 Agent 생성 실패. 5분 대기 후 재시도...") print("⚠️ API 쿼터 문제로 인한 Agent 생성 실패. 5분 대기 후 재시도...")
await asyncio.sleep(300) await asyncio.sleep(300)
await clean_resources(None, session, browser, playwright) await clean_resources(agent=None, session=session)
continue continue
try: try:
@ -249,14 +230,13 @@ async def scan_one_url(url: str, skip_html_check: bool = False):
# 실제 데이터 저장 # 실제 데이터 저장
for entry in oauth_entries: for entry in oauth_entries:
writer.writerow([url, entry.provider, entry.oauth_uri]) writer.writerow([url, entry.provider, entry.oauth_uri])
await clean_resources(agent, session)
await clean_resources(agent, session, browser, playwright)
# 성공적으로 처리했으므로 반복문 탈출 # 성공적으로 처리했으므로 반복문 탈출
break break
except Exception as e: except Exception as e:
await clean_resources(agent, session, browser, playwright) await clean_resources(agent, session)
# API 쿼터 문제인지 확인 # API 쿼터 문제인지 확인
if "ResourceExhausted" in str(e) or "429" in str(e): if "ResourceExhausted" in str(e) or "429" in str(e):
@ -293,7 +273,7 @@ async def loop(
) )
# (필요하다면) 강제 설정이 필요한 경우, 아래 주석을 해제하여 target_list[0] 등을 덮어쓸 수 있습니다. # (필요하다면) 강제 설정이 필요한 경우, 아래 주석을 해제하여 target_list[0] 등을 덮어쓸 수 있습니다.
#target_list[0] = "velog.io" # target_list[0] = "velog.io"
for i, url in enumerate(target_list): for i, url in enumerate(target_list):
print(f"\n🔄 Processing {i+1}/{len(target_list)}: {url}") print(f"\n🔄 Processing {i+1}/{len(target_list)}: {url}")