-
-
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경로에 심볼릭 링크를 걸어두세요. 인터넷 연결 변경시 자동으로 동작합니다.