Skip to content

Instantly share code, notes, and snippets.

@chwnam
Last active March 29, 2025 05:16
Show Gist options
  • Save chwnam/5b583ecb6bafa7f8b25de41827f3d510 to your computer and use it in GitHub Desktop.
Save chwnam/5b583ecb6bafa7f8b25de41827f3d510 to your computer and use it in GitHub Desktop.
스타벅스 와이파이 자동 인증 파이썬3 스크립트
#!/usr/bin/env python3
import time
from http.cookiejar import Cookie
from re import search, findall
from urllib.parse import urlencode
from urllib.request import (
HTTPCookieProcessor,
HTTPRedirectHandler,
Request,
build_opener
)
class RedirectionCheckHandler(HTTPRedirectHandler):
"""
302 리다이렉션이 일어났는지 점검하기 위한 핸들러
"""
def __init__(self):
self.code = ''
self.redirect_url = ''
def http_error_302(self, req, fp, code, msg, headers):
self.code = code
self.redirect_url = ''
return super().http_error_302(req, fp, code, msg, headers)
class KtStarbucksAutoAuthorize(object):
"""
KT 스타벅스에 자동으로 접속 인증합니다.
{"result_cd":"0000"} 이라는 응답이 들어오면 성공입니다.
"""
def __init__(self):
self.cooke_processor = HTTPCookieProcessor()
self.redirect_handler = RedirectionCheckHandler()
self.opener = build_opener(self.redirect_handler, self.cooke_processor)
def authorize(self):
"""
스타벅스 와이파이 네트워크에 인증 처리를 시도합니다.
"""
url = self.step1_check_captive_network()
if not url:
print("이미 인증 된 것 같은데요? 인터넷 잘 쓰세요!")
return
data = self.step2_post_form(url)
if not data:
print('스타벅스 지점을 못 찾았네요...')
return
print(self.step3_authorize(data))
def step1_check_captive_network(self):
"""
captive network 점검입니다. http 쪽으로 테스트를 해서 302 응답이 날아오는지 점검합니다.
"""
response = self.get_response('http://detectportal.firefox.com/success.txt')
if self.redirect_handler.code != 302:
return ''
html = response.read().decode('utf-8')
found = search('location.href = "(http://.+)";', html)
if not found:
return ''
return found.group(1)
def step2_post_form(self, url):
"""
step1 에서 302 리다이렉션의 주소로 접속을 시도합니다.
응답으로 아주 심플한 자바스크립트를 얻게 됩니다. 이 스크립트를 통해 재차 리다이렉션이 일어날 것을 기대하고 있습니다.
리다이렉션을 통해 접속한 URL 에서는 폼을 발견할 수 있습니다. 이 폼 양식을 POST 전송하게 되어 있습니다.
간단하게 HTML 홈 양식을 분석해 웹브라우저를 흉내냅니다.
"""
response = self.get_response(url)
html = response.read().decode('euc-kr')
# step3에 사용할 쿠키를 구워 둡니다. 스크립트와 정확히 동작하게 한다는 가정하에 작성하였으나,
# 테스트 결과 없어도 큰 문제는 없었습니다.
# cookie_found = findall('<script language="javascript">document.cookie="(.+?)";</script>', html)
# if cookie_found:
# for cookie in cookie_found:
# self.set_cookie(cookie, 'first.wifi.olleh.com')
form_found = findall('<input type="hidden" name="(.+?)" value="(.+?)">', html)
if not form_found:
return ''
data = {key: value for key, value in form_found}
self.get_response(
url='http://first.wifi.olleh.com/starbucks/index_en.html', # 폼이 전송될 곳은 정해져 있습니다.
data=data
)
return data
def step3_authorize(self, data):
"""
step2 에서 POST 전송을 보내면, 비로소 웹브라우저 화면과 유사한 사용자 동의 체크박스가 나오는 화면의 HTML 문서를 전달받습니다.
웹브라우저에서 사용자 동의 체크 박스가 나오는 화면입니다.
여기서 마지막으로 인증을 위한 POST 요청을 보내면 됩니다. 이 때 referer 필드는 중요합니다.
"""
print('data', data);
data = {
'firstflag': 'starbucks',
'branchflag': data['branchflag'] if 'branchflag' in data else '',
'lang': 'en',
'devicecode': 'pc',
'ip': data['ip'],
'secure_id': '',
'ssid': data['ssid'],
'mac': data['mac']
}
print('data', data)
response = self.get_response(
url='http://first.wifi.olleh.com/starbucks/auth_issue.php',
data=data,
referer='https://first.wifi.olleh.com/starbucks/index_kr.html'
)
return response.read().decode('utf-8').strip()
def get_response(self, url, data=None, referer=None):
if data:
data = urlencode(data).encode('utf-8')
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0',
'Accept': '*/*',
'Accept-Language': 'ko,en-US;q=0.7,en;q=0.3',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
}
if referer:
headers['Referer'] = referer
request = Request(
url=url,
data=data,
headers=headers
)
return self.opener.open(request)
def set_cookie(self, cookie_string, domain):
"""
쿠키를 굽습니다. 인증 과정에 있어 중요한 요소는 아닌 것 같지만, 가급적 웹브라우저의 요청/응답과 유사하게 하기 위해 구현해 두었습니다.
"""
params = {
"version": 0,
"name": '',
"value": '',
"port": None,
"port_specified": False,
"domain": '',
"domain_specified": False,
"domain_initial_dot": False,
"path": '/',
"path_specified": True,
"secure": False,
"expires": None,
"discard": True,
"comment": None,
"comment_url": None,
"rest": {},
"rfc2109": False
}
items = cookie_string.split(';')
key_val = items[0].split('=')
name = key_val[0].strip()
value = key_val[1].strip()
params['name'] = name
params['value'] = value
for item in items[1:]:
key_val = item.split('=')
key = key_val[0].strip()
val = key_val[1].strip()
params[key] = val
params['domain'] = domain
if params['expires']:
pattern = '%a, %d %b %Y %H:%M:%S %Z'
epoch = int(time.mktime(time.strptime(params['expires'], pattern)))
params['expires'] = epoch
self.cooke_processor.cookiejar.set_cookie(Cookie(**params))
if __name__ == '__main__':
KtStarbucksAutoAuthorize().authorize()
@chwnam
Copy link
Author

