본문 바로가기
Python

[Python] InvalidURL Url Encode / Url 한글 처리

by bryan.oh 2021. 4. 20.
반응형

InvalidURL

urllib.request 를 사용할 때 Url 에 한글이나 특문이 있으면 오류가 발생할 수 있습니다.

아래와 같은 코드는 오류가 발생하죠.

 

from urllib.request import Request, urlopen

url = 'https://hello-bryan.tistory.com/manage/여기에 한글이 있다.txt'

req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})
res = urlopen(req)
if res.status == 200:
    print('성공')
else:
    print('실패코드 {}'.format(res.status))

InvalidURL

URL 에 공백이 있어서 그렇죠.

 

그럼 공백을 빼고 한글만 있다면?

url = 'https://hello-bryan.tistory.com/manage/여기에한글이있다.txt'

UnicodeEncodeError

이건 한글 뿐만 아니라 ascii 코덱이 인코딩 못하는 문자가 있을 때 발생합니다.

 

해결 방법.

urlsplit , quote 를 사용합니다.

from urllib.parse import urlsplit, quote

단순히 URL 을 quote 로 감싸면 안됩니다. 왜냐하면 아래와 같은 결과가 나오기 때문이죠.

from urllib.parse import urlsplit, quote


url = 'https://hello-bryan.tistory.com/manage/여기에한글이있다.txt'
encoded_url = quote(url)
print(encoded_url)
# https%3A//hello-bryan.tistory.com/manage/%EC%97%AC%EA%B8%B0%EC%97%90%ED%95%9C%EA%B8%80%EC%9D%B4%EC%9E%88%EB%8B%A4.txt

 저 encoded_url 로 request 하면 ValueError 가 발생합니다. (https:// 에서 : 를 인코딩해서 url로 인식못함)

그래서 protocol (http://, https://) 를 발라내고 파일path 를 구분해서 quote 해줘야겠죠.

이때 사용하는게 urlsplit 입니다.

from urllib.parse import urlsplit, quote

url = 'https://hello-bryan.tistory.com/manage/여기에한글이있다.txt'
url_info = urlsplit(url)
print(url_info)
# SplitResult(scheme='https', netloc='hello-bryan.tistory.com', path='/manage/여기에한글이있다.txt', query='', fragment='')

scheme, netloc, path, query, fragment 로 구분되어집니다.

그럼 이 scheme, netloc 은 그대로, path 는 quote 로 감싸서 다시 url을 만들어보면,

from urllib.parse import urlsplit, quote
from urllib.request import Request, urlopen

url = 'https://hello-bryan.tistory.com/manage/여기에한글이있다.txt'
url_info = urlsplit(url)
print(url_info)
# SplitResult(scheme='https', netloc='hello-bryan.tistory.com', path='/manage/여기에한글이있다.txt', query='', fragment='')

encoded_url = f'{url_info.scheme}://{url_info.netloc}{quote(url_info.path)}'
print(encoded_url)
# https://hello-bryan.tistory.com/manage/%EC%97%AC%EA%B8%B0%EC%97%90%ED%95%9C%EA%B8%80%EC%9D%B4%EC%9E%88%EB%8B%A4.txt

req = Request(encoded_url, headers={'User-Agent': 'Mozilla/5.0'})
res = urlopen(req)
if res.status == 200:
    print('성공')  # 여기로 들어옴.
else:
    print('실패코드 {}'.format(res.status))

호출 성공입니다.

encoded_url = f'{url_info.scheme}://{url_info.netloc}{quote(url_info.path)}'

 

주의 query (파라메터) 가 있는 url 처리

url 을 생성하는 입장이라면 value 만 quote(value) 로 만들면 됩니다.

위 예제에서는 query ( = url 파라메터 ) 를 신경쓰지 않았지만

만약에 파라메터가 있는 url 이라면, (여기에한글이있다.php?name=브라이언&greet=하잉~)

url_info.query 는 name=브라이언&greet=하잉~ 이 됩니다. 

그럼 & 로 구분하고 key=value 가 나오면 = 로 구분해서 value 만 quote 해서 다시 = 붙히고 & 로 붙혀야 할거같아요.

음.. 이건 나중에 시간 되면..ㅋ

.
.
.

> 만들어야 할 일이 있어서 적어봅니다 ㅋㅋ

위 소스에 이어서 url_info.query 에 파라메터가 있다면 아래와 같이 처리할 수 있습니다.

parse_qsurlencode 를 추가합니다.

from urllib.parse import urlsplit, quote, parse_qs, urlencode
if url_info.query:
    enc_param = dict()
    params = parse_qs(url_info.query)
    for key, val in params.items():
        enc_param[key] = quote(val[0])
    encoded_url = f'{encoded_url}?{urlencode(enc_param)}'

aaa=bbb&ccc=ddd 라면 aaa=quote(bbb)&ccc=quote(ddd) 로 변경하는 소스입니다.

좀더 짧게 코드를 만들고 싶다면 

if url_info.query:
    enc_params = list(map(lambda item: (item[0], quote(item[1][0])), parse_qs(url_info.query).items()))
    encoded_url = f'{encoded_url}?{urlencode(enc_params)}'

 

전체 샘플 코드

from urllib.parse import urlsplit, quote, urlparse, parse_qs, urlencode
from urllib.request import Request, urlopen

url = 'https://hello-bryan.tistory.com/manage/여기에한글이있다.php?name=브라이언&greet=하잉~'
url_info = urlsplit(url)
print(url_info)

encoded_url = f'{url_info.scheme}://{url_info.netloc}{quote(url_info.path)}'
print(encoded_url)

if url_info.query:
    enc_params = list(map(lambda item: (item[0], quote(item[1][0])), parse_qs(url_info.query).items()))
    encoded_url = f'{encoded_url}?{urlencode(enc_params)}'

req = Request(encoded_url, headers={'User-Agent': 'Mozilla/5.0'})
res = urlopen(req)
if res.status == 200:
    print('성공')
else:
    print('실패코드 {}'.format(res.status))

 

 

 

728x90
반응형

댓글