将表单回复导出为csv Google Apps脚本

时间:2017-04-26 17:52:43

标签: google-apps-script google-apps google-form

是否有一种快速方法可以通过编程方式将所有回复从Google表单导出到csv?通过脚本调用类似“导出对csv的响应”。

现在我正在用摇滚艺术的方式做这件事:

  • 迭代我要导出的表单(~75)
    • 打开每个表单var form = FormApp.openById(formId);
    • 获取回复:var formReponses = form.getResponses();(每个表单0到700个回复)
    • 迭代回复并获得商品回复:var preguntes = formReponses[r].getItemResponses();
      • 对于每个itemResponse,将其转换为csv / json
    • 将响应导出到驱动器文件

极其缓慢,此外反复挂起,因此我必须以50个响应的块的形式导出响应,并将它们保存在Drive分隔文件中。在下次执行时(让服务器冷却一段时间后),我再次执行脚本,跳过在块文件上找到的响应数。

此外,我不确定Google在执行form.getResponses();时是否保留了回复顺序(实际上我发现如果表单已被修改,则顺序不一样)

有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

在@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());