Python+Flask+PandasでAS400のデータを抜き出す際の文字化けについて
Python+Flask+PandasでDBMSからデータ抽出する簡易的なシステムを構築し、Dockerコンテナ化して稼働させる取り組みをしています。
Dockerホスト機としてはQNAPのNASを、クライアント機としてはWin10のChromeブラウザを使用しています。
複数のDBMSからデータを抜き出す必要があるのですが、その内でAS400(IBMi)からデータを抜き出し、HTML表示すると一部の文字だけが化けてしまう事象に嵌っています。
文字のエンコードとしてはUTF-8に統一していると思っています。
【化ける文字の一部】
勝、線、ミ、高、川、竜、寛、軟…(気になるのは全て3バイト目が”9〇”の文字になります)
(↑ブラウザ表示の例です。”高木”と出力しています。)
コンテナ内からisqlでAS400に接続し、データを抜き出した場合は文字化けしませんでした。
何か妙案等をご存じの方がいらっしゃいましたら、ご教示を宜しくお願い致します。
以下、ソースコードになります。
app.py
1from flask import Flask, render_template, request, make_response 2from flask_bootstrap import Bootstrap 3from AS400 import * 4import pandas as pd 5 6app = Flask(__name__) 7bootstrap = Bootstrap(app) 8 9# ホームページ 10@app.route('/') 11def index(): 12 return render_template('index.html') 13 14# PSQL用 15# ここは上手く行くので割愛 16 17# AS400用 18@app.route('/AS400') 19def AS400(): 20 return render_template('AS400.html') 21 22# 結果の表示ページ 23@app.route('/result', methods=['GET', 'POST']) 24def result(): 25 26 # データフレームを生成 27 df = AS400_df() 28 29 if request.method == 'POST': 30 if 'generate' in request.form: 31 # データフレームをhtmlに変換 32 classes = 'table table-striped table-bordered table-hover table-sm thead-dark' 33 df_result = df.to_html(index=True, classes=classes) 34 35 return render_template('result.html', \ 36 dataframe = df_result) 37 else: 38 return render_template('index.html') 39 40 def get_key_from_values(dict, val): 41 return [k for k, v in dict.items() if v == val] 42 43if __name__=='__main__': 44 app.run(host='0.0.0.0', port=ポート番号, debug=True)
AS400.py
1from sqlalchemy import create_engine 2import urllib 3import pandas as pd 4 5quoted = urllib.parse.quote_plus("DSN=AS400DSN;uid=UID;pwd=PWD?charset=utf8") 6engine = create_engine('ibm_db_sa+pyodbc:///?odbc_connect={}'.format(quoted)) 7 8def AS400_df(): 9 # SQLを生成 10 sqlstring = "適当なSQL" 11 12 # フレームを生成 13 df = pd.read_sql(sql=sqlstring, con=engine) 14 return df
index.html
1{% extends 'base.html' %} 2{% block title %}INDEX{% endblock %} 3{% block content %} 4<div class="container"> 5 <form action="/result" method="POST"> 6 <h2>index</h2> 7</div> 8{% endblock %}
AS400.html
1{% extends 'base.html' %} 2{% block title %}AS400{% endblock %} 3{% block content %} 4<div class="container"> 5 <h1><u>AS400</u></h1> 6 <form action="/result" method="POST"> 7 <input type="submit" class="btn btn-primary btn-lg" name="generate" value="表示"> 8 </form> 9</div> 10{% endblock %}
base.html
1{% extends 'bootstrap/base.html' %} 2<!DOCTYPE html> 3<html lang="ja"> 4<head> 5 <meta charset="UTF-8"> 6 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 7 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 8 <link rel="stylesheet" href="../static/css/style.css"> 9 <title>{% block title %}{% endblock %}</title> 10</head> 11 12{% block body %} 13 <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script> 14 <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script> 15 <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script> 16 {% block navbar %} 17 <div class="navbar navbar-inverse" role="navigation"> 18 <div class="container"> 19 <div class="navbar-header"> 20 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> 21 <span class="sr-only">Toggle navigation</span> 22 <span class="icon-bar"></span> 23 <span class="icon-bar"></span> 24 <span class="icon-bar"></span> 25 </button> 26 <a class="navbar-brand" href="/">TEST</a> 27 </div> 28 <div class="navbar-collapse collapse"> 29 <ul class="nav navbar-nav"> 30 <li><a href="/">Home</a></li> 31 <li class="nav-item dropdown"> 32 <a class="nav-link text-secondary dropdown-toggle my-2 ml-3" href="#" data-toggle="dropdown" id="navbarDropdownMenuLink" aria-haspopup="true" aria-expanded="false">Tools</a> 33 <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> 34 <li><a class="dropdown-item" href="PSQL">PSQL</a></li> 35 <li><a class="dropdown-item" href="AS400">AS400</a></li> 36 </ul> 37 </li> 38 </ul> 39 </div> 40 </div> 41 </div> 42 {% endblock %} 43 {% block content %} 44 {% endblock %} 45{% endblock %} 46</html>
result.html
1{% extends 'base.html' %} 2{% block title %}RESULT{% endblock %} 3{% block content %} 4<div class="container"> 5 <button type="button" onclick="history.back()">戻る</button> 6 {{ dataframe | safe }} 7 <button type="button" onclick="history.back()">戻る</button> 8</div>> 9{% endblock %}
Dokerfile
1FROM python:3.8.11-slim-buster 2 3RUN pip install --upgrade pip 4RUN pip install flask 5RUN pip install flask-bootstrap 6RUN pip install pandas 7RUN pip install openpyxl 8RUN pip install xlsxwriter 9RUN pip install sqlalchemy 10 11# IBMからDLしたAS400(IBMi)のクライアントアクセス 12# このファイルにODBCが含まれている 13COPY ./ibm-iaccess-1.1.0.15-1.0.amd64.deb /usr/local/install/ 14 15RUN apt-get update && apt-get install -y \ 16 /usr/local/install/ibm-iaccess-1.1.0.15-1.0.amd64.deb \ 17 libpq-dev \ 18 gcc \ 19 g++ \ 20 python-pyodbc \ 21 unixodbc-dev \ 22 unixodbc 23RUN pip install pyodbc 24 25RUN pip install ibm_db 26RUN pip install ibm_db_sa 27 28WORKDIR /App 29COPY ./App/ /App 30COPY odbc.ini /etc/ 31 32CMD python app.py
Dockerコンテナを生成し、稼働したコンテナ内のODBC情報は以下の通りです。
odbcinst.ini
1[IBM i Access ODBC Driver] 2Description=IBM i Access for Linux ODBC Driver 3Driver=/opt/ibm/iaccess/lib/libcwbodbc.so 4Setup=/opt/ibm/iaccess/lib/libcwbodbcs.so 5Driver64=/opt/ibm/iaccess/lib64/libcwbodbc.so 6Setup64=/opt/ibm/iaccess/lib64/libcwbodbcs.so 7Threading=0 8DontDLClose=1 9UsageCount=1 10 11[IBM i Access ODBC Driver 64-bit] 12Description=IBM i Access for Linux 64-bit ODBC Driver 13Driver=/opt/ibm/iaccess/lib64/libcwbodbc.so 14Setup=/opt/ibm/iaccess/lib64/libcwbodbcs.so 15Threading=0 16DontDLClose=1 17UsageCount=1
odbc.ini
1[AS400DSN] 2Description = iSeries Access ODBC Driver 3Driver = IBM i Access ODBC Driver 4System = XXX.XXX.XXX.XXX 5Name = XXX.XXX.XXX.XXX 6UserID = ユーザID 7Password = パスワード 8CCSID = 01208
回答2件
あなたの回答
tips
プレビュー
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。