You need to enable JavaScript to run this app. 如何在Google Scripts中处理动态表单URL实现高尔夫预订自动提交
优惠活动
大模型
产品
解决方案
定价
更多

如何在Google Scripts中处理动态表单URL实现高尔夫预订自动提交

可落地的自动化实现方案

核心逻辑:每日变动的Google表单本质上只是随机替换了表单ID、题目对应的entry数字ID,只要题目的文本、顺序完全不变,就可以通过解析公开表单页面的源码自动匹配提交地址和字段映射,不需要手动硬编码修改。

方案1:自动匹配新表单地址与对应entry字段(对应需求1)

原来需要手动修改的2部分内容(硬编码的form_url、13个entry ID映射)全部通过脚本自动解析,日常仅需把每日新表单的公开访问链接粘贴到表格固定单元格即可,不需要改代码。

  • 实现逻辑:
    • 拉取表单公开页面的源码,自动提取真实提交用的formResponse地址
    • 匹配每个题目的纯文本标题和对应的entry ID建立映射表
    • 按照表格中存储的预订信息,自动绑定对应字段值,拼接提交的payload
  • 完整可运行代码:
// 辅助函数:输入表单公开访问链接,自动返回提交地址和题目标题-entry ID的映射
function parseGolfForm(formPublicUrl) {
  const formHtml = UrlFetchApp.fetch(formPublicUrl, {muteHttpExceptions: true}).getContentText();
  
  // 自动提取真实提交用的formResponse地址
  const formSubmitMatch = formHtml.match(/action="(https:\/\/docs\.google\.com\/forms\/d\/e\/[^/]+\/formResponse)"/);
  if (!formSubmitMatch) throw new Error("无法解析表单提交地址,请检查公开链接是否正确");
  const submitUrl = formSubmitMatch[1];

  // 自动匹配题目标题和对应的entry ID
  const questionMap = {};
  const questionRegex = /<div class="M2f2gb"[^>]*>(.*?)<\/div>.*?name="entry\.(\d+)"/gs;
  let match;
  while ((match = questionRegex.exec(formHtml)) !== null) {
    const rawTitle = match[1].replace(/<[^>]+>/g, '').trim(); // 去掉HTML标签获取纯题目文本
    const entryId = `entry.${match[2]}`;
    questionMap[rawTitle] = entryId;
  }
  // 单独识别表单内置的邮箱字段
  const hasEmailField = formHtml.includes('name="emailAddress"');
  return {submitUrl, questionMap, hasEmailField};
}

function golf_booking() {
  const workbook = SpreadsheetApp.getActiveSpreadsheet();
  const worksheet = workbook.getSheetByName("Details");
  
  // 每日仅需在这里粘贴新表单的公开访问链接(存在B15单元格),无需修改代码
  const formPublicUrl = worksheet.getRange("B15").getDisplayValue();
  const formInfo = parseGolfForm(formPublicUrl);

  // 把key替换成你表单上完全一模一样的题目文字,和表格读取的值做绑定
  const titleValueMap = {
    "联系邮箱": worksheet.getRange("B1").getDisplayValue(),
    "1号选手姓名": worksheet.getRange("B2").getDisplayValue(),
    "1号选手会员号": worksheet.getRange("B3").getDisplayValue(),
    "联系手机号": worksheet.getRange("B4").getDisplayValue(),
    "预订日期": worksheet.getRange("B5").getDisplayValue(),
    "预订类型": worksheet.getRange("B6").getDisplayValue(),
    "偏好开球时间": worksheet.getRange("B7").getDisplayValue(),
    "2号选手姓名": worksheet.getRange("B8").getDisplayValue(),
    "2号选手会员号": worksheet.getRange("B9").getDisplayValue(),
    "3号选手姓名": worksheet.getRange("B10").getDisplayValue(),
    "3号选手会员号": worksheet.getRange("B11").getDisplayValue(),
    "4号选手姓名": worksheet.getRange("B12").getDisplayValue(),
    "4号选手会员号": worksheet.getRange("B13").getDisplayValue()
  };

  // 自动拼接提交用的datamap,不需要手写entry ID
  const datamap = {};
  if (formInfo.hasEmailField) datamap.emailAddress = titleValueMap["联系邮箱"];
  Object.entries(titleValueMap).forEach(([title, value]) => {
    if (title === "联系邮箱") return;
    const matchedEntry = formInfo.questionMap[title];
    if (!matchedEntry) throw new Error(`表单中找不到题目:${title},请检查题目文本是否完全匹配`);
    datamap[matchedEntry] = value;
  });

  // 提交逻辑和原脚本完全一致
  const options = {method: "post", payload: datamap};
  UrlFetchApp.fetch(formInfo.submitUrl, options);
}
  • 使用说明:
    • 在Details工作表新增B15单元格,用来存放每日的新表单公开打开链接
    • 代码中titleValueMap的key值必须和表单题目文字完全一致,不能有多余空格、标点差异,否则会匹配失败

