勉強したことのメモ

Webエンジニア / プログラマが勉強したことのメモ。

GASで「カクヨム」の更新状況をスクレイピングで取得する

  Google Apps Script Google

Google Apps Scriptの勉強として「カクヨム」の指定した小説が更新された際に何らかの方法で通知を送りたい。以前に「小説家になろう」サイトにてAPIを用いて同じようなスクリプトを作成したが、今回はAPIが用意されていない為、スクレイピングを行う必要がある。以下に対応方法のメモ。

 

やりたいこと

スプレッドシートにNコードを入力しておくと定期的に「カクヨム」にリクエストし話数に変更があった場合、LINEやメールでその旨通知させたい。Nコードは「https://kakuyomu.jp/works/xxxxx/」の「xxxxx」部分にあたる。

尚、通知部分に関しては以下過去記事で取り扱ったので、今回は省略する。

スプレッドシートの作成

後で見たときにわかりやすいようA1~D1セルにカラム名を入力しておく。以下のような形。

シート名は「kakuyomu」とする。

 

ライブラリの追加

HTMLのソースコードから特定のデータを抽出する際にParserというライブラリが便利らしい。

スクリプトエディタページの左側にある「ライブラリ」をクリックするとダイアログが表示されるので、「1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw」にて検索し、Parserライブラリを追加する。

 

