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_qs 와 urlencode 를 추가합니다.
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))
'Python' 카테고리의 다른 글
[Python] convert uint16 to uint8 (0) | 2021.05.28 |
---|---|
[python] queue 를 list 로 (queue to list) (0) | 2021.05.04 |
Python 으로 Crawling 에 필요한 준비 (0) | 2021.04.15 |
[Python] remove list item. 리스트에서 아이템 삭제 방법(clear, pop, remove, del) (0) | 2021.03.25 |
[Python] PIL jpg png webp 변환 Image.convert() (0) | 2021.03.25 |
댓글