Zendesk GuideでFAQページを作っているサービスはわりと多く見かけます。
サービスのリニューアル時などたくさんの画像を一気に変更しなければならないことがあると思うんですが、Guideの全ページを開いて確認するのは大変です。そこで、Zendesk Guide内で表示している画像を一覧で見れるようにしてみました。
Google Apps ScriptでクロールしてSpreadSheetに結果を記入するだけなのですが、もしかしたら未来の自分含めて他の誰かに役立つこともあるかもしれないので書いておきます。もし他にいいやり方があれば教えてもらえるとありがたいです。
どんなものか
SpreadSheetからGoogle Apps Scriptを実行するだけです。実行日時の名前のシートが新規作成され、全画像が一覧で表示されます。

解説
Google Apps Scriptで指定したZendesk Guideページをクロールして、 <img> タグの画像のURLを一覧にしているだけです。
一覧を取得するAPIがなさそうだったのでクロールでやっています。Zendesk Guideのカテゴリやセクションの設定、レイアウトによってクロールのやり方は変わるので、そのままでは使えないことも多いと思います。変更にも弱いです。あくまで参考程度にしてください。
ちなみにGoogle Apps Scriptで書いた理由は、SpreadSheetの IMAGE 関数使ってセル内に指定したURLの画像を表示できて便利だからです。ページ内の任意の要素を取り出すのに愚直に正規表現を書いてつらかったのと、実行速度めちゃくちゃ遅いので改善の余地は多々あります。
function onOpen() {
var entries = [
{
name : "Zendesk Guide画像一覧作成",
functionName : "searchArticleImages"
}
];
// 上部にスクリプト実行メニューを作成して、下位項目のメニューを設定
SpreadsheetApp.getActiveSpreadsheet().addMenu("スクリプト実行", entries);
};
function searchArticleImages() {
const baseUrl = 'Zendesk GuideのページTOPのURL';
array = [];
// トップページのコンテンツを取得
var topContents = UrlFetchApp.fetch(baseUrl + '/hc/ja').getContentText('UTF-8');
while ((t = /<a href='\S*' class="blocks-item-link">\s*<h4 class="blocks-item-title">\S*<\/h4>/gm.exec(topContents)) !== null) {
categorylink = baseUrl + t[0].replace("<a href='", "").replace(/' class="blocks-item-link">\s*<h4 class="blocks-item-title">\S*<\/h4>/, "");
categoryTitle = t[0].replace(/<a href='\S*' class="blocks-item-link">\s*<h4 class="blocks-item-title">/, "").replace("</h4>", "");
// カテゴリのコンテンツを取得
var categoryContents = UrlFetchApp.fetch(categorylink).getContentText('UTF-8');
while ((c = /<h3 class="section-tree-title">\s*<a href="\S*">\S*<\/a>/gm.exec(categoryContents)) !== null) {
sectionLink = baseUrl + c[0].replace(/<h3 class="section-tree-title">\s*<a href="/, "").replace(/">\S*<\/a>/, "");
sectionTitle = c[0].replace(/<h3 class="section-tree-title">\s*<a href="\S*">/, "").replace(/<\/a>/, "");
// セクションのコンテンツを取得
var sectionContents = UrlFetchApp.fetch(sectionLink).getContentText('UTF-8');
while ((s = /<a href="\S*" class="article-list-link">\S*<\/a>/gm.exec(sectionContents)) !== null) {
articleLink = baseUrl + s[0].replace("<a href=\"", "").replace(/" class="article-list-link">\S*<\/a>/, "");
articleTitle = s[0].replace(/<a href="\S*" class="article-list-link">/, "").replace("<\/a>", "");
Logger.log(articleTitle);
// 記事のコンテンツを取得
var articleContents = UrlFetchApp.fetch(articleLink).getContentText('UTF-8');
while ((a = /<img src="\S*" alt="\S*"/gm.exec(articleContents)) !== null) {
imgUrl = baseUrl + a[0].replace("<img src=\"", "").replace(/" alt="\S*"/, "");
// ロゴ画像等は除く
if (imgUrl.match(/article_attachments/)) {
imgCellText = '=IMAGE("' + imgUrl + '",1)';
array.push([categoryTitle, sectionTitle, articleTitle, articleLink, imgUrl, imgCellText]);
Logger.log(imgUrl);
}
}
}
}
}
if (array.length > 0) {
array.unshift(['カテゴリタイトル', 'セクションタイトル', '記事タイトル', '記事URL', '画像URL', '画像'])
writeData(array);
} else {
Browser.msgBox(baseUrl + "のZendeskページ内に画像が1件も見つかりませんでした");
}
}
function writeData(data) {
// シート作成
var time = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss');
var newSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet(time);
var rows = data.length;
var cols = data[0].length;
// セルの縦横中央寄せ
newSheet.getRange(1, 1, rows, cols).setVerticalAlignment("middle");
newSheet.getRange(1, cols, rows, 1).setHorizontalAlignment("center");
// セルの折り返し
newSheet.getRange(1, 1, rows, 3).setWrap(true);
// データ追加
newSheet.insertRows(1, rows);
newSheet.getRange(1, 1, rows, cols).setValues(data);
// ヘッダの色付け
newSheet.getRange(1, 1, 1, cols).setBackground('#fff2cc');
// 画像セルの色付け
newSheet.getRange(2, cols, rows-1, 1).setBackground('#f3f3f3');
// Column/Row幅の設定
newSheet.setColumnWidth(1, 150);
newSheet.setColumnWidth(2, 150);
newSheet.setColumnWidth(3, 300);
newSheet.setColumnWidth(4, 100);
newSheet.setColumnWidth(5, 100);
newSheet.setColumnWidth(6, 300);
newSheet.setRowHeights(2, rows-1, 300);
// 1行目を固定
newSheet.setFrozenRows(1);
}
以上です。ヤッタネ!!