본문 바로가기

프로그래밍/Python

[Python|Jupyter] 노트북(.ipynb)을 nbconvert 로 html 로 변환하다 UnicodeDecodeError 가 발생하였다.

728x90

주피터 노트북으로 데이터를 분석하고, 그 결과물을 .html 로 변환하려 하였다.

변환메뉴를 선택하였으나, 변환되지 않고, 다음과 같은 UnicodeDecodeError가 발생하였다.

Traceback (most recent call last):
  File "D:\Python3664\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "D:\Python3664\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "D:\PyEnvs\aicpu3664\Scripts\jupyter-nbconvert.EXE\__main__.py", line 9, in <module>
  File "d:\pyenvs\aicpu3664\lib\site-packages\jupyter_core\application.py", line 266, in launch_instance
    return super(JupyterApp, cls).launch_instance(argv=argv, **kwargs)
  File "d:\pyenvs\aicpu3664\lib\site-packages\traitlets\config\application.py", line 658, in launch_instance
    app.start()
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\nbconvertapp.py", line 338, in start
    self.convert_notebooks()
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\nbconvertapp.py", line 508, in convert_notebooks
    self.convert_single_notebook(notebook_filename)
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\nbconvertapp.py", line 479, in convert_single_notebook
    output, resources = self.export_single_notebook(notebook_filename, resources, input_buffer=input_buffer)
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\nbconvertapp.py", line 408, in export_single_notebook
    output, resources = self.exporter.from_filename(notebook_filename, resources=resources)
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\exporters\exporter.py", line 179, in from_filename
    return self.from_file(f, resources=resources, **kw)
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\exporters\exporter.py", line 197, in from_file
    return self.from_notebook_node(nbformat.read(file_stream, as_version=4), resources=resources, **kw)
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\exporters\html.py", line 90, in from_notebook_node
    return super(HTMLExporter, self).from_notebook_node(nb, resources, **kw)
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\exporters\templateexporter.py", line 299, in from_notebook_node
    nb_copy, resources = super(TemplateExporter, self).from_notebook_node(nb, resources, **kw)
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\exporters\exporter.py", line 139, in from_notebook_node
    nb_copy, resources = self._preprocess(nb_copy, resources)
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\exporters\exporter.py", line 316, in _preprocess
    nbc, resc = preprocessor(nbc, resc)
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\preprocessors\base.py", line 47, in __call__
    return self.preprocess(nb, resources)
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\preprocessors\csshtmlheader.py", line 55, in preprocess
    resources['inlining']['css'] = self._generate_header(resources)
  File "d:\pyenvs\aicpu3664\lib\site-packages\nbconvert\preprocessors\csshtmlheader.py", line 132, in _generate_header
    header.append(f.read())
  File "D:\Python3664\lib\codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb3 in position 133: invalid start byte

nbconvert 패키지를 최신(5.5.0)으로 업데이트 해 보았으나, 이미 최신이었고, 구글에서 동일한 문제를 겪는 사람이 있는지 찾아보았으나, 찾아지지 않았다.

결국, 트레이스백의 csstmlheader.py 파일을 찾아가 보았다. 문제가 발생한 132번째 줄 근처의 코드는 다음과 같다.

        if os.path.isfile(custom_css_filename):
            if DEFAULT_STATIC_FILES_PATH and self._default_css_hash is None:
                self._default_css_hash = self._hash(os.path.join(DEFAULT_STATIC_FILES_PATH, 'custom', 'custom.css'))
            if self._hash(custom_css_filename) != self._default_css_hash:
                with io.open(custom_css_filename, encoding='utf-8') as f:
                    header.append(f.read())
        return header

코드를 살펴보니, 단순히 custom.css 파일을 utf-8 인코딩으로 열고(open), 내용을 읽어(f.read)들이는 동작이다.

코드의 custom.css 라는 파일명을 보니, jupyter 의 기본 폰트가 맘에 들지 않아서, 다른 블로그를 참조하여 custom.css 를 만들었던 기억이 났다. 그리고, 폰트는 제일 좋아하는 나눔고딕코딩으로 커스텀했었고, 파일을 찾아열어보니, 폰트명이 다음과 갈이 한글로 들어있다.

.rendered_html pre, .rendered_html code, pre, .CodeMirror, .prompt {
  font-family: "나눔고딕코딩", Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;;
}

그리고, 아마 메모장으로 편집을 하면서, euc-kr 인코딩으로 저장이 되었던 듯 하다. euc-kr 인코딩으로 0xb3aa 이므로, 에러메시지의 0xb3와 부합한다.

custom.cssutf-8 인코딩으로 다시 저장하여 문제가 해결됐다.