-
-
Save chwnam/5b583ecb6bafa7f8b25de41827f3d510 to your computer and use it in GitHub Desktop.
#!/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() |
잘 쓰고 있습니다. Mac에서 인증창이 안 뜰때가 자주 있었는데, 이 스크립트로 인증 잘 통과합니다.
2023년에도 잘 동작한다!
와 대박입니다..
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 입니다.
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
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
아 문제를 확인했네요. AP에 접속을 하고 captive network 인증창이 하나 뜨는데, 그 창을 닫지 않으면 위와 같은 에러가 납니다.
창을 닫고 실행하니 정상적으로 동작하네요 😊 정말 정말 편하게 잘 쓰고 있습니다. 감사합니다. @chwnam
아래 BASH 쉘 스크립트는 위 파이썬 스크립트를 보조하는 스크립트입니다.
주석을 참고하여 자신의 환경에 맞게 수정하세요. 그리고 우분투에서는 이 스크립트를
/etc/network/if-up.d
경로에 심볼릭 링크를 걸어두세요. 인터넷 연결 변경시 자동으로 동작합니다.