지난 포스팅에서 json 파이썬 표준 라이브러리를 통해서 JSON 데이터를 처리하는 방법에 대해 알아 보았습니다.
이번 포스팅에서는 urllib 표준 라이브러리에 대해 공부해 보도록 하겠습니다.
파이썬 표준 라이브러리
urllib
urllib 라이브러리는 URL 을 읽고 분석 할 때 사용되는 모듈입니다.
개발 공부하시는 분들이 많이 알고 싶어하시는 웹 크롤링을 할 때 자주 사용되기도 합니다.
인터넷 브라우저로 스마트뎁(smartdev.kr) 의 특정한 페이지를 읽고 싶다면 아래와 같이 사용하면 됩니다.
https://smartdev.kr/페이지 번호 또는 구분기호 (예 : https://smartdev.kr/80-파이썬-json-표준-라이브러리/)
그럼 위의 웹페이지를 오프라인에서도 읽을 수 있도록 페이지 번호를 입력 받아서 smartdev.kr 의 특정 페이지를 smartdev_페이지 번호 또는 구분기호.html 로 저장하는 함수는 어떻게 만들면 좋을까요?
URL 을 호출을 해서 원하는 리소스를 얻으려면 urllib 모듈을 사용하면 됩니다.
# urllib_test.py
import urllib.request
def get_smartdev(page):
resource = 'https://smartdev.kr/{}'.format(page)
with urllib.request.urlopen(resource) as s:
with open('smartdev_%s.html' % page, 'wb') as f:
f.write(s.read())
print(get_smartdev('80-파이썬-json-표준-라이브러리'))
위 코드에서 get_smartdev(page) 함수는 스마트뎁(smartdev.kr)의 페이지 번호를 입력 받아서 해당 페이지의 리소스 내용을 파일로 저장을 해주는 함수입니다.
urllib.request.urlopen(resource, context=context)로 s 객체를 생성을 하고 s.read() 함수로 리소스 내용의 전체를 읽어 들여 html 파일로 저장을 할 수 있게 해줍니다.
하지만 위 코드를 실행하게 되면 아래처럼 로그 같은 것들이 쭉 나오면서 마지막에 UnicodeEncodeError 오류가 나오게 됩니다.
(py_study_31010) D:\Dropbox\02.My_Job\80.Study\01.Python\00.study_python_3.11.0\01.TEST>python urllib_test.py
Traceback (most recent call last):
File "D:\Dropbox\02.My_Job\80.Study\01.Python\00.study_python_3.11.0\01.TEST\test.py", line 10, in <module>
print(get_smartdev('80-파이썬-json-표준-라이브러리'))
File "D:\Dropbox\02.My_Job\80.Study\01.Python\00.study_python_3.11.0\01.TEST\test.py", line 6, in get_smartdev
with urllib.request.urlopen(resource) as s:
File "C:\Users\donnr\anaconda3\envs\py_study_31010\lib\urllib\request.py", line 216, in urlopen
return opener.open(url, data, timeout)
File "C:\Users\donnr\anaconda3\envs\py_study_31010\lib\urllib\request.py", line 519, in open
response = self._open(req, data)
File "C:\Users\donnr\anaconda3\envs\py_study_31010\lib\urllib\request.py", line 536, in _open
result = self._call_chain(self.handle_open, protocol, protocol +
File "C:\Users\donnr\anaconda3\envs\py_study_31010\lib\urllib\request.py", line 496, in _call_chain
result = func(*args)
File "C:\Users\donnr\anaconda3\envs\py_study_31010\lib\urllib\request.py", line 1391, in https_open
return self.do_open(http.client.HTTPSConnection, req,
File "C:\Users\donnr\anaconda3\envs\py_study_31010\lib\urllib\request.py", line 1348, in do_open
h.request(req.get_method(), req.selector, req.data, headers,
File "C:\Users\donnr\anaconda3\envs\py_study_31010\lib\http\client.py", line 1282, in request
self._send_request(method, url, body, headers, encode_chunked)
File "C:\Users\donnr\anaconda3\envs\py_study_31010\lib\http\client.py", line 1293, in _send_request
self.putrequest(method, url, **skips)
File "C:\Users\donnr\anaconda3\envs\py_study_31010\lib\http\client.py", line 1131, in putrequest
self._output(self._encode_request(request))
File "C:\Users\donnr\anaconda3\envs\py_study_31010\lib\http\client.py", line 1211, in _encode_request
return request.encode('ascii')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 8-10: ordinal not in range(128)
위 오류는 문자 인코딩과 관련된 오류입니다. ‘ascii’ 코덱은 기본적으로 ASCII 문자만 처리할 수 있으므로, ASCII 범위를 벗어나는 문자를 인코딩하려고 할 때 발생합니다.
URL 에 한글 또는 특수 문자를 포함하는 경우에 발생합니다.
이를 해결하기 위해서는 URL 을 인코딩해야 합니다
import urllib.parse
import urllib.request
def get_smartdev(page):
encoded_page = urllib.parse.quote(page)
resource = 'https://smartdev.kr/{}'.format(encoded_page)
with urllib.request.urlopen(resource) as s:
with open('smartdev_{}.html'.format(page), 'wb') as f:
f.write(s.read())
get_smartdev('80-파이썬-json-표준-라이브러리')
위의 코드 에서 처럼 urllib.parse.quote 함수를 사용하여 페이지 이름을 URL 인코딩하여 encoded_page 변수에 저장합니다. 그런 다음 resource 변수에서 이 인코딩된 페이지 이름을 사용하여 URL을 구성합니다.
이렇게 수정하면 URL 인코딩에 문제를 해결하고 해당 오류가 발생하지 않게 됩니다.
아래 처럼 smartdev_80-파이썬-json-표준-라이브러리.html 파일이 잘 생성된 것을 확인 할 수 있습니다.

- 이 포스팅은 ‘위키독스’ 의 ‘점프 투 파이썬‘ 전자책을 구매하여 독학하기 위한 자료로 작성했습니다.
