将表单回复导出为 csv Google Apps 脚本
Export Form responses as csv Google Apps Scripts
有没有一种快速的方法可以以编程方式将 Google 表单中的所有响应导出到 csv?通过脚本调用 "Export responses to csv" 之类的东西。
现在我正在以摇滚艺术的方式来做:
- 遍历我要导出的表单 (~75)
- 打开每张表格
var form = FormApp.openById(formId);
- 获得回复:
var formReponses = form.getResponses();
(每个表单有 0 到 700 个回复)
- 迭代响应并获取项目响应:
var preguntes = formReponses[r].getItemResponses();
- 对于每个项目响应,将其转换为 csv/json
- 将响应导出到驱动器文件
这 非常慢 而且它 一遍又一遍地挂起 ,所以我不得不以 50 个响应为一组导出响应并保存它们在驱动器分隔文件中。在下次执行时(让服务器冷却一段时间后),我再次执行脚本,跳过在块文件中找到的响应数。
此外,我不确定 Google 在执行 form.getResponses();
时是否保持响应顺序(实际上我发现如果表格已被修改,顺序就不一样了)
有更好的方法吗?
在@JackBrown 的帮助下,我设法编写了一个 Chrome 扩展来下载回复(可能很快会在 github 中)。这将等待 formIds
对象中的每个下载完成,然后提示下一个:
'use strict';
function startDownload() {
const formIds = {
'Downloads-subfolder-here': {
'Download-filename-here': '1-cx-aSAMrTK0IHsQkE... {form-id here}',
'Another-filename-here': '...-dnqdpnEso {form-id here}',
// ...
},
'Another-subfolder-here': {
'Download-filename-here': '1-cx-aSAMrTK0IHsQkE... {form-id here}',
'Another-filename-here': '...-dnqdpnEso {form-id here}',
// ...
},
};
const destFolders = Object.keys(formIds);
const downloads = [];
for (let t = 0, tl = destFolders.length; t < tl; t += 1) {
const destFolder = destFolders[t];
const forms = Object.keys(formIds[destFolder]);
for (let f = 0, fl = forms.length; f < fl; f += 1) {
const formName = forms[f];
downloads.push({
destFolder,
formName,
url: `https://docs.google.com/forms/d/${formIds[destFolder][formName]}/downloadresponses?tz_offset=-18000000`,
filename: `myfolder/${destFolder}/${formName.replace(/\//g, '_')}.csv`,
});
}
}
const event = new Event('finishedDownload');
const eventInterrupt = new Event('interruptedDownload');
let currId;
chrome.downloads.onChanged.addListener((downloadDelta) => {
if (downloadDelta.id === currId) {
if (downloadDelta.state && downloadDelta.state.current === 'complete') {
document.dispatchEvent(event);
} else if (downloadDelta.state && downloadDelta.state.current === 'interrupted') {
console.log(downloadDelta);
document.dispatchEvent(eventInterrupt);
}
}
});
downloads.reduce((promise, actual) => {
return promise.then((last) => (last ? new Promise((resolve) => {
const { url, filename, destFolder, formName } = actual;
function listener() {
document.removeEventListener('finishedDownload', listener);
document.removeEventListener('interruptedDownload', listener);
resolve(true);
};
function interrupt() {
document.removeEventListener('finishedDownload', listener);
document.removeEventListener('interruptedDownload', listener);
resolve(false);
}
console.log(`Processant ${destFolder}, ${formName}: ${url}`);
document.addEventListener('finishedDownload', listener);
document.addEventListener('interruptedDownload', interrupt);
chrome.downloads.download({ url, filename }, (downloadId) => {
currId = downloadId;
if (!downloadId) {
console.log();
console.log('Error downloading...');
console.log(runtime.lastError);
resolve();
}
});
}) : Promise.resolve(false)));
}, Promise.resolve(true));
}
chrome.browserAction.onClicked.addListener((/*tab*/) => startDownload());
有没有一种快速的方法可以以编程方式将 Google 表单中的所有响应导出到 csv?通过脚本调用 "Export responses to csv" 之类的东西。
现在我正在以摇滚艺术的方式来做:
- 遍历我要导出的表单 (~75)
- 打开每张表格
var form = FormApp.openById(formId);
- 获得回复:
var formReponses = form.getResponses();
(每个表单有 0 到 700 个回复) - 迭代响应并获取项目响应:
var preguntes = formReponses[r].getItemResponses();
- 对于每个项目响应,将其转换为 csv/json
- 将响应导出到驱动器文件
- 打开每张表格
这 非常慢 而且它 一遍又一遍地挂起 ,所以我不得不以 50 个响应为一组导出响应并保存它们在驱动器分隔文件中。在下次执行时(让服务器冷却一段时间后),我再次执行脚本,跳过在块文件中找到的响应数。
此外,我不确定 Google 在执行 form.getResponses();
时是否保持响应顺序(实际上我发现如果表格已被修改,顺序就不一样了)
有更好的方法吗?
在@JackBrown 的帮助下,我设法编写了一个 Chrome 扩展来下载回复(可能很快会在 github 中)。这将等待 formIds
对象中的每个下载完成,然后提示下一个:
'use strict';
function startDownload() {
const formIds = {
'Downloads-subfolder-here': {
'Download-filename-here': '1-cx-aSAMrTK0IHsQkE... {form-id here}',
'Another-filename-here': '...-dnqdpnEso {form-id here}',
// ...
},
'Another-subfolder-here': {
'Download-filename-here': '1-cx-aSAMrTK0IHsQkE... {form-id here}',
'Another-filename-here': '...-dnqdpnEso {form-id here}',
// ...
},
};
const destFolders = Object.keys(formIds);
const downloads = [];
for (let t = 0, tl = destFolders.length; t < tl; t += 1) {
const destFolder = destFolders[t];
const forms = Object.keys(formIds[destFolder]);
for (let f = 0, fl = forms.length; f < fl; f += 1) {
const formName = forms[f];
downloads.push({
destFolder,
formName,
url: `https://docs.google.com/forms/d/${formIds[destFolder][formName]}/downloadresponses?tz_offset=-18000000`,
filename: `myfolder/${destFolder}/${formName.replace(/\//g, '_')}.csv`,
});
}
}
const event = new Event('finishedDownload');
const eventInterrupt = new Event('interruptedDownload');
let currId;
chrome.downloads.onChanged.addListener((downloadDelta) => {
if (downloadDelta.id === currId) {
if (downloadDelta.state && downloadDelta.state.current === 'complete') {
document.dispatchEvent(event);
} else if (downloadDelta.state && downloadDelta.state.current === 'interrupted') {
console.log(downloadDelta);
document.dispatchEvent(eventInterrupt);
}
}
});
downloads.reduce((promise, actual) => {
return promise.then((last) => (last ? new Promise((resolve) => {
const { url, filename, destFolder, formName } = actual;
function listener() {
document.removeEventListener('finishedDownload', listener);
document.removeEventListener('interruptedDownload', listener);
resolve(true);
};
function interrupt() {
document.removeEventListener('finishedDownload', listener);
document.removeEventListener('interruptedDownload', listener);
resolve(false);
}
console.log(`Processant ${destFolder}, ${formName}: ${url}`);
document.addEventListener('finishedDownload', listener);
document.addEventListener('interruptedDownload', interrupt);
chrome.downloads.download({ url, filename }, (downloadId) => {
currId = downloadId;
if (!downloadId) {
console.log();
console.log('Error downloading...');
console.log(runtime.lastError);
resolve();
}
});
}) : Promise.resolve(false)));
}, Promise.resolve(true));
}
chrome.browserAction.onClicked.addListener((/*tab*/) => startDownload());