DjangoでWebアプリを作ってみる。【vol. 07 有価証券報告書から抜き出した役員情報を加工する。】

※[こちら](https://qiita.com/TsJazz27Sumin/items/776eea0c6d0ac823d0f6)の記事の続きです。
### HTMLからスクレイピングしたデータを加工する。

前回完了時点では以下のように不要なものが混じってます。
主に改行やスペースです。※改行は分かりやすいように「/」に変換しています。
あと数字が全角だったり半角だったりするので統一感がありません。

```
...
//執行役//
-------------------------------------
//常務///（R&Dプラットフォーム担当、メディカル事業担当）//
-------------------------------------
//勝本　徹//
-------------------------------------
//1957年10月14日生//
-------------------------------------
/ ///////////////1982年４月/////当社入社///////2012年11月/////当社業務執行役員 SVP///////2013年４月/////ソニー・オリンパスメディカルソリューションズ㈱
代表取締役社長///////2016年１月/////ソニー・オリンパスメディカルソリューションズ㈱ 取締役（現在）///////2017年１月/////当社メディカルビジネスグループ長///////2017年４月/////ソニーイメージングプロダクツ&ソリューションズ 代表取締役副社長（現在）///////2018年４月/////当社執行役 EVP///当社R&Dプラットフォー
ム担当、メディカル事業担当（現在）///////2018年６月/////当社執行役 常務（現在）/////// /
-------------------------------------
//*//
-------------------------------------
//1//
...
```

そこでまず不要なものを削ったり、数字の半角寄せをするメソッドを用意します。

```py
number_translate_dictionary = {"０":"0","１":"1","２":"2","３":"3","４":"4","５":"5","６":"6","７":"7","８":"8","９":"9"}
trans_table = str.maketrans(number_translate_dictionary)

#...（中略）...

def process_item(item):
    return item.translate(trans_table).strip("/")
```

全角数字から半角数字に変換するために、辞書を用意し、translateメソッドを使用しています。
[こちら](https://qiita.com/tag1216/items/df6c93bdb823dd48af6c#strtranslate%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E6%9B%B8%E3%81%84%E3%81%9F%E5%A0%B4%E5%90%88)の記事に記載の内容になります。
そして、stripメソッドを使って項目の前後にある「/」を削っています。

続いて、各項目をモデルに詰め込むためのメソッドを用意します。
ここでは、役員情報が７列で構成されているので、引数であるcolumn_value_listには７項目入っている想定です。

念のため各項目を設定するときに`if`で確認をしています。
`process_item`で項目を加工しつつ、個別の項目によっては追加で`replace`をしています。

```py
from edinet.models import CorporateOfficer

#...（中略）...

def create_corporate_officer(column_value_list):
    corporate_officer = CorporateOfficer()

    if len(column_value_list) > 0:
        corporate_officer.position = process_item(column_value_list[0]).replace("/","")
    
    if len(column_value_list) > 1:
        corporate_officer.job = process_item(column_value_list[1]).replace("/","")
    
    if len(column_value_list) > 2:
        corporate_officer.name = process_item(column_value_list[2])
    
    if len(column_value_list) > 3:
        corporate_officer.birthday = process_item(column_value_list[3])
    
    if len(column_value_list) > 4:
        corporate_officer.biography = get_biography_value(column_value_list)
    
    if len(column_value_list) > 5:
        corporate_officer.term = process_item(column_value_list[5])
    
    if len(column_value_list) > 6:
        corporate_officer.stock = process_item(column_value_list[6])
    
    return corporate_officer
```

経歴だけ複数行に渡って構成されているので、別途加工用のメソッドを用意しています。

```py
import re

#...（中略）...

def get_biography_value(column_value_list):
    biography = process_item(column_value_list[4])
    biography_list = biography.split("/")

    number = 1
    value = ""
    for target in biography_list:
        if target.strip() != "":
            if re.search("[0-9]",target):
                number = 1

                if value.strip() != "":
                    value += "\n"

            if number == 1:
                value += target + " "
                number += 1
                continue

            if number == 2:
                value += target
                continue
    return value
```

一度、「/」でsplitしてリストに変換してから、数字が含まれるものは左辺、それ以外は右辺という形で`2017年4月 ソニーイメージングプロダクツ&ソリューションズ 代表取締役副社長（現在）`といった経歴の１行を構成していきます。

`CorporateOfficer`のリストを作って行く処理は、こういった形です。

```py
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
```

わかりやすさを優先して、一度`column_value_list`に必要な１行分の項目を詰めて、`create_corporate_officer`を使って、`CorporateOfficer`のインスタンスを生成、そしてリストに詰めています。

最終的にこういった形で`print`してみました。

```py
            corporate_officer_list = get_corporate_officer_list(soup) 

            for corporate_officer in corporate_officer_list:
                print("-------------")
                print("【役名】")
                print(corporate_officer.position)
                print("【職名】")
                print(corporate_officer.job)
                print("【氏名】")
                print(corporate_officer.name)
                print("【生年月日】")
                print(corporate_officer.birthday)
                print("【経歴】")
                print(corporate_officer.biography)
                print("【任期】")
                print(corporate_officer.term)
                print("【株式数】")
                print(corporate_officer.stock) 
```

結果は、こんな感じです。だいぶきれいになりました。

```
...

【役名】
執行役
【職名】
常務（R&Dプラットフォーム担当、メディカル事業担当）
【氏名】
勝本　徹
【生年月日】
1957年10月14日生
【経歴】
1982年4月 当社入社
2012年11月 当社業務執行役員 SVP
2013年4月 ソニー・オリンパスメディカルソリューションズ㈱ 代表取締役社長
2016年1月 ソニー・オリンパスメディカルソリューションズ㈱ 取締役（現在）
2017年1月 当社メディカルビジネスグループ長
2017年4月 ソニーイメージングプロダクツ&ソリューションズ 代表取締役副社長（現在）
2018年4月 当社執行役 EVP当社R&Dプラットフォーム担当、メディカル事業担当（現在）
2018年6月 当社執行役 常務（現在）
【任期】
*
【株式数】
1
```

次は、画面に表示してみたいと思います。