Separator

 

Обработка данных Wiki с помощью Google Docs таблиц

Гугл документы - инструмент очень мощный. В комплекте имеется интерфейс для написания своих скриптов, а эти скрипты позволяют как угодно эти документы менять и выполнять много смежный функций.
Давно хотел ознакомиться, и вот, недавно, выпал повод. Подробнее - под катом.


Есть такая интересная игра - Darkest Dungeon. Я в целом люблю играть очень размеренно, не просто сел, да прошёл, а ещё всякие Wiki проанализирую, как эффективнее провернуть дело.В данном случае, игра очень этому способствует, ибо ошибок не прощает. 

В связи с этим, важной задачкой становится подбор снаряжения. Снаряжения очень много, но внутриигровой интерфейс не позволяет как-то сортировать или фильтровать по параметрам. Что же делать?

Таблицы идеально подходят для такой цели, но заполнять вручную такую кучу инфы - жестоко. Кроме того, подобная информация, как правило уже заполнена на игровой Wiki. Так оно и оказалось.

Итак, задача поставлена - написать скрипт, который запросит данные с веб, заполнит таблицу в удобной форме.

Конечный скрипт будет приведён в конце. А сейчас, начнут по порядку, какие основные моменты пришлось изучить, чтобы решить задачу.

В меню таблицы выберем Инструменты - Редактор скриптов. Теперь надо писать код. Можно написать любую функцию и вызывать её вручную. Для разового импорта этого достаточно, но если в редакторе выбрать Правка - Триггеры текущего проекта. Там можно настроить выполнение функции на определённые события, а так же периодическое выполнение.

Приступим к коду. В первую очередь, я обеспокоился, сможет ли доступное API распарсить страницу. Ведь тот же jQuery, спокойно может создать виртуальный DOM из HTML и найти все что нужно. Ах да, можно ли вообще сделать http-запрос, чтобы получить нужные данные?

Да и да. Небольшое изучение мануалов привело к следующим выводам.

Получить html страницы весьма просто:
    var html = UrlFetchApp
     .fetch(url)
     .getContentText()

Теперь, нужно как-то добраться до данных. Ответ, казалось бы, находился на поверхности:
var html = XmlService.parse(html).getRootElement();

Но увы, полный HTML страницы выдавал ошибку: Error on line 67: The reference to entity "search" must end with the ';' delimiter. (строка 159, файл dd)

Парсеру не нравится script-теги, а возможно и другие тоже бы не понравилось. Пришёл к выводу, что проще всего будет изъять из исходного HTML только данные нужной таблицы, т.к. чистая таблица парсилась хорошо. Особо не мудрил:
    html = html
      .substr(html.indexOf(wrapper[0]));
    
    html = html.substr(0, html.indexOf(wrapper[1]) + wrapper[1].length);

Теперь, надо пройтись по внутренним данным и разобрать их. Привычных методов поиска DOM нет, но дочерние узлы получить можно, и на этом спасибо:

html.getChildren('tr').forEach(function(line) {
  // Пропуск заголовка
  var tds = line.getChildren('td');
  if ( ! tds.length ) {
    return; 
  }

  tds.forEach(function(col, colNum) {
      // Обработка колонок
  });
});

Этого вполне достаточно, чтобы получить со страницы все нужные данные, а там уже дело десятое как их обработать и преобразовать. На выходе получаем массив данных. Как добавить их в таблицу?

Для начала нужно получить лист, с которым будем работать. Я планировал, что будет несколько листов, с разными названиями, заполнить нам нужно определённый:
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();    
  var sheet = spreadsheet.getSheetByName("Trinkets");

Далее, все сводится к вызову пару методов из sheet, а именно:

  • getRange - позволяет "выделить" ячейку или ячейки
  • setValue(s) - позволяет установить значение или значения для выделенных ячеек
Пример, который запишет a, b, c, d в 2 колонки:
sheet.getRange(1, 1, 2, 2).setValues([['a', 'b'], ['c', 'd']);

Отмечу, что выделив диапазон, можно воспользоваться и setValue - тогда всем ячейкам будет применено одно и тоже значение. Это удобно для очистки больших диапазонов, для подготовки записи новых данных. Отмечу метод getDataRange - выделит весь лист (в пределах того, где есть хоть какие-либо данные.
Таким вот образом можно очистить лист: sheet.getDataRange().setValue("").setNote("");
setNote аналогична setValue (а так же имеет s-вариант), но устанавливает примечание для ячейки. В заголовок я выносил сокращения терминов, поэтому добавление примечания мне очень понадобилось - чтобы вывести расшифровку.

Вот и все. Напоследок, полный листинг:

Комментариев нет:

Отправить комментарий