TDnet(適時開示情報閲覧サービス)のサイトとHTML構造

  • URL

    1. トップページ:https://www.release.tdnet.info/inbs/I_main_00.html
      アクセスした日に公表された一覧が表示される。

    2. 指定日の一覧:https://www.release.tdnet.info/inbs/I_list_001_20200505.html
      指定日(2020/5/5)に公表された一覧が表示される。100件以上あればURLは002, 003,...と対応していく。

    3. 開示情報検索:https://www.release.tdnet.info/onsf/TDJFSearch/TDJFSearch
      日付・キーワードのパラメーターと一緒にPOSTすると、検索結果が返ってくる。単体でアクセスしても何も表示されない。

    BeautifulSoup等で解析する場合、2もしくは3を使うと便利である。

  • 2のケース
    URLの001と20200505の部分を任意の値にしBeautifulSoupで解析。日付は1か月程度さかのぼることができる。

    解析のポイント

    • 各要素のクラス名
      各要素においてoddnew-hogeとevennew-hogeと偶奇でクラス名が異なっており soup.hoge.find(class_=['oddnew-M kjCode','evennew-M kjCode'])とするとまとめて取得できる。

    • 日付
      HTMLのテーブルには時刻しか含まれないので、解析した時刻に加えURLで指定した日付をこのような形で変換する。
      import datetime as dt dt.datetime.strptime(DATE + TIME, '%Y/%m/%d %H:%M')

    • PDFやURLのリンク
      soup.hoge.find(class_=hoge).find('a').get('href')とaタグをはさんでhrefをgetすると取得できる。ただし、これは途中からの部分的なURLなので'https://www.release.tdnet.info/inbs/'を先頭につける必要がある。

    • 不要な空白
      会社名、上場取引所、更新履歴には不要な空白が含まれるので'文字列'.str.strip()として取り除く。


  • 3のケース
    response = requests.post('https://www.release.tdnet.info/onsf/TDJFSearch/TDJFSearch', data=data)としてresponse.textをBeautifulSoupで解析する。dataがパラメーターとなっており、 data = { 't0': 20200430, 't1': 20200501, 'q': u'業績予想', 'm': '0' } とすると、'業績予想'をキーワードに含む2020/4/30~2020/5/1に発表された一覧が取得できる。
    日本語など他バイト文字の場合、uを文字列の前につけないとエラーとなる。

    残りは2のケースと構造はおおむね同じである。

PythonにおけるPOST時のマルチバイト文字の扱い

requestsライブラリのrequests.post(url, data)のdataにパラメーターを渡すときにおける漢字などの扱いについて。

パラメータに漢字などの2バイト文字を入れたいとき、そのまま入力するとエラーになる。
ブラウザがPOSTする情報を見ると\u7d4c\u55b6のという形式で送信している。これはUnicodeエスケープシーケンスであり、Pythonでは u'経営' とすると正常に変換しPOSTできた。

'経営'.encode('unicode-escape').decode()などでも変換できるが、出力文字列は \\u7d4c\\u55b6 となり'\'が二重に出てしまう。これだとPOSTしてもエラーとなった。

pipenvでCythonをインストール(Windows)

pipenvでCythonのインストールではまったのでメモ。

シンプルに pipenv install cython では Installing dependencies from Pipfile.lock と表示され、79/100でタイムアウトしてしまう。Cythonの依存パッケージのインストールでエラーが出るようだ。

試行錯誤した結果、

  1. c++コンパイラ(MinGW64)をインストール
    配布元よりダウンロード・インストール
    http://mingw-w64.org/doku.php/start

  2. MinGW64にパスを通す
    "C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin" を環境変数に追加
    "x86_64-8.1.0-posix-seh-rt_v6-rev0" はインストールしたバージョンに対応する名前になる。

  3. pipenvの環境下にdistutils.cfgを作成
    以下のフォルダにdistutilsフォルダを作成、その中にdistutils.cfgを作成。
    "%homepath%/.virtualenvs/環境に対応したフォルダ/Lib"

