SBI証券の外国株式配当金支払通知書からデータを抜き出す

 確定申告の季節になりましたね。メインの証券会社としてSBI証券を使っています。暫く前から「My資産」というサマリーページが出来て、便利になりましたが、外国株式の配当金から引かれた外国の源泉徴収税の一覧が得られませんでした。

このページに説明されているのですが、特定口座(源泉徴収あり、配当受け入れ)以外の場合には、都度発行の様です。同じ日に支払われた場合には一つの支払い通知書に複数の支払が記載されています。

外国で支払った源泉徴収税を取り戻したり、分離課税にするか、総合課税にするか、申告不要にするかの検討をする際にspreadsheetにまとまっていると便利ですよね。ネットで検索しつつpythonのプログラムでSBIの支払通知書を読んで、データを取り出すことに成功したので、記事にしました。試したのは米国で外貨決済のものだけです。他国のADR等で別の処理が必要なものもあるかもしれません。

PDFファイルからテーブルを読み出すのにはcamelotというライブラリを使います。pip3でインストール出来ますが、ghostscriptを使いますので、必要なら別途homebrew等でインストールします。

取り敢えず一つ読んでみたら、(1) 日本語が読めない、(2) テーブルがうまく読めない、という状況でこれは駄目そうか、と諦めかけたのですが、line_scaleというパラメタを大きな値に設定したところうまく読めました。

以下にプログラムを示します。まずは必要なモジュールをインポートします。

import camelot
import pandas as pd
from pathlib import Path

次はpandasのDataFrameを作る準備をします。

cols = ["配当金等支払日", "国内支払日", "現地基準日", "銘柄コード",
        "1単位あたり金額", "数量", "配当金等金額", "外国源泉徴収税額",
        "外国精算金額", "国内源泉徴収税額", "受取金額",
        "申告レート基準日","申告レート", "為替レート基準日", "為替レート",
        "配当金等金額(円)", "外国源泉徴収税額(円)", "国内課税所得額(円)",
        "所得税(外貨)", "地方税(外貨)", 
        "所得税(円貨)", "地方税(円貨)"]
df = pd.DataFrame(index=[], columns=cols)
year = 2023
file_dir = Path.home() / "Documents" / "金融" / "投資記録" / str(year) / "SBI" / "SBI外貨建支払い通知書"

このディレクトリにある全てのPDFファイルを順番に読んで処理します。

for file in file_dir.glob("*.pdf"):
    print(file)
    tables = camelot.read_pdf(str(file), split_text=True, layout_kwargs = {'char_margin': 0.25}, line_scale=40)
    for i in range(0, tables.n, 2):
        s = pd.DataFrame([[pd.to_datetime(tables[0+i].df.loc[1,0], format='%Y/%m/%d'),
                           pd.to_datetime(tables[0+i].df.loc[1,1], format='%Y/%m/%d'),
                           pd.to_datetime(tables[0+i].df.loc[1,2], format='%Y/%m/%d'),
                           tables[0+i].df.loc[1,4],
                           float(tables[0+i].df.loc[3,2]),
                           int(tables[0+i].df.loc[5,0]),
                           float(tables[0+i].df.loc[5,1]),
                           float(tables[0+i].df.loc[5,2]),
                           #tables[0+i].df.loc[5,3],                   
                           float(tables[0+i].df.loc[5,6]),
                           float(tables[0+i].df.loc[5,8]),
                           float(tables[0+i].df.loc[5,14]),
                           pd.to_datetime(tables[1+i].df.loc[2,0], format='%Y/%m/%d'),
                           float(tables[1+i].df.loc[2,1]),
                           pd.to_datetime(tables[1+i].df.loc[3,0], format='%Y/%m/%d'),
                           float(tables[1+i].df.loc[3,1]),
                           int(tables[1+i].df.loc[2,2].replace(",","")),
                           int(tables[1+i].df.loc[2,3].replace(",","")),
                           int(tables[1+i].df.loc[2,4].replace(",","")),
                           float(tables[1+i].df.loc[2,6]),
                           float(tables[1+i].df.loc[2,7]),
                           int(tables[1+i].df.loc[3,6].replace(",","")),
                           int(tables[1+i].df.loc[3,7].replace(",",""))],],
                         columns = cols,
                         index = [pd.to_datetime(tables[0+i].df.loc[1,1], format='%Y/%m/%d')])
        df = pd.concat([df if not df.empty else None, s])

最後の部分だけ少し注釈を入れます。

  • read_pdfのところで、str(file)としているのは、何故かPathオブジェクトが受け入れられなかったからです。
  • 同じくread_pdfで、line_scale = 40が肝でした。char_marginオプションは不要かもしれません。試行錯誤の名残です。
  • うまく読めると一つの支払いについて二つのテーブルが作られます。一つ目がメインのテーブルで、二つ目が「国内源泉徴収税の明細」のテーブルです。メインのテーブルからcolsのうちの受取金額までを、国内源泉徴収税の明細のテーブルから残りを読み取ります。
  • 一つの支払い毎にDataFrameを作って、それをconcatしています。別のやり方ももちろんあると思います。
  • for i in range(0, tables.n, 2):で、一つのPDFファイルで複数の支払いがあった日に対応しています。
  • read_pdfが作るDataFrameのセルは全部文字列の様なので、新しいDataFrameには日付・float・intに変換して入れています。locで指定している場所は、一旦読んでみてPDFと照らし合わせあせながら指定しています。
最後にxlsxファイルに書き出します。


df.to_excel("sbi_shiharai.xlsx")

以上です。

コメント

このブログの人気の投稿

建築士さんと家を建てよう

資産の記録を自動化してみた

米国の年金の受給申請をした