【问题标题】:Read cell format from Google sheet using Python (API v4)使用 Python (API v4) 从 Google 表格中读取单元格格式
【发布时间】:2018-07-12 09:52:57
【问题描述】:

我正在寻找一种方法来从 Python 中的 Google 工作表中读取单元格的格式,特别是其背景颜色。

我发现两个流行的可以读取表格的包是gspread (fork)pygsheets。我都试过了,它们在读取我的工作表数据时效果很好,但是据我所知,它们都不支持读取单元格格式,只能设置它们。 pygsheets 的 GitHub 页面上的 open issue 描述了我需要的那种功能。

本质上,每行都是具有时间戳、用户名、cmets 等的记录,我想查找特定用户名的所有行并且只查找那些没有红色背景的行,有点像这样:

if ("Username" in record.values()) and (matching_cells.background != red):
        # Do something

谢谢!

【问题讨论】:

  • 直接使用表格 REST API?还是使用 Google 的客户端库?
  • @tehhowch 我正在研究它,但我无法像其他两个一样掌握文档——这可以通过 Google 的客户端库实现吗?你能指出我正确的方向吗?
  • spreadsheets.get,请求相应的字段。请注意,Python API Explorer 非常很有帮助:developers.google.com/apis-explorer/#p/sheets/v4/…(它有一个交互式和解释性的 fields 选择器!)
  • 这看起来很有趣,我一定会去看看。谢谢@tehhowch!

标签: python python-3.x google-sheets-api gspread pygsheets


【解决方案1】:

使用google-api-python-client获取您授权的sheets API客户端,您可以通过service.spreadsheets().get方法请求电子表格数据:

def get_sheet_colors(service, wbId: str, ranges: list):
    params = {'spreadsheetId': wbId,
              'ranges': ranges,
              'fields': 'sheets(data(rowData(values(effectiveFormat/backgroundColor,formattedValue)),startColumn,startRow),properties(sheetId,title))'}
    return service.spreadsheets().get(**params).execute()

desiredA1NotationRanges = ['\'Some Arbitrary Sheet 1\'!A1:K', '\'Some Other Arbitary Sheet\'!B2:D4']
all_data = get_sheet_colors(get_authed_service_somehow(), mySpreadsheetId, desiredA1NotationRanges))
# all_data is a dict with keys determined by the fields in the request
# (i.e. "sheets") and the output of the API method used (aka consult your API reference)

下面的代码使用上面的 API 响应并制作了两个数组,一个带有背景颜色,一个带有单元格值,并通过为行和列添加前缀来确保行和列索引是可移植的,以确保数据从单元格 A1 开始,即使您请求了“C3:J5”之类的范围。这是作为将 REST 资源转换为更熟悉的类型的示例提供的,并不打算在一般意义上有用。

dataset = []
default_bg = {'red': 1, 'green': 1, 'blue': 1}
# all_data['sheets'] is a list of sheet resources (per the API spec.)
for sheet in all_data['sheets']:
    # The sheet resource is a dict with keys determined by what we requested in fields
    # (i.e. properties (->sheetId, ->title), data)
    print('Sheet name is {title} with grid id {sheetId}'.format_map(sheet["properties"]))
    # each range in data will only contain startRow and/or startColumn if they are not 0
    # (i.e. if you grab A1:___, you won't have startRow or startColumn)
    for range in sheet['data']:
        rowData = range.get('rowData', [])
        if not rowData:
            continue
        offsets = {'row': range.get('startRow', 0),
                   'col': range.get('startColumn', 0)}
        rangeBGs = [default_bg] * offsets['row']
        rangeValues = [''] * offsets['row']
        for row in rowData:
            colData = row['values']
            newBGs = [default_bg] * offsets['col']
            newVals = [''] * offsets['col']
            for col in colData:
                try:
                    newBGs.append(col['effectiveFormat']['backgroundColor'])
                except KeyError:
                    newBGs.append(default_bg) # Shouldn't get called (all cells have a background)
                try:
                    newVals.append(col['formattedValue']) # Always a string if present.
                except KeyError:
                    newVals.append('') # Not all cells have a value.
            rangeBGs.append(newBGs)
            rangeValues.append(newVals)
        dataset.append({'sheetId': sheet['properties']['sheetId'],
                        'sheetName': sheet['properties']['title'],
                        'backgrounds': rangeBGs,
                        'values': rangeValues})
# dataset is now a list with elements that correspond to the requested ranges,
# and contain 0-base row and column indexed arrays of the backgrounds and values.
# One could add logic to pop elements from the ranges if the entire row has no values.
# Color in A1 of 1st range:
r1 = dataset[0]
print(f'Cell A1 color is {r1["backgrounds"][0][0]} and has value {r1["values"][0][0]}')
print(f'Cell D2 color is {r1["backgrounds"][3][1]} and has value {r1["values"][3][1]}')

参考资料:

【讨论】:

  • 制定字段部分是最难的......
  • 您使用了哪些参考文档链接来制定fields,无论如何?我在任何地方都找不到它。
  • 要部分回答我自己的问题,通过使用这个问题Retrieving Multiple Fonts 并执行“fields=sheets”,我得到了单元格范围中使用的整个值集,所以可以找到我想要的。很高兴知道它在官方文档中的位置,授予。
  • 在“提高性能”下?那将是我的第三个猜测...... :) 无论如何,谢谢。虽然它主要有语法,但确实提到可以使用通配符,所以大概“fields=*”会给我一切,类似于“fields=sheets”。