スクリプトの作成

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//カクヨム
function getKakuyomu(){
//スプレッドシートの読み込み
const sheet = SpreadsheetApp.getActiveSpreadsheet();
//シートを指定
const kakuyomuSheet = sheet.getSheetByName('kakuyomu');
//シートのデータ取得
const kakuyomuSheetVal = kakuyomuSheet.getDataRange().getValues();
//結果用配列
let resultVal = kakuyomuSheetVal;
//戻り値用変数
let returnMessage = '';
//ループ処理
for( let i = 1; i < kakuyomuSheetVal.length; i++ ){
//パース用オブジェクト
const parseData = new Object();
//通知用フラグ
let notifyFlg = false;
//行からデータ取得
const row = kakuyomuSheetVal[i];
const ncode = row[0];
const cnt = row[1];
const novelUpdate = row[2];
const sheetUpdate = row[3];
//URL指定
const novelUrl = 'https://kakuyomu.jp/works/' + ncode;
//HTMLデータ取得する
const html = UrlFetchApp.fetch(novelUrl).getContentText('UTF-8');
//小説の更新日時
parseData['novelUpdate'] = Parser.data(html).from('<p class="widget-toc-date"><time datetime="').to('Z"><span>').iterate();
parseData['novelUpdate'] = parseData['novelUpdate'][0].replace('T', ' ');
//全掲載部分数
parseData['general_all_no'] = Parser.data(html).from('<span class="js-vertical-composition-item">全').to('話</span>').iterate();
parseData['general_all_no'] = parseData['general_all_no'][0];
//小説の更新日時が変更されている場合
if( !novelUpdate || novelUpdate < parseData['novelUpdate'] ){
resultVal[i][2] = parseData['novelUpdate'];
}
//全掲載部分数が変更されている場合
if( !cnt || cnt < parseData['general_all_no'] ){
resultVal[i][1] = parseData['general_all_no'];
notifyFlg = true;
}
//チェック日時
const now = new Date();
const date = Utilities.formatDate(now, 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss');
resultVal[i][3] = date;
//全掲載部分数が変更されている場合
if( notifyFlg ){
returnMessage += "カクヨム更新通知\nhttps://kakuyomu.jp/works/" + ncode + "\n\n";
}
}
//シートにまとめて書き込み
kakuyomuSheet.getRange(1, 1, kakuyomuSheetVal.length,kakuyomuSheetVal[0].length).setValues(resultVal);
return returnMessage;
}
//カクヨム function getKakuyomu(){ //スプレッドシートの読み込み const sheet = SpreadsheetApp.getActiveSpreadsheet(); //シートを指定 const kakuyomuSheet = sheet.getSheetByName('kakuyomu'); //シートのデータ取得 const kakuyomuSheetVal = kakuyomuSheet.getDataRange().getValues(); //結果用配列 let resultVal = kakuyomuSheetVal; //戻り値用変数 let returnMessage = ''; //ループ処理 for( let i = 1; i < kakuyomuSheetVal.length; i++ ){ //パース用オブジェクト const parseData = new Object(); //通知用フラグ let notifyFlg = false; //行からデータ取得 const row = kakuyomuSheetVal[i]; const ncode = row[0]; const cnt = row[1]; const novelUpdate = row[2]; const sheetUpdate = row[3]; //URL指定 const novelUrl = 'https://kakuyomu.jp/works/' + ncode; //HTMLデータ取得する const html = UrlFetchApp.fetch(novelUrl).getContentText('UTF-8'); //小説の更新日時 parseData['novelUpdate'] = Parser.data(html).from('<p class="widget-toc-date"><time datetime="').to('Z"><span>').iterate(); parseData['novelUpdate'] = parseData['novelUpdate'][0].replace('T', ' '); //全掲載部分数 parseData['general_all_no'] = Parser.data(html).from('<span class="js-vertical-composition-item">全').to('話</span>').iterate(); parseData['general_all_no'] = parseData['general_all_no'][0]; //小説の更新日時が変更されている場合 if( !novelUpdate || novelUpdate < parseData['novelUpdate'] ){ resultVal[i][2] = parseData['novelUpdate']; } //全掲載部分数が変更されている場合 if( !cnt || cnt < parseData['general_all_no'] ){ resultVal[i][1] = parseData['general_all_no']; notifyFlg = true; } //チェック日時 const now = new Date(); const date = Utilities.formatDate(now, 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss'); resultVal[i][3] = date; //全掲載部分数が変更されている場合 if( notifyFlg ){ returnMessage += "カクヨム更新通知\nhttps://kakuyomu.jp/works/" + ncode + "\n\n"; } } //シートにまとめて書き込み kakuyomuSheet.getRange(1, 1, kakuyomuSheetVal.length,kakuyomuSheetVal[0].length).setValues(resultVal); return returnMessage; }
//カクヨム
function getKakuyomu(){

	//スプレッドシートの読み込み
	const sheet = SpreadsheetApp.getActiveSpreadsheet();

	//シートを指定
	const kakuyomuSheet = sheet.getSheetByName('kakuyomu');

	//シートのデータ取得
	const kakuyomuSheetVal = kakuyomuSheet.getDataRange().getValues();

	//結果用配列
	let resultVal = kakuyomuSheetVal;

	//戻り値用変数
	let returnMessage = '';

	//ループ処理
	for( let i = 1; i < kakuyomuSheetVal.length; i++ ){

		//パース用オブジェクト
		const parseData = new Object();

		//通知用フラグ
		let notifyFlg = false;

		//行からデータ取得
		const row = kakuyomuSheetVal[i];
		const ncode = row[0];
		const cnt = row[1];
		const novelUpdate = row[2];
		const sheetUpdate = row[3];

		//URL指定
		const novelUrl = 'https://kakuyomu.jp/works/' + ncode;

		//HTMLデータ取得する
		const html = UrlFetchApp.fetch(novelUrl).getContentText('UTF-8');

		//小説の更新日時
		parseData['novelUpdate'] = Parser.data(html).from('<p class="widget-toc-date"><time datetime="').to('Z"><span>').iterate();
		parseData['novelUpdate'] = parseData['novelUpdate'][0].replace('T', ' ');

		//全掲載部分数
		parseData['general_all_no'] = Parser.data(html).from('<span class="js-vertical-composition-item">全').to('話</span>').iterate();
		parseData['general_all_no'] = parseData['general_all_no'][0];

		//小説の更新日時が変更されている場合
		if( !novelUpdate || novelUpdate < parseData['novelUpdate'] ){
			resultVal[i][2] = parseData['novelUpdate'];
		}

		//全掲載部分数が変更されている場合
		if( !cnt || cnt < parseData['general_all_no'] ){
			resultVal[i][1] = parseData['general_all_no'];
			notifyFlg = true;
		}

		//チェック日時
		const now = new Date();
		const date = Utilities.formatDate(now, 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss');
		resultVal[i][3] = date;

		//全掲載部分数が変更されている場合
		if( notifyFlg ){
			returnMessage += "カクヨム更新通知\nhttps://kakuyomu.jp/works/" + ncode + "\n\n";
		}

	}

	//シートにまとめて書き込み
	kakuyomuSheet.getRange(1, 1, kakuyomuSheetVal.length,kakuyomuSheetVal[0].length).setValues(resultVal);

	return returnMessage;
}

 

参考サイト

https://auto-worker.com/blog/?p=2460

 - Google Apps Script Google

  関連記事

GASで祝日一覧(年月日と祝日名)データをJSON出力するAPIを作成

PHPのシステム案件で祝日を取得し、処理を行う箇所があった。Googleカレンダ ...

GASとLINEを連携させて通知メッセージを送る方法のメモ

Google Apps ScriptとLINEを連携させ、LINEに何らかの通知 ...

GASを使ってみて感じたメリットとデメリット

Google Apps Scriptを色々勉強した中で感じたメリットとデメリット ...

GASを使って任天堂ホームページ更新情報のRSSを取得する方法

GASを使ってRSSを取得してみたい。今回はニンテンドーホームページ更新情報とい ...

GASを利用してGmailに届いたメール内容をGoogleスプレッドシートに記入する方法

WordPressのContact Form7から送信した内容をGmailで受け ...

S