[build]
compiler=mingw32

1-3を実行後だと pipenv install Cython で正常にインストールできた。

Excel VBAとGithub

Excel VBAのコードはxlsmファイルの形式ではバイナリ形式で認識されるため、直接Githubで管理できない。
今回はxlsmからコードを分離しbasファイルなどのモジュールにエクスポートすることで、Github管理する方法を紹介する。

まずはxlsmファイルからコードを分離する必要がある。
手動でもVBAのコード編集画面のファイルメニューやプロジェクトエクスプローラーから、モジュールのインポート・エクスポートは可能である。同じことをVBAでも実現できる。

  • インポート
    FilePathにインポートしたいファイルパスを指定する。
Private Function Import_Module()
    Const FilePath As String = "example.bas"
    ThisWorkbook.VBProject.VBComponents.Import FilePath
End Function
  • エクスポート
    ModuleNameにエクスポートしたいモジュール名を指定する。
Private Function Export_Module()
    Const ModuleName as String = "Module1"
    Dim objVBC As Object 'VBComponent
    Set objVBC = ThisWorkbook.VBProject.VBComponents(ModuleName)
    ThisWorkbook.VBProject.VBComponents.Remove objVBC
End Function

ここまでのコードで、xlsmファイルからコードを分離・取り込みすることが可能となる。

ここからはGithubに関連するコードを説明する。
以下はstrCMD()にシェルコマンドをセットし、ExecuteCMD()で実行するプログラムである。
ExecuteCMD()のCurrentDirectoryは、.gitフォルダと同じディレクトリにする必要がある。

Private Function gitPullAddCommitPush()
    Dim strCMD As String
        
    strCMD = "git pull"
    ExecuteCMD(strCMD)
    
    strCMD = "git add ."
    ExecuteCMD(strCMD)
    
    strCMD = "git commit -m revise"
    ExecuteCMD(strCMD)
    
    strCMD = "git push origin master"
    ExecuteCMD(strCMD)
End Function

Public Function ExecuteCMD(strCMD As String) 'CMDにコマンドを投げる
    Dim buf As String
    With CreateObject("Wscript.Shell")
        .CurrentDirectory = ThisWorkbook.Path
        buf = .Run(strCMD, WaitOnReturn:=True)
    End With
End Function

Export_Module()でモジュールを分離した後、gitPullAddCommitPush()を実行すれば、basファイルなどの形でコードをGithubで管理できる。

Excel VBA開発環境の色を変える

Excel等でマクロのコードを編集する画面の背景はデフォルトでは白である。
この画面の背景色・文字色は変更することができる。
f:id:kurama_sk:20200411190138p:plain

変更するには、VBA編集画面のメニューバー: ツール→オプション→エディターの設定 を開く。
f:id:kurama_sk:20200411185644p:plain

画像の設定は以下の通り。

  • 標準コード:前景 白、背景 黒
  • 選択された文字:(デフォルト)
  • 構文エラーの文字:前景 赤
  • 次のステートメント:背景 黄色、インジケーター 黄色
  • ブレークポイント:前景 白、背景 濃赤、インジケーター 濃赤
  • コメント:前景 緑、背景 黒
  • キーワード:前景 水色、背景 黒
  • 識別子:前景 ピンク、背景 黒
  • ブックマーク:前景 白、背景 黒、インジケーター 水色
  • 呼び出し元:前景 白、背景 黒、インジケーター 緑

前景は文字色のことである。背景を黒にする場合、基本的には背景は黒、前景は黒以外にすることとなる。
「キーワード」はDim、If、For、Subなどの予約語。「識別子」は定義した変数、関数、ThisWorkbookなどのオブジェクト。

vbsでExcel VBAを実行する

過去記事の「パターン1. 特定の場所にxlsmブックを作り、外部から参照する方法(Application.Run)」の補足。 以前は特定のファイルのVBAを実行する方法として、別ブックのSubプロシージャから起動する方法を説明した。

