使用 Python 和 Google 表格 API 仅获取 Google 电子表格的可见数据?

Fetching only the non-hidden, visible data of a Google spreadsheet using Python and Google Sheets API?

我正在使用 Google Sheets API 从在线电子表格中检索数据并将它们读入 pandas 数据框。我已成功设置脚本来获取数据,但此默认实现获取所有内容,甚至隐藏 rows/columns。电子表格中有许多行已被隐藏。我不想检索那些,因为一行的隐藏状态意味着它是无关紧要的。因此,我正在寻找一种无需手动隐藏 rows/columns 即可获取电子表格 的方法。或者,另一种方法是获取电子表格内容,然后 排除隐藏的单元格 。到目前为止,我还没有设法弄清楚 Google Sheet 中是否实现了这样的功能 API.

我目前的工作实施如下。这里的问题是,这甚至包括隐藏的 rows/columns:

def getSpreadsheetData(name, spreadsheet_id, sheet_id=None):

    global values_input, service
    creds = ServiceAccountCredentials.from_json_keyfile_name(creds_file_path, SCOPES)
    service = build('sheets', 'v4', credentials=creds)

    sheet = service.spreadsheets()
    data_table = sheet.values().get(spreadsheetId=spreadsheet_id,
                                      range=name).execute()
    data_values = data_table.get('values', [])

    if not data_values:
        print('No data found.')
        return -1

    else:
        df = pd.DataFrame(data_values)
        return df

编辑: 在我看来,这个问题不同于仅根据列值过滤电子表格,如 所述。我只想获取电子表格中未隐藏的那些行。获取电子表格内容的默认 API 调用(请参阅我上面的代码)会获取所有行,即使是那些手动隐藏的行,因此对于通过 link 打开电子表格的人来说是不可见的。

编辑 2: 我更新了 post 以更清楚地表明我当前的工作实现 return 是所有隐藏的单元格,而这正是我不想要的。我想要一种可以排除那些被用户手动隐藏的 rows/columns 的方法,因为隐藏的单元格不重要且无关紧要。因此,我的输出数据框中不需要它们。

编辑 3: 我整理了一个下面共享的小样本数据集。请将内容复制到GoogleSheet。有了这些数据,我发现解析器无法区分什么应该是 header 什么应该在第一行。请注意,示例数据集具有三个可见行和一个隐藏行。该函数需要 return pandas 数据框中的这三个可见行。相反,我只得到一个 header 和两行,其中 header 实际上是真实列名和第一行内容的组合。 数据集:

Lesson  Date/Time       German        English                   Completed
Hallo!  Oct 21st, 2021  nicht         not   
Hallo!  Oct 21st, 2021  nicht so gut  not so good               10/22
Hallo!  Oct 21st, 2021  oder          or    
Hallo!  Oct 21st, 2021  schön         nice; beautiful; pretty   10/22
    

注意:第 3 行(包含 'oder' 和 'or' 的行)已隐藏。

代码:

def getSpreadsheetData(spreadsheet_id, sheet_id=None):

    global values_input, service
    creds_file_path = ""        # add your service account path here 
    SCOPES = ['https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive']

    creds = ServiceAccountCredentials.from_json_keyfile_name(creds_file_path, SCOPES)
    service = build('sheets', 'v4', credentials=creds)
    access_token = creds.get_access_token().access_token

    url = 'https://docs.google.com/spreadsheets/d/' + spreadsheet_id + '/gviz/tq?tqx=out:csv&gid=' + sheet_id
    res = requests.get(url, headers={'Authorization': 'Bearer ' + access_token})
    df = pd.read_csv(io.StringIO(res.text), sep=',')
    return df

输出不正确:

  Lesson Hallo! Date/Time Oct 21st, 2021  German nicht              English not Completed   Unnamed: 5
0        Hallo!           Oct 21st, 2021  nicht so gut              not so good      10/22         NaN
1        Hallo!           Oct 21st, 2021         schön  nice; beautiful; pretty      10/22         NaN

可以看出,header和第一行合并了,这是不正确的。在 pd.read_csv() 中包含 header=0 参数也没有帮助,同样的错误输出是 returned.


关于您的以下目标,

This problem, in my opinion, is different from merely filtering the spreadsheet based on a column value, as described . I want to fetch only those rows of a spreadsheet that are not hidden. The default API call to fetch content of a spreadsheet (see my code above) fetches all the rows, even those that have manually been hidden and hence are not visible for people opening the spreadsheet via a link.