chwnam commented Jul 28, 2019

아래 BASH 쉘 스크립트는 위 파이썬 스크립트를 보조하는 스크립트입니다.

#!/bin/bash

# kt_starbucks

SSID=$(iwgetid -r | tr '[:upper:]' '[:lower:]')
SCRIPT='/path/to/kt_starbucks.py' # 파이썬 스크립트의 경로를 입력해 두세요
LOG='/path/to/log' # 마지막 실행 결과를 기록해 둡니다.
USER='user' # 사용자의 계정을 입력해 두세요

if [[ ${SSID} != 'kt_starbucks' ]]; then
    echo 'Are you at Starbucks?'
    exit
fi

if [[ ! -x ${SCRIPT}  ]]; then
    echo 'The script is not executable!'
    exit
fi

sudo --user=${USER} ${SCRIPT} 2>&1 | tee ${LOG}

주석을 참고하여 자신의 환경에 맞게 수정하세요. 그리고 우분투에서는 이 스크립트를 /etc/network/if-up.d 경로에 심볼릭 링크를 걸어두세요. 인터넷 연결 변경시 자동으로 동작합니다.

@lifefeel
Copy link

lifefeel commented Sep 5, 2019

잘 쓰고 있습니다. Mac에서 인증창이 안 뜰때가 자주 있었는데, 이 스크립트로 인증 잘 통과합니다.

@chwnam
Copy link
Author

chwnam commented Mar 1, 2023

2023년에도 잘 동작한다!

@Zeta611
Copy link

Zeta611 commented Jul 2, 2024

와 대박입니다..

@chwnam
Copy link
Author

chwnam commented Jan 10, 2025

2025년도에도 잘 도악한다!

@tanji3000
Copy link

tanji3000 commented Jan 14, 2025

File "/opt/homebrew/Cellar/[email protected]/3.12.8/Frameworks/Python.framework/Versions/3.12/lib/python3.12/urllib/request.py", line 1347, in do_open
raise URLError(err)
urllib.error.URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>

저는 에러가 나는데 코멘트 해주실 분 계신가요? ㅠ macos 최신버전, python3.12 입니다.

@chwnam
Copy link
Author

chwnam commented Jan 14, 2025

File "/opt/homebrew/Cellar/[email protected]/3.12.8/Frameworks/Python.framework/Versions/3.12/lib/python3.12/urllib/request.py", line 1347, in do_open raise URLError(err) urllib.error.URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>

저는 에러가 나는데 코멘트 해주실 분 계신가요? ㅠ macos 최신버전, python3.12 입니다.

저도 MacOS에서 이 스크립트를 씁니다. 문제가 없는데, 아마 AP(Access Point)에 접속하지 않고 스크립트를 실행한게 아닌가 생각됩니다.
우선 st_starbucks 같은 AP에 접속하신 후, 스크립트를 실행해야 합니다. @tanji3000

@tanji3000
Copy link

File "/opt/homebrew/Cellar/[email protected]/3.12.8/Frameworks/Python.framework/Versions/3.12/lib/python3.12/urllib/request.py", line 1347, in do_open raise URLError(err) urllib.error.URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>
저는 에러가 나는데 코멘트 해주실 분 계신가요? ㅠ macos 최신버전, python3.12 입니다.

저도 MacOS에서 이 스크립트를 씁니다. 문제가 없는데, 아마 AP(Access Point)에 접속하지 않고 스크립트를 실행한게 아닌가 생각됩니다. 우선 st_starbucks 같은 AP에 접속하신 후, 스크립트를 실행해야 합니다. @tanji3000

답변주셔서 감사합니다. AP에 접속이후에 스크립트를 실행해서 기존에도 잘 쓰고 있었는데, 언제부터인가 동작이 안되더라구요.
다른 매장 스타벅스에서 동일한지 확인해봐야겠네요. 원인을 못찾고 있습니다. ㅠㅠ 감사합니다. @chwnam

@tanji3000
Copy link

아 문제를 확인했네요. AP에 접속을 하고 captive network 인증창이 하나 뜨는데, 그 창을 닫지 않으면 위와 같은 에러가 납니다.
창을 닫고 실행하니 정상적으로 동작하네요 😊 정말 정말 편하게 잘 쓰고 있습니다. 감사합니다. @chwnam

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment