※この記事の続きです。
前回までの課題の解消
次は、Ajaxを使って部分View読み込みをしたいと思っていたのですが、前回までの課題の解消を先にやりたいと思います。
とりあえず画面に表示できるところまで行きましたが、3点課題がありました。
- 課題1. 毎回のように以下の処理を呼び出しているので、デザイン調整や特定箇所のロジック改善をやりだすと不要な処理がある。特にAPI呼び出しとZip解凍は時間がかかる。
- API呼び出し。
- Zip解凍
- 役員情報を読み込む
- データを加工する。
- 課題2. データが無駄に取れている。
- 課題3. テーブルの列幅が整ってない。
課題1の対応:デザイン調整や特定箇所のロジック改善をやりだすと不要な処理がある。
API呼び出しとZip解凍を除いたリロード用の処理を作る。
サーバー側で新しくメソッドを追加します。
def reload(request):
file = os.getcwd() + "\XBRL\PublicDoc\jpcrp030000-asr-001_E01777-000_2018-03-31_01_2018-06-19.xbrl"
data = get_information_about_officers_text(file)
soup = BeautifulSoup(data.text)
corporate_officer_list = get_corporate_officer_list(soup)
context = {'corporate_officer_list': corporate_officer_list, 'corporate_officer_list_count': len(corporate_officer_list)}
return render(request, 'edinet/corporate_officer_list.html', context)
URLのマッピングも追加します。
urlpatterns = [
path('', views.corporate_officer_list, name='corporate_officer_list'),
path('call-edinet-api', views.call_edinet_api, name='call_edinet_api'),
path('reload', views.reload, name='reload'), # 追加
]
画面にボタンを追加します。
<a href="{% url 'reload' %}" class="btn btn-lg btn-secondary">Reload</a>
これで時間のかかっていたAPI呼び出しとZip解凍をスルーして進めることが出来ました。
今回は、ネタ元のXBRLファイルがローカルにあるので取れる対応です。
ただ、今回のように中間ファイル的なものが存在していなくても、似たようなことはやれます。
例えば、フロント寄りの処理だけ調整したい場合は、JavaやC#の開発でやっていたのは、DIで差し込むService入れ替えてしまうというやり方です。
課題2の対応:データが無駄に取れている。
画面に出して気が付きましたが、データが無駄に取れていました。
明らかにデータが多い。
def get_corporate_officer_list(soup):
corporate_officer_list = list()
for table in soup.find_all("table"):
for tr in table.find_all_next("tr"): # ここに問題あり!!!
column_value_list = list()
if len(tr.find_all("td")) > 7:
for child in tr.children:
if child.name == "td":
column_value_list.append(child.get_text().replace('\n', '/'))
if len(column_value_list) > 0:
corporate_officer = create_corporate_officer(column_value_list)
corporate_officer_list.append(corporate_officer)
return corporate_officer_list
table
の要素をfind_allする部分は良かったのですが、次のtr
をfind_all_next
するところに問題がありました。
-
table
の要素をループする。 - ループのたびに
tr
をfind_all_next
する。 - 結果、
table
の要素数分、HTMLに含まれるtr
がすべて取れる。
という形です。
これでは、まずいので処理を見直しました。
def get_corporate_officer_list(soup):
corporate_officer_list = list()
for table in soup.find_all("table"):
for tableChild in table.children:
if tableChild.name == "tbody":
for tr in tableChild.children:
if tr.name == "tr":
column_value_list = list()
if len(tr.find_all("td")) > 7:
for trChild in tr.children:
if trChild.name == "td":
column_value_list.append(trChild.get_text().replace('\n', '/'))
if len(column_value_list) > 0:
corporate_officer = create_corporate_officer(column_value_list)
corporate_officer_list.append(corporate_officer)
return corporate_officer_list
ちゃんとHTMLの構成に沿って、Childを辿っていくやり方です。
これでlist_count = 17
になり、有価証券報告書に記載の男性15名 女性2名
とも合致します。
課題3の対応:テーブルの列幅が整ってない。
CSSを適用することにしました。一部、bootstrapのtable-responsiveを使用しています。
CSSの配置場所や読み込み方は、こちらの記事を参考にさせていただきました。
.edinet-table {
width:1900px;
}
.position {
width:200px;
}
.job {
width:200px;
}
.name {
width:200px;
}
.birthday {
width:200px;
}
.biography {
width:700px;
}
.term {
width:200px;
}
.stock {
width:200px;
}
HTML側に適用します。
<div class="table-responsive">
<table class="table table-bordered table-striped table-dark edinet-table">
<thead>
<tr>
<th class="position">役名</th>
<th class="job">職名</th>
<th class="name">氏名</th>
<th class="birthday">生年月日</th>
<th class="biography">経歴</th>
<th class="term">任期</th>
<th class="stock">株式数</th>
</tr>
</thead>
<tbody>
{% for corporate_officer in corporate_officer_list %}
<tr>
<td class="position">{{corporate_officer.position}}</td>
<td class="job">{{corporate_officer.job}}</td>
<td class="name">{{corporate_officer.name}}</td>
<td class="birthday">{{corporate_officer.birthday}}</td>
<td class="biography">{{corporate_officer.biography | linebreaks }}</td>
<td class="term">{{corporate_officer.term}}</td>
<td class="stock">{{corporate_officer.stock}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
これでだいぶ体裁が整いました。自分のPCの画面幅は超えているのでtableの縦横スクロールが出ている状態です。height
は指定していませんが、これは経歴がパラパラと縦に続くためです。
実は、経歴の加工ロジックにも課題があるのですが、こちらは実際の業務で手動も含めて、だいぶ苦労して対応しているので、ロジック修正は控えます。
次は、Ajaxを使って部分View読み込みをしたいと思います。