乃木坂46のブログ内の画像を定期的に保存する

# はじめに
Qiitaで[Konaさんの記事](https://qiita.com/xxPowderxx/items/e9726b8b8a114655d796)を読んでいてGASを使ってドライブに自動保存できないかと思ったので作成。
前の月のブログの画像を毎日午前と午後に2人分、最大2*28(2月が28日間しかないので)=56人分保存できる。

# とりあえずコード全体
```blog.js
const memberList = [48006];

function getEntrysFromMember(memberId, startMask, endMask) {
  const entrysList = new Array();
  for (let page = 0; true; page++) {
    const startLength = entrysList.length;
    const html = UrlFetchApp.fetch(`https://www.nogizaka46.com/s/n46/diary/MEMBER/list?page=${page}&ct=${memberId}`).getContentText("UTF-8");
    const entrys = Parser.data(html).from("<a class=\"bl--card js-pos a--op hv--thumb\"").to("</a>").iterate();
    const memberName = Parser.data(html).from("<p class=\"bd--prof__name f--head\">").to("</p>").build().replace(/\s+/g, "") ?? memberName;
    for (const entry of entrys) {
      const entryDate = new Date(Parser.data(entry).from("<p class=\"bl--card__date\">").to("</p>").build());
      if (startMask <= entryDate) {
        if (entryDate < endMask) {
          const entryUrl = Parser.data(entry).from("href=\"").to("\">").build();
          entrysList.push([entryUrl, entryDate]);
        }
      } else {
        return [memberName, entrysList];
      }
    }
    if (entrysList.length != 0 && entrysList.length == startLength) {
      return [memberName, entrysList];
    }
  }
}

function downloadImages(memberName, entrys) {
  let imgInfoMap = new Map();
  for (const entry of entrys) {
    const html = UrlFetchApp.fetch(`https://www.nogizaka46.com${entry[0]}`).getContentText("UTF-8");
    const bodys = Parser.data(html).from("<div class=\"bd--edit\">").to("<div class=\"bd--pnv js-pos a--op\">").build().match(/(src=)["|'](.*?)\.(jpg|png|jpeg)["|']+/g);
    if (bodys == null) {
      continue;
    }
    const imgUrls = new Array();
    const dateStr = Utilities.formatDate(entry[1], "Asia/Tokyo", "yyyyMMdd");
    for (const body of bodys) {
      for (const url of body.match(/(images|files)(\/.*?)\.(jpg|png|jpeg)+/g)) {
        if (url.match(/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+/g)) {
          imgUrls.push(url);
        }
      }
    }
    if (typeof imgInfoMap.get(dateStr) === "undefined") {
      imgInfoMap.set(dateStr, imgUrls);
    } else {
      imgInfoMap.set(dateStr, imgUrls.concat(imgInfoMap.get(dateStr)));
    }
  }
  let folder = DriveApp.getRootFolder().getFoldersByName("乃木坂46").next();

  try {
    folder = folder.getFoldersByName(memberName).next();
  } catch (e) {
    folder.createFolder(memberName);
    folder = folder.getFoldersByName(memberName).next();
  }
  folder = folder.getFoldersByName("blog").next();
  const files = folder.getFiles();
  const filesList = new Array();
  while (files.hasNext()) {
    filesList.push(files.next().getName());
  }
  for (const imgInfo of imgInfoMap) {
    console.log(`Processing ${imgInfo[0]}`);
    for (let i = 0; i < imgInfo[1].length; i++) {
      const fileName = `${imgInfo[0]}_${i + 1}.jpeg`;
      if (filesList.indexOf(fileName) < 0) {
        const response = UrlFetchApp.fetch(`https://www.nogizaka46.com/${imgInfo[1][i]}`);
        const fileBlob = response.getBlob().setName(fileName);
        const file = DriveApp.createFile(fileBlob);
        file.makeCopy(file.getName(), folder);
        file.setTrashed(true);
      }
    }
  }
}

function pictureGetterEveryMonth() {
  const startDay = new Date();
  const endDay = new Date();
  const index = startDay.getHours() / 12 | 0 ? (startDay.getDate() - 1) * 2 + 1 : (startDay.getDate() - 1) * 2;

  if (index < memberList.length) {
    startDay.setMonth(startDay.getMonth() - 1);
    startDay.setDate(1);
    endDay.setDate(31);
    const retVal = getEntrysFromMember(memberList[index], startDay, endDay);
    if (retVal[0] != undefined) {
      downloadImages(retVal[0], retVal[1]);
    }
  }
}
```
# 使用方法
## 1.Google Drive上に画像を保存するためのフォルダを作る

- 今回はルート直下に以下のような構成で作成

```txt
乃木坂46
└── 遠藤さくら
    └── blog ←ここに保存する
```
## 2.プロジェクトの作成
[Google Apps Script](https://script.google.com/)でプロジェクトを作成してコードを貼り付ける。

## 3.ライブラリ追加
ライブラリの横の＋マークを押し、スクリプトIDに
`1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw`
を入力してParserライブラリを追加する
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378179/90687af9-f902-de22-cc48-b7f908f1c225.png)
## 4.トリガーを設定する
pictureGetterEveryMonthを午前と午後に毎日実行するために以下のような2つのトリガーを作成する。
(実行する時刻は午前と午後に分かれていればいつでも良い)
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378179/680330ef-e9b7-a74d-993e-db112dae59d7.png)

## 保存したいメンバーの追加
公式サイトのBLOG→メンバーを選択からメンバーを選択する。
その後表示されるページのURLの`ct=`のあとの数字をソースコードの最初にある`memberList`内に記載する。
例えば、遠藤さくらちゃんの場合はURLが`https://www.nogizaka46.com/s/n46/diary/MEMBER/list?ima=0115&ct=48006`なので`48006`を記載する


# 各関数のざっくりとした解説
今後追記予定