본 포스팅은 이전 블로그로부터 백업된 글입니다.
이전 작성일: 2018-11-08
개요
저는 주로 어떤 사이트에 로그인을 실행하는 기능을 만들 때 Selenium과 Chrome Driver 이 두 개를 활용해 특정 Login Form이나 Html Tag를 찾아 selenium 모듈의 webdriver 객체의 "find_element_by_name" 과 같은 메서드를 이용합니다 헌데 이번에 쓰는 Urllib의 기능은 이런 순서와는 좀 다르게 쿠키값을 수정해 보내는 형식으로 로그인을 해보겠습니다. 'GET' 방식이나 'POST' 방식으로 로그인 하는 것도 가능하다고 합니다 이 글에서 쓰는 방식은 정확하게 말하면 보내는 쿠키 값을 수정하는 것이지만 POST 방식의 헤더를 수정하는 것이기 때문에 POST 방식도 될 수 있다고 생각합니다.
이용할 사이트는 https://mail.mokpo.ac.kr 이고 목포대학교의 웹 메일 URL 입니다. 저는 이 대학의 학생이기 때문에 ID 랑 Password 를 쓸 수 있지만 혹시나 이 글에 나온 코드를 그대로 따라 해보려고 하시는 분들은 제한적인 요소가 있으실 거라 생각되기 때문에 어디까지나 이러한 기능이 있구나 정도의 글로 봐주시면 감사합니다.
urllib.request & parse
import urllib.request
import urllib.parse
urllib를 쓰기 위한 기본적인 뼈대라 생각하시면 됩니다 urllib.request는 request를 urllib.parse는 urlencode을 수행하는 기능을 해줍니다.
http.cookiejar Module
import http.cookiejar
cj = http.cookiejar.LWPCookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
mail.mokpo.ac.kr 은 쿠키를 이용하기 때문에 클라이언트가 쿠키정보를 가지고 있어야 합니다 LWPCookieJar()라는 것은 사용할 쿠키를 초기화(?) 하는 것이고 HTTPCookieProcessor() 를 이용해 이 쿠키를 설정해줍니다 ( 아마도 사용할 쿠키를 실체화 시키는 로직 같습니다 ) 그렇게 초기화 시킨 쿠키를 build_opener를 통해 저장해두는 코드입니다
Setup
BaseURL = "http://mail.mokpo.ac.kr/"
url = "http://mail.mokpo.ac.kr/login_pool.jsp"
MailBoxURL = "http://mail.mokpo.ac.kr/leftmenu.jsp?color=red&gw_sms=null&gw_mail=true"
params = urllib.parse.urlencode(values)
params = params.encode("utf8")
req1 = urllib.request.Request(url,params)
res1 = opener.open(req1)
BaseURL은 처음에 접근할 URL을 의미합니다 여기서는 먼저 Login Page에 접속해야 하기 때문에 기본 Page의 URL 주소를 잡았습니다그 밑의 "url" 변수를 "http://mail.mokpo.ac.kr/login_pool.jsp"라는 주소를 초기화했습니다 실제 이 주소는 접근할 수 없는 주소 입니다 하지만 Login ID 와 Password를 보내서 실제로 로그인을 동작시키는 주소기 때문에 mail.mokpo.ac.kr에 로그인 하기 위해선 중요한 URL입니다. MailBoxURL은 "받은 편지함","보낸 편지함" 과 같은 기능을 이용할 수 있게 클라이언트가 서버에서 받아오는 하나의 Html Frame 과 같습니다
위의 사진은 burp suite를 사용해 Login 요청을 보내는 헤더를 잡은 내용입니다 보시면 POST 방식으로 login_pool.jsp에 무엇인가 보낸다는 라는 느낌을 받을 수 있습니다 그 내용은 밑에서 3번째 줄에 Cookie를 보시면 JESSIONID 와 그 밑의 LoginID 그리고 &x ,&y ,&password ,p_lang 등등 여러가지가 보이는 걸 알 수 있습니다 눈치가 빠르신 분들은 이미 아시겠지만 이 부분을 수정해서 보내게 되면 Login을 할 수 있게 되는 겁니다. "쿠키" 값을 어떻게 바꾸냐 하면 이미 언급했던 urllib.parse.encode(valuse) 를 이용하면 됩니다 values에 있는 내용은 Python에서는 Dict 형으로 설정해줘야 하고 그 내용은 다음과 같이 작성했습니다.
values = {
"LoginID":ID,
"x":"0",
"y":"0",
"password":password,
"p_lang":""
}
values 와 같은 형식으로 urlencode()를 수행하셨다면 그 밑에 줄에 encode("utf8')를 통해 bytes type으로 Casting(형변환)을 해줘야합니다
req1 = urllib.request.Request(url,params)
res1 = opener.open(req1)
res1 은 그 요청을 수행한 url 주소를 open합니다 (정확한 의미는 찾을 수 없었으나 제가 써 본 결과 open의 의미는 url이 포함하고 있는 Html 의 정보를 받아온다는 뜻으로 보입니다)
예외 처리
try:
GetMailBox = urllib.request.Request(MailBoxURL,params)
respone = opener.open(GetMailBox)
content = respone.read()
MailParsing+=content.decode("utf8")
except Exception as e:
print(e)
위에서 보이는 코드는 MailBoxURL에 보이는 주소의 값을 요청한 뒤 요청된 값을 저장한 뒤 "받은 편지함","보낸 편지함" 과 같은 정보를 담고 있는 Html Tag를 찾기 위해서 쓰는 코드입니다
굳이 예외 처리가 필요한가 싶은 정도의 코드이지만 burp suite로 보게 되면 MailBoxURL의 URL은 매번 Request를 할 때 마다 Request가 되는 Url Page가 다르기 때문에 MailBoxURL이 아닌 경우에는 ( 순서가 MailBoxURL 이 아닌 경우 ) Error를 내뿜으면서 종료가 됩니다. 예외처리는 이 MailBoxURL 맞을 때까지 찾고 나머지 URL 주소에 대해서는 pass를 시킵니다.
URL Filter
UrlFilter1 = []
UrlFilter2 = []
UrlFilter3 = []
MailLIst = []
UrlFilter1 += MailParsing.split(';')
for rd in UrlFilter1:
if "\r\n" in rd:
UrlFilter2.append(rd.replace("\r\n",''))
del UrlFilter1
for rd in UrlFilter2:
if "\t" in rd:
UrlFilter3.append(rd.replace('\t',''))
else:
UrlFilter3.append(rd)
del UrlFilter2
for rd in UrlFilter3:
SaveMailIndex = rd.find("list.jsp?")
SaveMailIndex2 = rd.find("')")
if SaveMailIndex != -1:
ClearUrl = rd[SaveMailIndex::].replace("')",'')
# print(ClearUrl)
MailLIst.append(ClearUrl)
이 부분은 자세하게 설명하면 길어지니 간단히 설명 드리자면 앞에서 받아왔던 MailBoxURL의 메일함을 Html Tag를 찾아 그 URL를 Parsing 해주는 코드입니다. MailLIst 변수는 그 Parsing 된 URL 주소만 뽑아서 담아주는 리스트 입니다
받은 편지함에 있는 내용의 HTML TAG 찾기
GetMailBox = urllib.request.Request(BaseURL+MailLIst[0], params)
res2 = opener.open(GetMailBox)
soup = BeautifulSoup(res2,"html.parser")
Table_Find = soup.find("td",{"width":"100%"})
Table_Find2 = Table_Find.find("table",{"class":"dataTable"})
MailList[0]는 "받은 편지함"에 있는 Url이 파싱된 문자열 타입의 data 입니다 이 부분을 거의 BaseURL에 연결해 접근하게 되면 받은 편지함에 접근 할 수 있습니다. res2는 그렇게 요청한 GetMailBox를 open 하고 BeautifulSoup를 이용해 html 구조를 관찰한 다음 Table_FInd 와 Table_Find2를 통해 받은 메일 목록을 가져옵니다 BeautifulSoup를 쓰실 때 따로 from bs4 import BeautifulSoup4로 import를 하셔야 사용이 가능합니다 설치가 안 되어 있으시면 pip install beatifulsoup4 로 설치하시면 됩니다.
나머지
DataString = ""
for rd in Table_Find2.findAll("td"):
DataString += rd.text
DataString = DataString.strip()
ScrapingSplitList,ScrapingSplitList2,ScrapingSplitList3 = [],[],[]
print("==== Scraping ! ====")
for rd in DataString:
if ' ' == rd:
ScrapingSplitList.append(' ')
if ' ' != rd:
ScrapingSplitList.append(rd)
tmpstr = str()
for rd in ScrapingSplitList:
if rd != '\xa0':
tmp = []
tmpstr += rd
tmp.append(tmpstr)
elif rd == '\xa0':
ScrapingSplitList2.append(tmp)
tmpstr = str()
for rd,count in zip(ScrapingSplitList2,range(len(ScrapingSplitList2))):
tmp = []
try:
if ScrapingSplitList2[count] == ScrapingSplitList2[count+1]:
ScrapingSplitList3.append(ScrapingSplitList2[count])
if count+1 == max(range(len(ScrapingSplitList2))):
ScrapingSplitList3.append(ScrapingSplitList2[count])
ScrapingSplitList3.append(ScrapingSplitList2[count+1])
except:
pass
DataString 변수는 Table_Find2 에서 찾은 받은 편지함의 텍스트 정보를 저장합니다 그 밑의 ScrapingSplitLIst 변수들은 텍스트 정보를 나눠서 각각 필터링 시켜주는 용도로 사용되었습니다
이런 과정을 거치면 위의 사진과 같이 결과가 나옵니다. 메일의 내용은 개인적인 정보라 가렸습니다
기타
urllib를 통해서 웹 메일 로그인을 시도해봤습니다. 비교적 밑에 있는 설명은 되게 짧은데 이 부분은 텍스트 정보를 어떻게 자르고, 나누고, 붙일까 라는 개념이기 때문에 urllib를 쓰는 것과는 다르기 때문에 짧게 적었습니다. 만들 떄는 어려웠지만 만들고 나서 보니 비교적 쉬운 코드네요 . 앞서 언급했듯이 예제를 따라하시는 게 제한적인 요소가 있을 겁니다. 저는 대학에 학적이 있는 상태라 이 학교 메일을 쓸 수가 있지만 다른 분들은 그렇지 않으신 분도 있을테니 이 글을 보시는 분들은 '이 사람은 urllib를 이렇게 사용했구나' 정도의 글로써 참고해주시면 감사합니다.
참고 URL
urllib 에서 cookie 를 생성하는 법:
'Language > Python' 카테고리의 다른 글
setuptools를 활용한 프로젝트 패키징 (1) | 2023.06.18 |
---|---|
함수에 적용되어있는 decorator를 알아내는 방법 (0) | 2023.05.05 |
pytest-django 에서 자주 사용했던 것들 (3) | 2023.03.19 |
Python을 이용한 UserAssist 레지스트리 분석하기 (0) | 2023.02.06 |
외부 APIResponse Data를 DataClass로 변경하기 (0) | 2023.02.01 |