”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 通过 gcloud CLI 身份验证从本地脚本写入 Google 表格

通过 gcloud CLI 身份验证从本地脚本写入 Google 表格

发布于2024-11-03
浏览:466

Write to Google Sheets from a local script via gcloud CLI authentication

最近,我需要从 GitHub API 提取数据并发布到 Google Sheet,以便我可以分享一些有关代码审查工作量的图表。这篇文章是关于我如何进行身份验证的。

我编写了一个 Node.js 脚本,因为我的用例对于 BASH 来说太复杂,而对于 Go 来说似乎太临时了。最初,该脚本生成了临时 CSV 数据,我可以使用“粘贴为 CSV”功能将其手动复制到 Google 表格中。经过几轮手动复制后,我想明智地利用我的时间:我估计我可以在几个小时内完成工作表集成,如果是的话,那就
可能会在几个月内得到回报。

旁白: 表格不是我的数据库。这是我的数据报告用户界面。 不要使用表格作为数据库。

我花了将近 4 个小时才完成这项工作,因为身份验证很困难。这篇文章展示了更直接的可行解决方案。

创建 oAuth 应用程序的复杂性很容易让人分心,虽然我特别喜欢使用云服务中的服务帐户,但这就是
本地运行时不太方便。

我学到的技巧是,gcloud CLI 的应用程序默认凭据设置可以作为 Google Workspace 代码的一种 OAuth 代理运行,方法是扩展它向 Google 验证帐户的方式以包含更多权限(OAuth 范围)。

?使用 gcloud CLI 进行本地身份验证

要向 Google Sheets 发出 API 请求,请在您的云项目中启用 Sheets API:

$> gcloud services enable sheets.googleapis.com

Operation "operations/acat.p2-480745230567-02564c8d-c6ba-4f60-90bd-13f33e41f0fe" finished successfully.

设置您的应用程序默认凭据,还声明一些非默认 OAuth 范围,以便凭据可以与工作表一起使用:

$> gcloud auth application-default login --scopes \
   'https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/spreadsheets'

这将触发 OAuth 流程,涉及访问浏览器中的网页。根据终端配置,这可能会显示 URL 甚至打开页面。

当 gcloud 被授予此范围时,可以访问您的本地凭据的代码将对您的所有 Google 表格数据具有读/写访问权限。您可以在没有自定义范围的情况下重新运行此命令,以根据需要打开和关闭该访问。

?️ 为 Google Sheets 初始化 Node 客户端

import {google} from 'googleapis';

function sheetsClient() {
    const authConfig = new google.auth.GoogleAuth({
        scopes: [
            // Only 'spreadsheets' scope is needed in the code.
            // gcloud CLI also needs 'cloud-platform' and 'drive'.
            'https://www.googleapis.com/auth/spreadsheets'
        ],
    });
    const auth = await authConfig.getClient();
    return google.sheets({version: 'v4', auth});
}

?将数据附加到工作表

文档中有关如何将数据附加到工作表的示例
(单击 Node.js 选项卡)效果很好。但是,我无法理解如何从那里进行身份验证。一旦我理解了上面的技巧,将缺少的 OAuth 范围添加到我的开发环境凭据中,该示例就可以工作。

我做了一些更改,以便更轻松地重用客户端,以不同的方式参数化请求,并强调我希望表格处理数据的方式。

我的代码将数据附加到工作表,利用上面的客户端初始化代码:

let client;

async function appendDataToSheet(spreadsheetId, tab, values) {
    if (!client) {
        client = sheetsClient();
    }

    try {
        const result = await client.spreadsheets.values.append({
            spreadsheetId,
            range: `${tab}!A2:AG`,
            // Use my data as provided.
            valueInputOption: 'RAW',
            // Inserts rows as part of appending to reduce overwrites.
            insertDataOption: 'INSERT_ROWS',
            requestBody: { values },
        });
        console.log(`${result.data.updates.updatedCells} cells appended.`);
    } catch(e) {
        // Show the error, do not stop. Cross-reference the error with terminal output
        // and decide case-by-case to re-run the script or manually copy data.
        console.error(e);
    }
}

我使用“append”是因为我的脚本收集每月指标,并且append允许我添加新行而无需删除较早的行。

以下是如何调用appendDataToSheet()函数的示例:

const values = [
  // Each nested array is a spreadsheet row.
  [1, 2, 3, 4, 'luggage'],
  [4, 5, 6, 'N/A', 'sticks'],
];
appendDataToSheet(
  'HPDkfqdu6rfIq5-4uTGDqz2tvmPxDZMul27JFexample',
  'Exported Data Tab',
  values
);

文档中提供了一些有关使用 Sheets API 的好提示,例如建议每张工作表每秒不要发送多个 API 请求。我找到了困难的方法:用第二个请求的数据覆盖第一个请求的数据。

?发货吧!

如果我继续将其生产化,我可能会改用
Cloud Scheduler 和 Cloud Run 作业。如果您想阅读相关内容,请告诉我。

封面照片由 Glib Albovsky 在 Unsplash 上拍摄

