Google 검색 자료를 크롤링 할 일이 생겼지만 구글 내부의 봇 탐지 기능 때문에 어려워졌다.
크롤링을 자주 접하고 해보았더라면 다들 한 번 쯤은 겪는 현상이다.
코드적인 실력보다 bot 탐지를 우회하는 여러 방법을 아는 것이 크롤링 실력 향상에 도움이 되는 것이라고 생각한다.
우회? 방법이라기 보단 자동화 Chrome을 일반 사용자가 접속하는 것 처럼 위장하는 느낌이다.
즉 완벽한 방법은 아니니 나와 같은 문제를 겪는 중이라면 시도해보는 것도 좋다.
Chrome 실행 과정 (결과만 보고 보고 싶으신 분들은 맨 아래로)
1. Chrome 실행 (launch 부분)
- 실행 시점에 명령어를 전달
--enable-automation
--disable-blink-features=AutomationControlled
2. Browser Proceess 생성(browser 객체)
- 실행 환경 관리자 역할
- 옵션 목록 저장
- Renderer 생성 시 그대로 전달
3. 탭 열림 → Renderer Process 생성 (browser.newPage())
- 1번에서 전달한 명령어를 Renderer 에 그대로 전달받음
- disable-blink는 탭마다 다시 적용됨
4. disable-blink 작동
- Renderer Process 시작 후 내부 초기화 시작
① 옵션 읽기
② Blink 초기화
③ V8 chrlghk
④ Blink, V8 연결
disabled-blink 적용 지점 = Blink 초기화
- 초기화 시 Blink가 체크 하는 부분: "AutomationControlled 확인"
- 현재 HTML, JS, navigator 없는 상태
5. Blink가 navigator 환경을 결정
ex) navigator.webdriver의 true/ undefined 여부 결
현재 JS 실행 전, 구조 설계 단계
6. V8(JS 엔진) 준비
- V8은 JS 문법 실행
- navigator 접근 시 Blink에게 요청
7. WebIDL로 연결
Blink(C++) ↔ WebIDL ↔ V8(JS)
JS 에서 navigator 가 보이기 시작
8. HTML 로드 → JS 실행
V8은 navigator.webdriver 요청
Blink 입장에서는 첫 명령어를 받은 시점에 disabled처리를 했기 때문에 undefined 반환
8-1. Browser Process
→ google.com으로 HTTP 요청
8-2. 서버 응답
→ HTML 내려옴
8-3. Renderer Process (Blink)
→ HTML 파싱 시작
8-4. <script> 태그 발견
→ V8에서 JS 실행
이후
DOM 생김
window, document 접근 가능⊙
navigator 접근 가능
※ 정리
chrome.exe 실행
→ 옵션 전달
→ Browser Process
→ Renderer Process
→ Blink 초기화 (disable-blink 적용)
→ navigator 구조 결정
→ V8 초기화
→ JS 실행
frontend 개발자라면 이해하기 좀 더 수월 할 듯 하다.
어쨌든 주요 포인트는 bot 탐지를 우회하는 방법이다 위와 같이 첫 실행 옵션에서 설정을 해주면 우회가 가능하다는 것을 알 수 있다.
◈ pyppeteer 예시
browser = await launch(
executablePath=chrome_path,
headless=False,
args=[
'--window-size=1200,800',
# 자동화 제어 플래그 숨김 (navigator.webdriver 탐지 방지)
'--disable-blink-features=AutomationControlled',
# "Chrome이 자동화 소프트웨어에 의해 제어되고 있습니다" 정보바 숨김
# '--disable-infobars',
],
# 자동화 관련 기본 인자 제거 (navigator.webdriver = true 방지)
# ignoreDefaultArgs=['--enable-automation'],
)
저 코드를 사용해서 실행해보면
위와 같이 bot 탐지에 걸리지 않고 Blink에 전달 되었던 대로 접속 되는 것을 볼 수 있다.
이런 것들이 귀찮다?
undetected_chromedriver
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
def main():
# Chrome 옵션 설정
options = uc.ChromeOptions()
options.add_argument('--window-size=1200,800')
options.add_argument('--lang=ko-KR')
# undetected-chromedriver 실행
driver = uc.Chrome(options=options)
driver.get('https://www.google.com')
print("Google.com 접속")
selenium 기반이지만 이거 사용하시면 됩니다. 웬만한 옵션은 추가 되어 있습니다.
[권장사항] executablePath 적용
라이브러리에서 기본 제공하는 Chromium은 User-Agent, JS 엔진 동작, Blink feature set이 구형 인 경우가 많아 해당 요소를 기반으로 탐지되는 웹사이트가 간혹 존재
이는 엔진 레벨(브라우저 엔진[Blink·V8·Network stack] 내부 동작 영역) 에서 판별되는 영역이므로 JS 우회만으로는 대응이 불가능
executablePath를 지정하지 않을 경우 오래된 Chromium 기반으로 실행될 수 있으므로, 본인 환경에 설치된 최신 Chrome 경로를 지정하여 실행하는 것을 권장