art-of-lives.hatenablog.com

今回はVBScriptから起動する方法を説明する。この方法だとvbsファイルをダブルクリックするだけでVBAの実行が可能。
イメージとしてはパターン1の呼び出し側のブックに記述されているVBAコードを、独立したファイルに外に出すものとなる。 コードも過去記事のパターン1であるVBA版コードを手直ししたものとなる。

Const FilePath = "C:\book.xlsm"
Const FunctionName = "call_msgbox"

With WScript.CreateObject("Excel.Application")
    .Visible = True 'Trueなら実行時にExcelの画面を表示
    .Workbooks.Open FilePath
    .Application.Run FunctionName
    .Quit
End With

メモ帳に上記コードをコピーして、ファイル名の最後を .vbs にすれば完成である。vbsファイルをダブルクリックすると C:\book.xlsm の call_msgbox という関数が呼び出される。
1行目のファイルパスと2行目の関数名は適宜変えることになる。

応用としてファイル名の変更が不要なバージョンも説明する。

FilePath = Replace(WScript.ScriptFullName, ".vbs", ".xlsm")
Const FunctionName = "main"

With WScript.CreateObject("Excel.Application")
    .Visible = True 'Trueなら実行時にExcelの画面を表示
    .Workbooks.Open FilePath
    .Application.Run FunctionName
    .Quit
End With

このファイルを .vbs で保存するほか、実行したいxlsmファイルと同じフォルダに xlsmファイルと同じ名前で保存(この例では book.vbs )する。関数名は main など適当な名前に決めておくと使い回したときにいちいち変える手間がない。このvbsファイルをダブルクリックすればbook.xlsmのmainプロシージャor関数が呼び出される。
変わったのは1行目のみで"WScript.ScriptFullName"で自分(book.vbs)のファイルパスを取得し.vbsを.xlsmに置換することで、呼び出すxlsmファイルのパスを作成する。

githubにサンプルをアップロードしている。 github.com

Excel VBAの管理方法2

前回記事のパターン2. basファイルをベースに管理し、実行時にxlsm化する方法(VBComponents.Import)について説明する。 art-of-lives.hatenablog.com

所定の場所のbasファイルを取り込んだ、新しいブックを作るVBAコードはこのようになる。

Private Function Import_bas()
    Const FilePath As String = "example.bas"
    Workbooks.Add.VBProject.VBComponents.Import FilePath
End Function

最もシンプルな使い方としては、この短いコードをあらかじめ記述したExcelブック(以下取り込み用Excel)と実際に使用したいbasファイルをセットでgithubに上げておく。
VBAのコード管理はbasファイルで行うとgithubで管理しやすく、最新のコードを各人各フォルダでbasからExcelに展開して使う事ができる。
githubがない環境でも、共有フォルダなど特定の場所にbasファイルを置き(この場合は相対パスではなく絶対パスを記述)、この取り込み用Excelで展開することでコードの管理が楽になると思われる。

以下メモ

  • FilePathにはファイル名しか記述していない。これは相対パスにすることで取り込み用Excelと同じフォルダの中しか取り込み対象としない。絶対パスでも問題ないが、basファイルの場所が変わると取り込み用Excelのコードも修正する必要がある。

  • 取り込み用Excelは起動するだけで自動実行されるようにしておくとと楽。または同様のVBScriptを作っておき、クリックするだけで実行されるようにしてもよい。

  • basファイルにAttribute VB_Name = "SampleModuleName"と記述しておくとその名前でExcelに登録される。何も書かなければModule1かその連番となる。

  • Workbooks.Addは新規に作成されたWorkbookオブジェクトである。これによりbasファイルが取り込まれただけの新しいブックが作成される。なお、この部分を置き換えることで、basファイルのインポート先を既存のワークブックにすることもできる。

  • basファイルはVBAでいう標準モジュールであり、他にもclsファイル(クラスモジュール)やfrmファイル(ユーザーフォーム)も対応可能。