我的示例脚本使用查询语言从 sheet 检索显示行和隐藏行。所以,关于I want to fetch only those rows of a spreadsheet that are not hidden.,这可以通过示例脚本来实现。从 The default API call to fetch content of a spreadsheet (see my code above) fetches all the rows, even those that have manually been hidden and hence are not visible for people opening the spreadsheet via a link. 开始,我认为您尝试过使用表格 API。在这种情况下,即使存在隐藏的行,也会检索所有行。

并且从read them into a pandas dataframe.开始,我认为您的目标可以通过修改的示例脚本来实现。

所以,为了达到你的目的,示例脚本如下。

示例脚本:

示例脚本:

service = build('sheets', 'v4', credentials=creds) # This is from your script.

spreadsheet_id = "###" # Please set the Spreadsheet ID.
sheet_id = "###"  # Please set the sheet name.

# Removed ---> url = 'https://docs.google.com/spreadsheets/d/' + spreadsheet_id + '/gviz/tq?tqx=out:csv&gid=' + sheet_id
url = 'https://docs.google.com/spreadsheets/d/' + spreadsheet_id + '/pub?output=csv&gid=' + sheet_id
res = requests.get(url, headers={'Authorization': 'Bearer ' + creds.token})
df = pd.read_csv(io.StringIO(res.text), sep=',')
  • 在此示例中,还使用了 import csvimport ioimport requests。并且,访问令牌是从 service = build('sheets', 'v4', credentials=creds)creds 中检索到的。

  • 当此脚本为 运行 时,显示的行是从 sheet 和隐藏行中检索的,检索到的值将放入数据框中。

    • 在此示例脚本中,用于将检索到的值放入数据框的脚本被添加到
  • 在这种方法中,显示的行不仅可以从手动隐藏行的sheet中检索到,还可以从基本过滤器过滤后的行中的sheet中检索到.

参考:

已添加 1 个:

当上述脚本无法解决您的问题时,请测试以下脚本。在此脚本中,使用 Sheets API 检索值。此时,首先检索基本过滤器过滤后的行号。并且,使用行号检索显示的行。

示例脚本:

service = build('sheets', 'v4', credentials=creds) # This is from your script.

spreadsheet_id = "###" # Please set the Spreadsheet ID.
sheet_name = "Sheet1"  # Please set the sheet name.

fields = 'sheets(data(rowMetadata(hiddenByFilter)))'
res = service.spreadsheets().get(spreadsheetId=spreadsheet_id, ranges=sheet_name, fields=fields).execute()
rowMetadata = res["sheets"][0]["data"][0]["rowMetadata"]
filteredRows = {"shownRows": [], "hiddenRows": []}
for i, r in enumerate(rowMetadata):
    filteredRows["hiddenRows" if "hiddenByFilter" in r and r["hiddenByFilter"] else "shownRows"].append(i + 1)

result = service.spreadsheets().values().get(spreadsheetId=spreadsheet_id, range=sheet_name).execute()
values = result.get("values", [])
v = []
for e in filteredRows["shownRows"]:
    if e - 1 < len(values):
        v.append(values[e - 1])
    else:
        break
df = pd.DataFrame(v[1:], columns=v[0])
print(df)

添加了 2 个:

当行被基本过滤器和手动操作隐藏时,您可以使用以下脚本检索显示的行。

示例脚本:

service = build('sheets', 'v4', credentials=creds) # This is from your script.

spreadsheet_id = "###" # Please set the Spreadsheet ID.
sheet_name = "Sheet1"  # Please set the sheet name.

fields = 'sheets(data(rowMetadata(hiddenByFilter,hiddenByUser)))'
res = service.spreadsheets().get(spreadsheetId=spreadsheet_id, ranges=sheet_name, fields=fields).execute()
rowMetadata = res["sheets"][0]["data"][0]["rowMetadata"]
filteredRows = {"shownRows": [], "hiddenRows": []}
for i, r in enumerate(rowMetadata):
    filteredRows["hiddenRows" if ("hiddenByFilter" in r and r["hiddenByFilter"]) or ("hiddenByUser" in r and r["hiddenByUser"]) else "shownRows"].append(i + 1)

result = service.spreadsheets().values().get(spreadsheetId=spreadsheet_id, range=sheet_name).execute()
values = result.get("values", [])
v = []
for e in filteredRows["shownRows"]:
    if e - 1 < len(values):
        v.append(values[e - 1])
    else:
        break
df = pd.DataFrame(v[1:], columns=v[0])
print(df)