方案2:按题目顺序循环提交(对应需求2)

如果表单的题目顺序长期固定,不需要逐字匹配题目文本,直接按题目出现的顺序循环匹配entry ID即可,代码逻辑更轻量。

  • 实现逻辑:
    • 解析页面时按顺序提取所有entry ID存入数组
    • 把需要提交的预订值按照和表单题目一致的顺序排成数组
    • 循环遍历数组,自动拼接提交payload,不需要手写entry映射
  • 完整可运行代码:
// 按页面出现顺序提取所有entry ID
function parseFormByOrder(formPublicUrl) {
  const formHtml = UrlFetchApp.fetch(formPublicUrl, {muteHttpExceptions: true}).getContentText();
  const submitUrl = formHtml.match(/action="(https:\/\/docs\.google\.com\/forms\/d\/e\/[^/]+\/formResponse)"/)[1];
  
  // 按出现顺序抓所有entry ID,自动去重
  const entryList = [];
  const entryRegex = /name="entry\.(\d+)"/g;
  let match;
  while ((match = entryRegex.exec(formHtml)) !== null) {
    const entryId = `entry.${match[2]}`;
    if (!entryList.includes(entryId)) entryList.push(entryId);
  }
  return {submitUrl, entryList, hasEmail: formHtml.includes('name="emailAddress"')};
}

function golf_booking() {
  const workbook = SpreadsheetApp.getActiveSpreadsheet();
  const worksheet = workbook.getSheetByName("Details");
  const formPublicUrl = worksheet.getRange("B15").getDisplayValue();
  const formInfo = parseFormByOrder(formPublicUrl);

  // 按照表单题目顺序,把要提交的值排成一致的数组
  const valueOrderList = [
    worksheet.getRange("B2").getDisplayValue(), // 第1题:1号选手姓名
    worksheet.getRange("B3").getDisplayValue(), // 第2题:1号选手会员号
    worksheet.getRange("B4").getDisplayValue(), // 第3题:联系手机号
    worksheet.getRange("B7").getDisplayValue(), // 第4题:偏好开球时间
    worksheet.getRange("B8").getDisplayValue(), // 第5题:2号选手姓名
    worksheet.getRange("B9").getDisplayValue(), // 第6题:2号选手会员号
    worksheet.getRange("B10").getDisplayValue(), // 第7题:3号选手姓名
    worksheet.getRange("B11").getDisplayValue(), // 第8题:3号选手会员号
    worksheet.getRange("B12").getDisplayValue(), // 第9题:4号选手姓名
    worksheet.getRange("B13").getDisplayValue(), // 第10题:4号选手会员号
    worksheet.getRange("B5").getDisplayValue(), // 第11题:预订日期
    worksheet.getRange("B6").getDisplayValue() // 第12题:预订类型
  ];

  // 循环自动拼接待提交的datamap
  const datamap = {};
  if (formInfo.hasEmail) datamap.emailAddress = worksheet.getRange("B1").getDisplayValue();
  for (let i = 0; i < formInfo.entryList.length; i++) {
    datamap[formInfo.entryList[i]] = valueOrderList[i];
  }

  UrlFetchApp.fetch(formInfo.submitUrl, {method: "post", payload: datamap});
}

注意事项

  • 解析用的正则如果遇到Google前端结构调整,仅需微调匹配规则,核心逻辑(提取提交地址、匹配input字段名)不会变化
  • 表单的题目文本、顺序如果发生变动,需要同步调整脚本内的映射关系或值的排列顺序
  • 脚本仅拉取公开表单页面的源码,不需要额外的Google账号授权,只要表单可公开填写即可正常运行

内容的提问来源于stack exchange,提问作者miwotsukushi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.10 04:15:07