Python Selenium 네이버 로그인 자동화 3가지 방법 (2021년 정리본)

Selenium을 처음 배울 때, 네이버 로그인 폼 앞에서 처음으로 막혔던 기억이 있습니다. send_keys로 ID와 PW를 넣으면 그만인 줄 알았는데, 어느 날부터인가 로그인이 통과되지 않았습니다.

2021년 1월, 외부 블로그(cceeddcc.tistory.com/98)를 참고해 정리해 둔 학습 메모입니다. 이 글은 원리 이해를 위한 학습 목적으로 작성됐으며, 네이버를 비롯한 대부분의 포털은 자동 로그인·크롤링을 서비스 약관으로 제한하고 있습니다. 실서비스 자동화에 그대로 적용하는 것은 약관 위반 소지가 있음을 먼저 짚어두겠습니다. 본문 하단에 원래 출처 링크가 있습니다.


0. 준비 — Selenium 핵심 함수 참고표

아래 세 가지 방법에서 이 중 일부가 직접 쓰입니다. 처음 보는 페이지를 뜯어볼 때 빠르게 참고할 수 있도록 한 표로 정리해 두었습니다.

함수설명
webdriver.Chrome("c:/...")chromedriver 경로 지정 후 사용
implicitly_wait(3)웹 페이지 로드를 위해 3초 대기
get(url)url에 접근
page_source현재 렌더링된 페이지의 Elements를 모두 가져오기
find_element_by_name('...')name 속성으로 단일 element 접근
find_element_by_id('...')id로 접근
find_element_by_xpath('...')xpath로 접근
find_element_by_css_selector('...')css selector로 접근
find_element_by_class_name('...')class 이름으로 접근
find_element_by_tag_name('...')tag 이름으로 접근

요소를 찾는 방법은 상황마다 다릅니다. id가 명확히 지정돼 있으면 find_element_by_id가 가장 간결하고, 폼 구조가 복잡하거나 동적으로 렌더링되는 경우에는 xpathcss_selector로 접근하는 편이 유연합니다. class나 tag는 같은 값이 여러 요소에 겹치는 경우가 많아, 단일 요소를 특정할 때는 주의가 필요합니다.


방법 1 — send_keys로 직접 입력 (현재 차단됨)

가장 직관적인 접근은 find_element_by_id로 로그인 폼 요소를 잡고 send_keys로 문자열을 그대로 넣는 방식입니다.

# 2021년 당시 기준: pip install selenium==3.141.0 beautifulsoup4==4.9.3
from selenium import webdriver
from bs4 import BeautifulSoup as bs
import time

# chromedriver의 위치 지정
driver = webdriver.Chrome("c:/Users/학습러/Desktop/chromedriver_win32/chromedriver.exe")

login_url = "https://nid.naver.com/nidlogin.login"
driver.get(login_url)

driver.find_element_by_id("id").send_keys('my_id') # id 넣기
driver.find_element_by_id("pw").send_keys('my_pw') # password 넣기

# 로그인 클릭
driver.find_element_by_xpath('//*[@id="frmNIDLogin"]/fieldset/input').click()

time.sleep(2)
driver.close()

## 2019/02/20 기준 send_keys 함수 사용하면
## 네이버가 자동화된 소프트 웨어라 판단하고 막아놓음

⚠️ 원문 주석: “2019/02/20 기준 send_keys 함수 사용하면 네이버가 자동화된 소프트 웨어라 판단하고 막아놓음”

원문에 따르면 처음에는 한 번 통과할 수도 있다고 기록돼 있지만, 2019년 2월 이후로는 이 방식 자체가 차단된 것으로 정리됐습니다. send_keys가 키 입력을 프로그래밍 방식으로 직접 전달하기 때문에 사람이 타이핑하는 패턴과 달라, 자동화 소프트웨어로 판단된다는 것이 원문 주석의 설명입니다.


방법 2 — pyperclip 클립보드 붙여넣기 우회

send_keys가 막히는 이유가 키 입력 패턴 탐지라면, 실제 타이핑 대신 OS의 붙여넣기 이벤트를 활용하는 방식이 한 가지 대안이 됩니다. pyperclip으로 ID/PW 문자열을 클립보드에 올린 뒤, ActionChains로 Ctrl+V(Mac에서는 Cmd+V)를 입력하면 브라우저 입장에서는 OS 수준의 붙여넣기 이벤트로 인식됩니다.

아래 코드를 실행하려면 ActionChains, Keys, random, time 모듈이 모두 필요합니다. 코드 블록 상단의 import를 모두 포함해 사용하세요.

# 2021년 당시 기준: pip install selenium==3.141.0 pyperclip==1.8.2
import pyperclip
import time
import random
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys

userid = 'my_id'
userpw = 'my_pw'

# 클립보드에 input을 복사한 뒤 해당 내용을 actionChain을 이용해 로그인 폼에 붙여넣기
def copy_input(xpath, input):
    pyperclip.copy(input)
    driver.find_element_by_xpath(xpath).click()
    # ActionChains(driver).key_down(Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform() # win linux
    ActionChains(driver).key_down(Keys.COMMAND).send_keys('v').key_up(Keys.COMMAND).perform() # mac
    time.sleep(random.uniform(0,3))

