質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.53%
Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Docker

Dockerは、Docker社が開発したオープンソースのコンテナー管理ソフトウェアの1つです

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

2回答

1981閲覧

Python+Flask+PandasでAS400のデータを抜き出す際の文字化けについて

horio

総合スコア13

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Docker

Dockerは、Docker社が開発したオープンソースのコンテナー管理ソフトウェアの1つです

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2022/05/10 07:12

編集2022/05/26 10:47

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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

助言頂いた内容を色々と試したのですが、文字化けは治りませんでした。
ただ、回避は出来ましたのでクローズとさせて頂きます。
回避策としては、ODBCが原因であるのは明らかでしたので、JDBCを利用する方法で実装する方針に変更しました。
こちらの方法だと文字化けは発生しませんでした。

AS400.py

1import jaydebeapi 2import pandas as pd 3 4conn = jaydebeapi.connect("com.ibm.as400.access.AS400JDBCDriver", "jdbc:as400://XXX.XXX.XXX.XXX", ["UID", "PAS"], "/App/jt400.jar",) 5 6def AS400_df(): 7 # SQLを生成 8 cur = conn.cursor() 9 sqlstring = "適当なSQL" 10 cur.execute(sqlstring) 11 12 # フレームを生成 13 df = pd.read_sql(cur.fetchall()) 14 15 curs.close() 16 conn.close() 17 18 return df

投稿2022/05/26 01:47

horio

総合スコア13

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

答えではありませんが、

コンテナ内からisqlでAS400に接続し、データを抜き出した場合は文字化けしませんでした。

上記ということは、環境に依存しているように見えます。

文字のエンコードとしてはUTF-8に統一していると思っています。

と、記載がありますが、「思っている」は危険なので本当に統一されているか確認した方が良いです。

Webでありがちなのが以下だと思うので、1つずつ潰してみてはいかがでしょうか?

  1. DBの設定が想定と異なる文字コードになっている(別の文字コードが指定されている)
  2. DBの設定は正しいが、異なる文字コードの文字を入力している(正しい文字コードを設定したが、別の文字コードの値を入力してしまっている)
  3. DBから取得する時の文字コードが異なる(データを取得する時の文字コードの扱いが想定と異なる)
  4. DBから取得した値の文字コードの扱いが異なる(データを取得した後の保持する文字コードが想定と異なる)
  5. Web側に渡す時に文字コードが変更されている
  6. ブラウザの表示文字コードが想定と異なる
  7. 参照していると思っているものと異なるものを参照している(別DBとか、そもそも埋め込んでましたとか)

簡単な物からやるのが良いと思いますが、def AS400_df():辺りで正しいデータが表示できるか確認してみるのもありかもしれません。

回答できる人が凄く少なそうな質問なので、頑張ってデバッグするか、もっと一般化した問題として挙げ直すかした方が回答が来る気がします。

投稿2022/05/12 07:00

FiroProchainezo

総合スコア2385

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

horio

2022/05/13 05:27 編集

FiroProchainezo様 コメント頂きありがとうございます。 エンコードの点、再確認してみたいと思います。 本件、デバッグを続けていますが、python上のODBCで抜き取った時点で既に特定の文字が化けているようで、unixodbc/pyodbc/ibm_db_saの複合動作な点が怪しいと思っています。 他の方からの回答も待ちつつ、デバッグ作業を続けてみます。
FiroProchainezo

2022/05/13 05:12

書き忘れていました。 Flaskを使うなら、SQLAlchemyではなくFlask-SQLAlchemyを使った方が良いと思います。 若干モデルの書き方が異なりますが、他の人が作ってくれてるFlask用のSQLAlchemyなので単にSQLAlchemyを使うよりも問題が少なくなる可能性があります。 (Flask-SQLAlchemyを使った場合、pandasが使用可能なのかどうかは未確認です) また、SQLAlchemy(Flask-SQLAlchemy)のモデルを作ってpandasを使わずアクセスしたら文字化けするのかしないのかも確認した方が良いと思います。 pandasは高機能なので何かしてくれてるのかもしれませんし。 モデル作るのが面倒な場合は、生SQLを実行可能なので、そちらでも良いかもしれません。 https://www.sukerou.com/2019/04/sqlalchemysqlsql.html
horio

2022/05/13 05:31

度々コメント頂きありがとうございます。 「Flask-SQLAlchemy」は知りませんでしたので、早速試してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.53%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問