[ToyProject]自動化ゲーム名簿の作成(1)-GASの使用


0.本段階での構想


IMPORTXMLではなく、GASで名簿を簡潔に自動化します.フリップフロップが使えるので、もっといいです.😀

1.appsスクリプトの設定


デフォルト設定とコードは、2つの記事リンクGAS設定Cheerioの使用に置き換えられます.
上記の記事に基づいて、紅葉名簿を更新するための基本コードを作成します.GetMapleData.gs
function getContent_(name) { // 캐릭터 검색 결과 페이지를 반환
  const baseUrl = "https://maple.gg/u/";
  const url = baseUrl + name;
    try {
      const response = UrlFetchApp.fetch(url)
      if (response.getResponseCode() == 200) {
        return response.getContentText();
      }
      else {
        return null;
      }
    }
    catch (error) {
      Logger.log(error);
      return null;
    }
}
function getMapleData() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("명부"); // 시트 선택
  const datarange = sheet.getDataRange(); // 데이터 범위 가져오기
  const numRows = datarange.getNumRows(); // 총 행의 수 가져오기
  const namePos = 1; // 캐릭터명의 위치는 각 행의 1열임 
  const worlds = ["루나", "스카니아", "엘리시움", "크로아", "오로라", "베라", "레드", "유니온", "이노시스", "제니스", "아케인", "노바", "리부트1", "리부트2"];

  for (var i = 3; i <= numRows; i++) { // 3행부터 데이터가 있음
    const name = sheet.getRange(i, namePos).getValue(); // 캐릭터명 가져오기
    if (name === "" || worlds.includes(name)) { // 빈칸이거나 캐릭터명이 아닌 월드명일 경우 거름
      continue; 
    }
    html = getContent_(name);
    if (html === null) {
      Logger.log(name + ": 스크래핑 오류 발생!");
      continue;
    }
    const $ = Cheerio.load(html);
    console.log(name);
  }
}

function setSheetData(sheet, data){

}
  • getContent_(name):パラメータとしてロール名を受け入れ、ロール検索結果ページに戻る関数.エラー時にnullを返します.
  • getMapleData():ディレクトリに入力するデータを結果ページからscrapingする関数.次に、データ消去機能を追加します.
  • setSheetData():各ロール行にフレキシブルデータを入力するための関数.同様に、以下に機能を追加します.
  • 2. maple.消去gg


    1) robots.txt確認



    robots.txtをチェックすると、スクリプトには制約がありません.

    2)抽出要素


    次に、以前に作成したスクリプトに抽出要素のコードを追加して、getMapleData()を完了します.

    maple.ggの結果ページからセレクタパスをコピーし,cacheioにより各データを抽出する.GetMapleData.gs - getMapleData()
    
    ...
    
    function getMapleData() {
      const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("명부"); // 시트 선택
      const datarange = sheet.getDataRange(); // 데이터 범위 가져오기
      const numRows = datarange.getNumRows(); // 총 행의 수 가져오기
      const namePos = 1; // 캐릭터명의 위치는 각 행의 1열임 
      const worlds = ["루나", "스카니아", "엘리시움", "크로아", "오로라", "베라", "레드", "유니온", "이노시스", "제니스", "아케인", "노바", "리부트1", "리부트2"];
      let data = []; // 시트 입력용 데이터
    
      for (var i = 3; i <= numRows; i++) { // 3행부터 데이터가 있음
        const name = sheet.getRange(i, namePos).getValue(); // 캐릭터명 가져오기
        if (name === "" || worlds.includes(name)) { // 빈칸이거나 캐릭터명이 아닌 월드명일 경우 거름
          continue; 
        }
        html = getContent_(name);
        if (html === null) {
          Logger.log(name + ": 스크래핑 오류 발생!");
          continue;
        }
        const $ = Cheerio.load(html);
        let level, job, guild, mureung, union; // 긁어올 데이터들
        if ($('#character-card > div > ul.character-card-summary > li:nth-child(3) > span')) { // 레벨 데이터
          level = $('#character-card > div > ul.character-card-summary > li:nth-child(3) > span').text();
        }
        else {
          level = "NONE";
        }
        if ($('#character-card > div > ul.character-card-summary > li:nth-child(5) > span')) { // 직업 데이터
          job = $('#character-card > div > ul.character-card-summary > li:nth-child(5) > span').text();
        }
        else {
          job = "NONE";
        }
        if ($('#character-card > div > div:nth-child(3) > span')){
          guild = $('#character-card > div > div:nth-child(3) > span').text();
        }
        else {
          guild = "NONE";
        }
        if ($('#character-card > div > ul.character-card-additional > li:nth-child(1) > span')) { // 무릉도장 데이터
          mureung = $('#character-card > div > ul.character-card-additional > li:nth-child(1) > span').text();
        }
        else {
          mureung = "NONE";
        }     
        if ($('#character-card > div > ul.character-card-additional > li:nth-child(2) > small')) { // 유니온 데이터
          union = $('#character-card > div > ul.character-card-additional > li:nth-child(2) > small').text();
          if (union === "") {
            union = "정보없음";
          }
        }
        else {
          union = "NONE";
        }
        data.push([i, level, job, guild, mureung, union]); // 행 위치와 데이터를 함께 저장
        Utilities.sleep(1000); // 스크래핑 사이에 딜레이 삽입
      }
      setSheetData(sheet, data) // 데이터 한번에 입력
    }
    
    ...
    
  • let data = [];:後でsetSheetData()のロールデータに移動します.行の位置やロールデータなど.
  • Utilities.sleep(1000):サーバへの干渉を回避するために、スクリプト間に遅延を挿入します.
  • setSheetData():図面にデータを書き込むための関数で、直ちに実行します.
  • 3)データシートへの書き込み


    同様に、以前に作成したsetSheetData()を完了します.setValues()関数.
    GetMapleData.gs - setSheetData()
    
    ...
    
    function setSheetData(sheet, data){
      var colPos = 2; // 입력을 시작할 열의 위치
      var numRows = 1; // 입력할 행의 개수(범위)
      var numCols = 5; // 입력할 열의 개수(범위) 
      for (var datum of data) { 
        var input = []; // 입력할 정보만 따로 추출
        var rowPos = datum[0]; // 입력을 시작할 행의 위치 추출
        input.push(datum.slice(1)); // rowPos를 제외한 정보를 추출하고,setValues() 인자에 맞게 변환
        console.log(input);
        sheet.getRange(rowPos, colPos, numRows, numCols).setValues(input); // setValues()가 object[][]를 인수로 받음
      }
    }
    
  • sheet.getRange(rowPos, colPos, numRows, numCols).setValues(input):図面入力範囲を指定し、一度にデータを入力

  • 現在はGASオートマップを使用しておりますggからデータをキャプチャできます.

    3.トリガの設定


    トリガの詳細については、トリガの使用記事リンクを使用して置き換えてください.

    メフのキャラクターデータは午前3時から4時まで更新されるので、実行時間は일 단위 타이머(通常は午前10時)に設定し、定期的なチェック時間を考慮します.
    トリガなしでデータを自動的にリフレッシュできるレコードが完了しました.

    4.次の段階で悩む


    maple.GG情報更新ボタンは毎日押してこそ正常にデータを更新することができますが、これはどのように自動化すればいいですか?🤔

    5. Reference


    apps script refenrence - setValues
    GAS Cheerioライブラリ