def naver_log_in(id, pw) :
    driver.get(url)
    driver.implicitly_wait(10)
    time.sleep(random.uniform(1,2))

    copy_input('//*[@id="id"]', id)
    time.sleep(random.uniform(1,2))

    copy_input('//*[@id="pw"]', pw)
    time.sleep(random.uniform(1,2))

    driver.find_element_by_xpath('//*[@id="frmNIDLogin"]/fieldset/input').click()
    time.sleep(3)


naver_log_in(userid, userpw)

코드를 보면 implicitly_wait(10)으로 페이지 로드를 기다리고, random.uniform(0, 3) · random.uniform(1, 2) 같은 무작위 딜레이를 섞어 입력 단계 사이에 불규칙한 간격을 줍니다. Windows/Linux에서는 Keys.CONTROL, Mac에서는 Keys.COMMAND를 사용해야 하며, 원문에도 적혀 있듯 linux에서 사용하기 까다롭다는 한계가 있습니다. pyperclip 자체가 OS 클립보드에 직접 접근하는 방식이라 GUI가 없는 환경에서는 추가 설정이 필요합니다.

이 한계를 극복하기 위해 찾은 것이 세 번째 방법, Python에서 키를 보내는 것을 완전히 포기하고 브라우저 안에서 JavaScript를 직접 실행하는 방식입니다.


방법 3 — execute_script로 JavaScript 직접 주입

세 번째 방법은 Python에서 키 입력을 보내는 것이 아니라, execute_script를 통해 브라우저 안에서 JavaScript가 직접 input 요소의 value를 세팅하는 방식입니다.

# (driver는 방법 1·2와 동일한 selenium==3.141.0 기준)
# execute_script 함수 사용 (자바스크립트로 아이디, 패스워드를 넘겨주는 형태)
driver.execute_script("document.getElementsByName('id')[0].value=\'"+id+"\'")
driver.execute_script("document.getElementsByName('pw')[0].value=\'"+pw+"\'")

driver.find_element_by_xpath('//*[@id="frmNIDLogin"]/fieldset/input').click()

원문 설명을 의역하면, “파이썬에서 키를 직접 넘겨주는 게 아니라 브라우저 내에서 자바스크립트로 아이디 값을 넘겨주기 때문에 네이버의 자동화된 소프트와 알고리즘을 우회하는 원리”입니다. 자동화 키 입력 탐지를 구조적으로 비껴가는 방식인 셈입니다.

단, 폼이 단순 value 속성 변경만으로 활성화되지 않는 경우가 있습니다. SPA(React·Vue처럼 JavaScript로 화면을 구성하는 앱) 기반 폼은 DOM 속성 변경과 상태 관리가 별개로 동작하는 경우가 있어 이 방식이 동작하지 않을 수 있습니다. 이는 SPA 폼 전반에 대한 일반론이며, 특정 서비스의 동작을 단정하는 것은 아닙니다.

원문에서는 세 가지 방법 중 이 execute_script 방식이 당시 가장 안정적으로 동작했다고 정리되어 있었습니다. 키 입력 이벤트를 완전히 우회하기 때문에 탐지 가능성이 낮고, OS별 클립보드 설정도 필요 없다는 점에서 실용적인 선택이었습니다.


2026년 시점 회고 메모

2021년에 정리한 메모인 만큼, 지금 시점에서 덧붙여 두면 좋을 내용이 몇 가지 있습니다.

Selenium 4 이후 메서드 변경: 본문에 등장하는 find_element_by_id, find_element_by_xpathfind_element_by_* 시리즈는 Selenium 4.0부터 deprecation warning이 발생하며, 향후 버전에서 완전 제거 예정입니다. 현재는 from selenium.webdriver.common.by import By를 임포트한 뒤 find_element(By.ID, '...') 형태로 쓰는 것이 권장됩니다. 새로 작성하는 코드라면 이 방식으로 전환하는 것이 좋습니다.

보안 강화 추세: 포털 로그인 보안은 그 사이 CAPTCHA, 디바이스 핑거프린팅 등 여러 방면으로 더 까다로워졌습니다. 이 학습 메모에서 소개한 우회 원리가 지금도 동일하게 통한다고 단정하기는 어렵습니다.

약관 주의: 자동 로그인은 서비스 약관 위반 소지가 있습니다. 학습 외 목적으로 실서비스에 운용하지 말 것을 권장합니다. 공식 기능 연동이 필요하다면 해당 서비스가 제공하는 공식 OpenAPI를 사용하는 것이 바람직하며, 코드에 자격 증명을 직접 작성하기보다는 환경변수나 시크릿 매니저로 분리하는 것이 일반적입니다.

이상 2021년 학습 메모에 2026년 보완 내용을 덧붙인 정리였습니다.


출처: cceeddcc.tistory.com/98

Similar Posts