版本声明 本文转载于:https://dev.to/googlecloud/write-to-google-sheets-from-a-local-script-via-gcloud-cli-authentication-3p1f?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 为什么我在Silverlight Linq查询中获得“无法找到查询模式的实现”错误?
    为什么我在Silverlight Linq查询中获得“无法找到查询模式的实现”错误?
    查询模式实现缺失:解决“无法找到”错误在Silverlight应用程序中,尝试使用LINQ建立LINQ连接以错误而实现的数据库”,无法找到查询模式的实现。”当省略LINQ名称空间或查询类型缺少IEnumerable 实现时,通常会发生此错误。 解决问题来验证该类型的质量是至关重要的。在此特定实例中...
    编程 发布于2025-05-10
  • 如何在鼠标单击时编程选择DIV中的所有文本?
    如何在鼠标单击时编程选择DIV中的所有文本?
    在鼠标上选择div文本单击带有文本内容,用户如何使用单个鼠标单击单击div中的整个文本?这允许用户轻松拖放所选的文本或直接复制它。 在单个鼠标上单击的div元素中选择文本,您可以使用以下Javascript函数: function selecttext(canduterid){ if(do...
    编程 发布于2025-05-10
  • 如何处理PHP文件系统功能中的UTF-8文件名?
    如何处理PHP文件系统功能中的UTF-8文件名?
    在PHP的Filesystem functions中处理UTF-8 FileNames 在使用PHP的MKDIR函数中含有UTF-8字符的文件很多flusf-8字符时,您可能会在Windows Explorer中遇到comploreer grounder grounder grounder gro...
    编程 发布于2025-05-10
  • 在Pandas中如何将年份和季度列合并为一个周期列?
    在Pandas中如何将年份和季度列合并为一个周期列?
    pandas data frame thing commans date lay neal and pree pree'和pree pree pree”,季度 2000 q2 这个目标是通过组合“年度”和“季度”列来创建一个新列,以获取以下结果: [python中的concate...
    编程 发布于2025-05-10
  • \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    答案: 在大多数现代编译器中,while(1)和(1)和(;;)之间没有性能差异。编译器: perl: 1 输入 - > 2 2 NextState(Main 2 -E:1)V-> 3 9 Leaveloop VK/2-> A 3 toterloop(next-> 8 last-> 9 ...
    编程 发布于2025-05-10
  • Python元类工作原理及类创建与定制
    Python元类工作原理及类创建与定制
    python中的metaclasses是什么? Metaclasses负责在Python中创建类对象。就像类创建实例一样,元类也创建类。他们提供了对类创建过程的控制层,允许自定义类行为和属性。在Python中理解类作为对象的概念,类是描述用于创建新实例或对象的蓝图的对象。这意味着类本身是使用类关...
    编程 发布于2025-05-10
  • 在Java中使用for-to-loop和迭代器进行收集遍历之间是否存在性能差异?
    在Java中使用for-to-loop和迭代器进行收集遍历之间是否存在性能差异?
    For Each Loop vs. Iterator: Efficiency in Collection TraversalIntroductionWhen traversing a collection in Java, the choice arises between using a for-...
    编程 发布于2025-05-10
  • 如何在无序集合中为元组实现通用哈希功能?
    如何在无序集合中为元组实现通用哈希功能?
    在未订购的集合中的元素要纠正此问题,一种方法是手动为特定元组类型定义哈希函数,例如: template template template 。 struct std :: hash { size_t operator()(std :: tuple const&tuple)const {...
    编程 发布于2025-05-10
  • 反射动态实现Go接口用于RPC方法探索
    反射动态实现Go接口用于RPC方法探索
    在GO 使用反射来实现定义RPC式方法的界面。例如,考虑一个接口,例如:键入myService接口{ 登录(用户名,密码字符串)(sessionId int,错误错误) helloworld(sessionid int)(hi String,错误错误) } 替代方案而不是依靠反射...
    编程 发布于2025-05-10
  • 如何有效地选择熊猫数据框中的列?
    如何有效地选择熊猫数据框中的列?
    在处理数据操作任务时,在Pandas DataFrames 中选择列时,选择特定列的必要条件是必要的。在Pandas中,选择列的各种选项。选项1:使用列名 如果已知列索引,请使用ILOC函数选择它们。请注意,python索引基于零。 df1 = df.iloc [:,0:2]#使用索引0和1 c...
    编程 发布于2025-05-10
  • Java的Map.Entry和SimpleEntry如何简化键值对管理?
    Java的Map.Entry和SimpleEntry如何简化键值对管理?
    A Comprehensive Collection for Value Pairs: Introducing Java's Map.Entry and SimpleEntryIn Java, when defining a collection where each element com...
    编程 发布于2025-05-10
  • Python高效去除文本中HTML标签方法
    Python高效去除文本中HTML标签方法
    在Python中剥离HTML标签,以获取原始的文本表示Achieving Text-Only Extraction with Python's MLStripperTo streamline the stripping process, the Python standard librar...
    编程 发布于2025-05-10
  • 在程序退出之前,我需要在C ++中明确删除堆的堆分配吗?
    在程序退出之前,我需要在C ++中明确删除堆的堆分配吗?
    在C中的显式删除 在C中的动态内存分配时,开发人员通常会想知道是否有必要在heap-procal extrable exit exit上进行手动调用“ delete”操作员,但开发人员通常会想知道是否需要手动调用“ delete”操作员。本文深入研究了这个主题。 在C主函数中,使用了动态分配变量(H...
    编程 发布于2025-05-10
  • Java数组中元素位置查找技巧
    Java数组中元素位置查找技巧
    在Java数组中检索元素的位置 利用Java的反射API将数组转换为列表中,允许您使用indexof方法。 (primitives)(链接到Mishax的解决方案) 用于排序阵列的数组此方法此方法返回元素的索引,如果发现了元素的索引,或一个负值,指示应放置元素的插入点。
    编程 发布于2025-05-10
  • 如何在JavaScript对象中动态设置键?
    如何在JavaScript对象中动态设置键?
    在尝试为JavaScript对象创建动态键时,如何使用此Syntax jsObj['key' i] = 'example' 1;不工作。正确的方法采用方括号: jsobj ['key''i] ='example'1; 在JavaScript中,数组是一...
    编程 发布于2025-05-10

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3