月でループする(クエリパラメータを動的に作成) VBA Python

スクレイピングで頻出するのは
開始日と終り日を入力
開始日から終わり日までループしながらなにかしらのデータを取得するというもの。

頻出のわりにはぴたっとはまるものがなかったのでメモ書き


http://test.jp?xx=202112
http://test.jp?xx=202201
のようにxx=202201のクエリパラメータ部分を動的に変更することで、各月のデータを取得する。


例えば
開始：2021/11/01
終了：2022/2/28
の場合
年月を表す文字列を以下のように順次作成し、
202111
202112
202201
202202
作成した文字列をクエリパラメータにして順次ページ遷移する


#vbaの場合
前提
windows10
##①DateDiff 関数でループに必要な月の差分を求める。
例・開始が2021年11月10日終了が2022年2月1日の場合、4か月
[DateDiff関数使い方](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/datediff-function)

##②必要な月数だけループする

##③ループ処理中でDateAdd関数を使い、開始月から１か月づつ足す。
[DateAdd関数使い方](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/dateadd-function)

##④　③で作成した日付型のデータをFormat関数でクエリパラメータ用に成形する
[Format関数使い方](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/format-function-visual-basic-for-applications)


##以下サンプル
開始日を2021/10/30　終了日を2022/2/28と設定
動的にパラメータを設定したいURLをhttps://test?xx=
したので、
https://test?xx=202110
https://test?xx=202111
https://test?xx=202112
https://test?xx=202201
https://test?xx=202202
とコンソールに出力される。

```:vba

Sub test()

    '開始日と終わり日を設定する
    Dim STARTDAY As String: STARTDAY = "2021/10/30"
    Dim LASTSDAY As String: LASTDAY = "2022/2/28"
     
    Dim mm As Long                  'forループで使う
    Dim hizukemozi As Date           '1か月後の日付
    Dim para As String               'クエリパラメータ用に成形する
    Dim url As String: url = "https://test?xx="    'クエリパラメータを使ってURLを動的に作成する
   
    '月の分だけループする
    For mm = 0 To DateDiff("m", STARTDAY, LASTDAY)
    
      hizukemozi = DateAdd("m", mm, STARTDAY)　　　'開始日に1月ずつ足す
      para = Format(hizukemozi, "yyyymm")           '日付を成形する
      Debug.Print (url & para)　　　　　　　　　　　'日付部分を動的に変更できた。
    Next mm

End Sub

```






#Pythonの場合
vbaをそのまま翻訳すればいいかと思いきや・・・
vbaのDateDiff関数に相当する関数を見つけることができなくて
地味に面倒でした。

##①月で計算するにはdateutil.relativedataを使うのが簡単

インストールされていない場合は以下でインストール。
windowsの場合

```:python
py -m pip install python-dateutil

```


<font color="red">(注)python-dateutil　コピペしたときに入れ替わってしまったのか、
python－dateutilとハイフンが全角になっていて。
pipインストール時にエラー。無駄な時間を過ごしました。</font>

[dateutil.relativedata解説](https://dateutil.readthedocs.io/en/stable/relativedelta.html)


##②strptime関数を使い日付文字列を日付型に変更する

[strptime関数解説](https://docs.python.org/ja/3/library/datetime.html#strftime-strptime-behavior)

##③開始日と終了日の月の差分を求める
VBAのDateDiff関数に相当するものを見つけることができなかったので
年と月それぞれでに引き算しました。

##④必要な月数だけループ処理する

##⑤dateutil.relativedelta関数でループ中の開始月に1か月づつ足していく
[dateutil.relativedelta関数解説](https://dateutil.readthedocs.io/en/stable/relativedelta.html)

<font color="red">(注)relativedelta(months=i) の　months=i monthの末尾にsがつく場合と　month=iのように末尾にsがつかない場合意味が違います。</font>
最初month=iにしていたため、年をまたいだ処理ができなくて無駄な時間を過ごしました。
monthsのように末尾にsがつくと相対参照になるらしいです。
今回はmonths=iとsがつくのが正解



```:python
import datetime
from dateutil.relativedelta import relativedelta

if __name__ == '__main__':

    startday="2021/10/30"      #開始日
    lastday="2022/2/28"        #終了日
    url = "https://test?xx="   #日付のパラメータを追加するURL

    #開始日終了日を日付型にする
    startday=datetime.datetime.strptime(startday,"%Y/%m/%d")
    lastday = datetime.datetime.strptime(lastday,"%Y/%m/%d")
    
    #開始日と終了日の月の差分を取得する
    sabun = (lastday.year-startday.year)*12+lastday.month-startday.month
    
    for i in range(0,sabun+1):

        start = startday   #開始日を設定する            
        loop=start+relativedelta(months=i)  #開始日に1か月づつ加算する
        para = loop.strftime("%Y%m")        #日付型データをクエリパラメータ用データに成形する
        print(url+para)        

```