이 튜토리얼에서는 다음을 배웁니다:
유저 에이전트헤더가 중요한 이유- 헤드드 및 헤드리스 브라우저 모두에서 Selenium의 기본 사용자 에이전트 값
- Selenium에서 사용자 에이전트 변경 방법
- 셀레니움에서 사용자 에이전트 로테이션 구현 방법
자, 시작해 보겠습니다!
사용자 에이전트 헤더가 중요한 이유는 무엇인가요?
User-Agent 헤더는 HTTP 요청을 수행하는 클라이언트 소프트웨어를 식별하는 문자열입니다. 일반적으로 요청이 발생한 브라우저 또는 애플리케이션 유형, 운영 체제, 아키텍처에 대한 정보를 포함합니다. 이는 일반적으로 웹 요청을 수행하는 브라우저, HTTP 클라이언트 또는 기타 애플리케이션에 의해 설정됩니다.
예를 들어, 아래는 작성 시점 기준 Chrome이 설정하는 사용자 에이전트입니다:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
이 사용자 에이전트 문자열의 구성 요소는 다음과 같습니다:
Mozilla/5.0: 역사적으로 Mozilla 브라우저와의 호환성을 나타내는 데 사용되었습니다. 현재는 호환성 이유로 추가된 접두사를 나타냅니다.Windows NT 10.0; Win64; x64: 운영 체제(Windows NT 10.0), 플랫폼(Win64), 아키텍처(x64).AppleWebKit/537.36: Chrome이 의존하는 브라우저 엔진.KHTML, like Gecko: Mozilla에서 사용하는 KHTML 엔진 및 Gecko 레이아웃 엔진과의 호환성을 나타냅니다.Chrome/125.0.0.0: 브라우저 이름 및 버전.Safari/537.36: Safari와의 호환성.
간단히 말해서, 사용자 에이전트는 요청이 알려진 브라우저에서 왔는지, 아니면 다른 유형의 소프트웨어에서 왔는지 식별합니다.
스크래핑 봇과 브라우저 자동화 스크립트는 기본값이나 일관성 없는 사용자 에이전트 문자열을 사용하는 경향이 있습니다. 이는 들어오는 요청을 모니터링하여 웹 페이지 데이터를 보호하는 안티 스크래핑 솔루션의 눈에는 자동화된 특성으로 드러납니다. User-Agent 헤더를 살펴봄으로써, 현재 사용자가 합법적인지 봇인지 판단할 수 있습니다.
자세한 내용은 웹 스크래핑용 사용자 에이전트 가이드를 참조하십시오.
기본 Selenium 사용자 에이전트는 무엇인가요?
웹 페이지 가져오기용 HTTP GET 요청 시 셀레니움이 설정하는 User-Agent 헤더는 제어 중인 브라우저와 헤드드 모드/헤드리스 모드 여부에 따라 달라집니다.
참고: 본 문서에서는 Python 기반 Selenium을 Chrome에서 실행하도록 구성합니다. 그러나 여기서 배우는 내용은 다른 프로그래밍 언어와 브라우저로 쉽게 확장할 수 있습니다.
Selenium 사용자 에이전트 문자열을 확인하려면 httpbin. io/user-agent 페이지를 방문하는 기본 브라우저 자동화 스크립트를 작성하세요. 이 페이지는 단순히 들어오는 요청의 User-Agent 헤더를 반환하는 API입니다.
selenium을 임포트하고, Chrome 인스턴스를 초기화한 후, 원하는 페이지를 방문하여 그 내용을 출력합니다:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
# Selenium에서 헤드리스 모드 활성화
options = Options()
# options.add_argument('--headless')
# Chrome 인스턴스 초기화
driver = webdriver.Chrome(
options=options,
)
# 원하는 페이지 방문
driver.get("https://httpbin.org/user-agent")
# 페이지 콘텐츠 가져오기
user_agent_info = driver.find_element(By.TAG_NAME, "body").text
# 페이지 콘텐츠 출력
print(user_agent_info)
# 브라우저 종료
driver.quit()
위의 Python 스크립트를 실행하면 터미널에 다음과 같은 내용이 출력됩니다:
{
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
}
이 값은 작성 시점에 Chrome이 설정하는 User-Agent 헤더에 해당합니다. Selenium이 실제 브라우저 창에서 작동하므로 놀랄 일은 아닙니다.
동시에 Selenium은 일반적으로 헤드리스 브라우저 인스턴스를 제어하도록 구성됩니다. 그 이유는 브라우저 UI 로딩이 많은 리소스를 소모하며 실제 운영 환경에서는 아무런 이점을 제공하지 않기 때문입니다. 따라서 --headless 옵션을 주석 해제하여 스크립트를 헤드리스 모드로 실행하세요. 이번에는 결과가 다음과 같을 것입니다:
{
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/125.0.6422.142 Safari/537.36"
}
보시다시피 Chrome/125.0.0.0이 HeadlessChrome/125.0.6422.142로 대체되었습니다. 이 값은 요청이 브라우저 자동화 도구에서 온 것임을 명확히 식별합니다. 인간 사용자가 헤드리스 브라우저를 사용할 리 없기 때문입니다. 결과적으로 봇 방지 시스템은 이러한 요청을 봇에서 온 것으로 표시하고 차단할 수 있습니다. 이것이 셀레니움 사용자 에이전트 값 설정이 매우 중요한 이유입니다!
자세한 내용은 Selenium 웹 스크래핑 가이드에서 확인하세요.
Selenium에서 사용자 에이전트 변경 방법
Selenium은 사용자 에이전트 값을 설정하는 두 가지 방법을 제공합니다. 두 가지 방법을 모두 살펴보겠습니다!
전역적으로 사용자 에이전트 설정하기
Chrome에서 지원하는 옵션 중에는 --user-agent 플래그도 있습니다. 이 플래그를 사용하면 Chrome 프로세스가 탭이나 창에서 웹 페이지를 방문할 때 사용할 글로벌 사용자 에이전트를 지정할 수 있습니다.
Python을 사용한 Selenium에서 글로벌 사용자 에이전트 설정 방법:
custom_user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
options = Options()
# 브라우저 옵션에 사용자 정의 사용자 에이전트 설정
options.add_argument(f'--user-agent={custom_user_agent}')
# 기타 옵션...
# 사용자 정의 사용자 에이전트로 Chrome 인스턴스 초기화
driver = webdriver.Chrome(
options=options,
)
모든 것을 결합하고 다음 스크립트로 작동하는지 확인하세요:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
custom_user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
options = Options()
# 브라우저 옵션에 사용자 정의 사용자 에이전트 설정
options.add_argument(f'--user-agent={custom_user_agent}')
# 헤드리스 모드 활성화
options.add_argument('--headless')
# 사용자 정의 사용자 에이전트로 헤드리스 Chrome 인스턴스 초기화
driver = webdriver.Chrome(
options=options,
)
# 원하는 페이지 방문
driver.get("https://httpbin.org/user-agent")
# 페이지 콘텐츠 가져오기
user_agent_info = driver.find_element(By.TAG_NAME, "body").text
# 페이지 콘텐츠 출력
print(user_agent_info)
# 브라우저 종료
driver.quit()
이제 스크립트를 실행하면 다음과 같이 출력됩니다:
{
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
}
이는 custom_user_agent 문자열에 지정된 사용자 에이전트와 일치합니다. 특히 Selenium을 통해 제어되는 브라우저는 헤드리스 모드에서도 헤더가 있는 브라우저의 사용자 에이전트 값을 노출합니다. 이 방법은 덜 복잡한 봇 방지 솔루션에는 충분할 것입니다.
이 접근법의 주요 단점은 --user-agent 플래그를 브라우저 인스턴스 설정 중에 한 번만 설정할 수 있다는 점입니다. 일단 지정되면 커스텀 사용자 에이전트는 전체 브라우징 세션 동안 사용되며, get() 호출 전에 실시간으로 변경할 수 없습니다.
로컬에서 사용자 에이전트 설정
Chrome Devtools Protocol (CDP) 명령어를 사용하면 실행 중인 Chrome 브라우저와 통신할 수 있습니다. 특히 브라우저가 설정한 기본값과 구성을 동적으로 변경할 수 있는 기능을 제공합니다.
Selenium에서는 드라이버 객체가 제공하는 execute_cdp_cmd() 메서드를 사용하여 CDP 명령을 실행할 수 있습니다. 특히 Network.setUserAgentOverride CDP 명령은 주어진 문자열로 사용자 에이전트를 재정의합니다. 아래와 같이 Selenium에서 로컬로 사용자 에이전트를 변경하는 데 사용하세요:
custom_user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
driver.execute_cdp_cmd('Network.setUserAgentOverride', {'userAgent': custom_user_agent})
다음 로직을 통해 동일한 브라우징 세션 내에서 사용자 에이전트를 여러 번 업데이트할 수 있는지 확인하세요:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
options = Options()
# 헤드리스 모드 활성화
options.add_argument('--headless')
# 헤드리스 Chrome 인스턴스 초기화
driver = webdriver.Chrome(
options=options,
)
# 사용자 정의 사용자 에이전트 설정
custom_user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
driver.execute_cdp_cmd('Network.setUserAgentOverride', {'userAgent': custom_user_agent})
# 원하는 페이지 방문
driver.get("https://httpbin.org/user-agent")
# 페이지 콘텐츠 가져와 출력
user_agent_info = driver.find_element(By.TAG_NAME, "body").text
print(user_agent_info)
# 다른 사용자 에이전트 설정
custom_user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0"
driver.execute_cdp_cmd('Network.setUserAgentOverride', {'userAgent': custom_user_agent})
# 페이지 재로드
driver.refresh()
# 페이지 콘텐츠 출력
user_agent_info = driver.find_element(By.TAG_NAME, "body").text
print(user_agent_info)
# 브라우저 종료
driver.quit()
위 스크립트를 실행하면 다음과 같은 결과가 출력됩니다:
{
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
}
{
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0"
}
대단하네요! 동일한 브라우징 세션 내에서 서로 다른 두 개의 셀레니움 사용자 에이전트 문자열이 나타났습니다.
셀레니움에서 사용자 에이전트 로테이션 구현하기
헤드리스 모드가 아닌 User-Agent 헤더 설정만으로는 봇 방지 기능을 극복하기에 충분하지 않을 수 있습니다. 문제는 동일한 IP 주소에서 동일한 헤더로 너무 많은 요청이 발생하면 Selenium 스크립트의 자동화된 특성이 드러날 가능성이 높다는 점입니다.
봇 탐지를 피하는 핵심은 사용자 에이전트 로테이션 구현과 같이 요청을 무작위화하는 것입니다. 이 접근법의 핵심은 Selenium에서 페이지로 이동하기 전에 사용자 에이전트를 무작위로 선택하는 것입니다. 이렇게 하면 자동화된 요청이 서로 다른 브라우저에서 온 것처럼 보이게 되어 차단 및 금지 위험을 줄일 수 있습니다.
이제 아래 단계를 따라 셀레니움에서 사용자 에이전트 로테이션을 구현하는 방법을 알아보세요!
1단계: 사용자 에이전트 목록 수집
User Agent String.com과 같은 포털에서 적절한 사용자 에이전트를 가져와 다음과 같이 Python 배열에 저장하세요:
user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 14.5; rv:126.0) Gecko/20100101 Firefox/126.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15"
# 기타 사용자 에이전트...
]
2단계: 무작위 사용자 에이전트 추출
Selenium 웹 드라이버 객체에 무작위 사용자 에이전트를 설정하는 사용자 정의 함수를 정의합니다:
def set_user_agent(driver):
# 사용자 에이전트 설정...
Python 표준 라이브러리에서 random 패키지를 임포트하여 user_agents 목록에서 사용자 에이전트를 무작위로 선택할 준비를 합니다:
import random
random.choice() 함수를 사용하여 배열에서 사용자 에이전트 문자열을 무작위로 추출합니다:
random_user_agent = random.choice(user_agents)
그런 다음 execute_cdp_cmd() 함수를 사용하여 Chrome 창에 할당합니다:
driver.execute_cdp_cmd('Network.setUserAgentOverride', {'userAgent': random_user_agent})
이제 set_user_agent() 함수는 다음과 같이 구성됩니다:
def set_user_agent(driver):
# 목록에서 사용자 에이전트 문자열을 무작위로 선택
random_user_agent = random.choice(user_agents)
# 드라이버에 사용자 에이전트 설정
driver.execute_cdp_cmd('Network.setUserAgentOverride', {'userAgent': random_user_agent})
3단계: 임의의 사용자 에이전트 설정
get()으로 페이지로 이동하기 전에 set_user_agent() 함수를 호출하여 Selenium 사용자 에이전트를 변경합니다:
# 사용자 정의 사용자 에이전트 설정
set_user_agent(driver)
# 원하는 페이지 방문
driver.get("https://httpbin.org/user-agent")
단계 #4: 모든 것 통합하기
다음은 Python Selenium 사용자 에이전트 로테이션 스크립트의 전체 모습입니다:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
import random
user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 14.5; rv:126.0) Gecko/20100101 Firefox/126.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15"
def set_user_agent(driver):
# 목록에서 사용자 에이전트 문자열을 무작위로 선택
random_user_agent = random.choice(user_agents)
# 드라이버에 사용자 에이전트 설정
driver.execute_cdp_cmd('Network.setUserAgentOverride', {'userAgent': random_user_agent})
options = Options()
# 헤드리스 모드 활성화
options.add_argument('--headless')
# 헤드리스 Chrome 인스턴스 초기화
driver = webdriver.Chrome(
options=options,)
# 사용자 정의 사용자 에이전트 설정
set_user_agent(driver)
# 원하는 페이지 방문
driver.get("https://httpbin.org/user-agent")
# 페이지 콘텐츠 가져와 출력
user_agent_info = driver.find_element(By.TAG_NAME, "body").text
print(user_agent_info)
# 브라우저 종료
driver.quit()
이 스크립트를 여러 번 실행해 보면 서로 다른 사용자 에이전트 문자열이 출력되는 것을 확인할 수 있습니다.
자, 이제 Selenium에서 사용자 에이전트를 변경하는 전문가가 되셨습니다.
결론
이 가이드에서는 User-Agent 헤더의 중요성과 Selenium에서 이를 재정의하는 방법을 배웠습니다. 이 기술은 기본적인 안티봇 시스템이 요청이 합법적인 비 헤드리스 브라우저에서 온 것으로 생각하도록 속일 수 있게 합니다. 그러나 고급 솔루션은 여전히 사용자를 탐지하고 차단할 수 있습니다. IP 차단 방지를 위해 Selenium에 프록시를 통합할 수 있지만, 그것조차 충분하지 않을 수 있습니다!
이러한 문제를 피하려면 Selenium 및 기타 모든 브라우저 자동화 도구와 통합되는 차세대 브라우저인 Scraping Browser를 사용하세요. Scraping Browser는 브라우저 지문 인식(fingerprinting)을 피하면서 안티봇 기술을 손쉽게 우회해 줍니다. 내부적으로는 사용자 에이전트 로테이션, IP 로테이션, CAPTCHA 해결 등의 기능을 활용합니다. 브라우저 자동화가 이토록 쉬웠던 적은 없습니다!