Google Sheet API v4 获取空单元格
Googlesheet APIv4 getting empty cells
我有一个 googlesheet,其中一列可能不包含任何信息。在遍历行并查看该列时,如果该列为空白,则它没有 returning 任何内容。更糟糕的是,如果我获取整行并包括那个公共项,比如获取 5 列,那么当任何列为空时我只返回 4 列。如果我得到一行列并且列中的一个单元格为空,我该如何 return NULL 或空字符串?
// Build a new authorized API client service.
Sheets service = GoogleSheets.getSheetsService();
range = "Functional Users!A3:E3";
response = service.spreadsheets().values().get(spreadsheetId, range).execute();
values = response.getValues();
cells = values.get(0);
我得到了一行中的 5 个单元格。 cells.size() 应该总是 return 五。但是,如果 5 个单元格中的任何一个为空白,它将减少 return 个单元格。假设只有 B3 的单元格是空的。 cells.size() 将为 4。下一次迭代,我得到 A4:E4 并且单元格 D4 为空。同样,cells.size() 将为 4。无法知道缺少哪个单元格。如果 A4 AND D4 AND E4 为空,则 cells.size() 将为 2。
无论单元格是否为空,如何将其添加到 return 5 个单元格?
我已经涉足 Sheetsv4,这确实是当您读取一系列包含空数据的单元格时的行为。似乎这就是它的设计方式。如 Reading data docs 中所述:
Empty trailing rows and columns are omitted.
所以如果你能找到一种方法来写一个代表 'empty values' 的字符,比如零,那么这就是一种方法。
我解决这个问题的方法是将值转换为 Pandas 数据框。我在我的 Google 表格中获取了我想要的特定列,然后将这些值转换为 Pandas 数据框。将数据集转换为 Pandas 数据框后,我进行了一些数据格式化,然后将数据框转换回列表。通过将列表转换为 Pandas 数据框,每一列都会被保留。 Pandas 已经为空的尾随行和列创建了空值。但是,我还需要转换具有空值的非尾随行以保持一致性。
# Authenticate and create the service for the Google Sheets API
credentials = ServiceAccountCredentials.from_json_keyfile_name(KEY_FILE_LOCATION, SCOPES)
http = credentials.authorize(Http())
discoveryUrl = ('https://sheets.googleapis.com/$discovery/rest?version=v4')
service = discovery.build('sheets', 'v4',
http=http,discoveryServiceUrl=discoveryUrl)
spreadsheetId = 'id of your sheet'
rangeName = 'range of your dataset'
result = service.spreadsheets().values().get(
spreadsheetId=spreadsheetId, range=rangeName).execute()
values = result.get('values', [])
#convert values into dataframe
df = pd.DataFrame(values)
#replace all non trailing blank values created by Google Sheets API
#with null values
df_replace = df.replace([''], [None])
#convert back to list to insert into Redshift
processed_dataset = df_replace.values.tolist()
我在使用工作表 api 的 V4 时遇到了同样的问题,但能够使用范围末尾的额外列和 values.get
的 valueRenderOption
参数解决此问题] API
给定三列 A、B 和 C,其中任何一列都可能包含空值,添加一个附加列 D 并在此处添加任意值,例如 'blank'.
确保捕获范围内的新列并添加附加参数,
valueRenderOption: 'FORMATTED_VALUE'
。
您应该以类似这样的调用结束:
sheets.spreadsheets.values.get({
spreadsheetId: SOME_SHEET_ID,
range: "AUTOMATION!A:D",
valueRenderOption: 'FORMATTED_VALUE'
}, (err, res) => {})
这将为您提供每个值的长度一致的数组,并在空单元格值的位置返回一个空白字符串“”。
我能找到的唯一解决方案是编写您自己的函数:
def _safe_get(data, r, c):
try:
return data[r][c]
except IndexError:
return ''
def read(range_name, service):
result = service[0].spreadsheets().values().get(spreadsheetId=service[1],
range=range_name).execute()
return result.get('values', [])
def safe_read(sheet, row, col, to_row='', to_col='', service=None):
range_name = '%s!%s%i:%s%s' % (sheet, col, row, to_col, to_row)
data = read(range_name, service)
if to_col == '':
cols = max(len(line) for line in data)
else:
cols = ord(to_col.lower()) - ord(col.lower()) + 1
if to_row == '':
rows = len(data)
else:
rows = to_row - row + 1
return [[_safe_get(data, r, c)
for c in range(cols)]
for r in range(rows)]
我知道这太晚了,但为了防止将来遇到此问题的其他人想要修复它,我将分享我为解决此问题所做的工作。
我所做的是将我正在寻找的单元格范围的长度增加一个。然后在我正在阅读的 Google 电子表格中,我添加了一行“."s in the extra column (The column added to the array now that the desired range of cells has increased). Then I protected that line of periods so that it can't be changed from the "”。
这种方式为您提供了一个数组,其中包含您要查找的所有内容,包括空结果,但确实会将数组大小增加 1。但是如果这让您感到困扰,您可以创建一个没有数组最后一个索引的新数组。
如果您从 google sheet API v4 中拉出一个范围,则如果空行数据位于所选范围的开头或中间,则包含空行数据。 仅省略范围末尾没有数据的单元格。使用此假设,您可以 'fill' 应用代码中的无数据单元格。
例如,如果您选择 A1:A5 而 A1 没有值,它仍将在行数据中返回为 {}
。
如果缺少 A5,那么您将得到一个长度为 4 的数组,因此知道要填充空的 A5。
如果 A4 和 A5 为空,那么您将得到一个长度为 3 的数组,依此类推。
如果范围 none 包含数据,那么您将收到一个空对象。
如果行中的最后一个单元格有值,则该行将完全返回
例如:
行数:
|Nick|29 years|Minsk|
|Mike| |Pinsk|
|Boby| | |
Return:
[
["Nick", "29 years", "Minsk"],
["Mike", "", "Pinsk"]
["Boby"]
]
因此,当您添加一个包含空单元格而不是空单元格(""
或 null
)的新行时,只需使用 space " "
然后当您读取值时,只需将 space " "
中的所有项目映射到空 ""
行数:
|Nick|29 years|Minsk|
|Mike| |Pinsk|
|Boby| |" " |
Return:
[
["Nick", "29 years", "Minsk"],
["Mike", "", "Pinsk"]
["Boby", "", " "]
]
只需添加:
values.add("");
之前:
cells = values.get(0);
这将确保您不会因为空白单元格或行而查询空列表。
另一个选项是遍历返回的行,检查行的长度并附加您期望返回的任何数据。我发现这比将垃圾数据添加到我的数据集更可取。
我来晚了,但还有另一种选择:
def read_sheet(service, SPREADSHEET_ID, range) -> pd.DataFrame:
result = service.spreadsheets().values().get(spreadsheetId=SPREADSHEET_ID, range=range).execute()
rows = result.get('values', [])
df = pd.DataFrame(rows[0:])
df.columns = df.iloc[0]
df = df.drop(axis=0, index=0)
return df
要使此解决方案生效,您需要在要阅读的电子表格的所有列中输入 headers(列名)。它将加载没有 headers(列名)规范的 pandas df,用第一行替换列名,然后删除它。
Sheets API V4,应该 return 所有空白直到最后填充的列。
这将填补空白:
values = result.get('values', [])
print(values[1:5]) # [['Spinach Lasagna', '10', '5', '', 'x'], ['Hot Dish', '10', '5', '', '', '', 'x'], ['Tuna-Noodle Casserole', '10', '5', '', 'x', '', '', 'x'], ['Sausage and Peppers', '10', '3', '', '', '', '', '', 'x']]
n_col = 14 # hard code
n_col = max([len(i) for i in values]) # if last column is occupied at least once
n_col = len(values[0]) # if you have header
values = [lst + ([''] * (n_col - len(lst))) for lst in values]
print(values[1:4]) # [['Spinach Lasagna', '10', '5', '', 'x', '', '', '', '', '', '', '', '', ''], ['Hot Dish', '10', '5', '', '', '', 'x', '', '', '', '', '', '', ''], ['Tuna-Noodle Casserole', '10', '5', '', 'x', '', '', 'x', '', '', '', '', '', '']]
我有一个 googlesheet,其中一列可能不包含任何信息。在遍历行并查看该列时,如果该列为空白,则它没有 returning 任何内容。更糟糕的是,如果我获取整行并包括那个公共项,比如获取 5 列,那么当任何列为空时我只返回 4 列。如果我得到一行列并且列中的一个单元格为空,我该如何 return NULL 或空字符串?
// Build a new authorized API client service.
Sheets service = GoogleSheets.getSheetsService();
range = "Functional Users!A3:E3";
response = service.spreadsheets().values().get(spreadsheetId, range).execute();
values = response.getValues();
cells = values.get(0);
我得到了一行中的 5 个单元格。 cells.size() 应该总是 return 五。但是,如果 5 个单元格中的任何一个为空白,它将减少 return 个单元格。假设只有 B3 的单元格是空的。 cells.size() 将为 4。下一次迭代,我得到 A4:E4 并且单元格 D4 为空。同样,cells.size() 将为 4。无法知道缺少哪个单元格。如果 A4 AND D4 AND E4 为空,则 cells.size() 将为 2。
无论单元格是否为空,如何将其添加到 return 5 个单元格?
我已经涉足 Sheetsv4,这确实是当您读取一系列包含空数据的单元格时的行为。似乎这就是它的设计方式。如 Reading data docs 中所述:
Empty trailing rows and columns are omitted.
所以如果你能找到一种方法来写一个代表 'empty values' 的字符,比如零,那么这就是一种方法。
我解决这个问题的方法是将值转换为 Pandas 数据框。我在我的 Google 表格中获取了我想要的特定列,然后将这些值转换为 Pandas 数据框。将数据集转换为 Pandas 数据框后,我进行了一些数据格式化,然后将数据框转换回列表。通过将列表转换为 Pandas 数据框,每一列都会被保留。 Pandas 已经为空的尾随行和列创建了空值。但是,我还需要转换具有空值的非尾随行以保持一致性。
# Authenticate and create the service for the Google Sheets API
credentials = ServiceAccountCredentials.from_json_keyfile_name(KEY_FILE_LOCATION, SCOPES)
http = credentials.authorize(Http())
discoveryUrl = ('https://sheets.googleapis.com/$discovery/rest?version=v4')
service = discovery.build('sheets', 'v4',
http=http,discoveryServiceUrl=discoveryUrl)
spreadsheetId = 'id of your sheet'
rangeName = 'range of your dataset'
result = service.spreadsheets().values().get(
spreadsheetId=spreadsheetId, range=rangeName).execute()
values = result.get('values', [])
#convert values into dataframe
df = pd.DataFrame(values)
#replace all non trailing blank values created by Google Sheets API
#with null values
df_replace = df.replace([''], [None])
#convert back to list to insert into Redshift
processed_dataset = df_replace.values.tolist()
我在使用工作表 api 的 V4 时遇到了同样的问题,但能够使用范围末尾的额外列和 values.get
的 valueRenderOption
参数解决此问题] API
给定三列 A、B 和 C,其中任何一列都可能包含空值,添加一个附加列 D 并在此处添加任意值,例如 'blank'.
确保捕获范围内的新列并添加附加参数,
valueRenderOption: 'FORMATTED_VALUE'
。
您应该以类似这样的调用结束:
sheets.spreadsheets.values.get({
spreadsheetId: SOME_SHEET_ID,
range: "AUTOMATION!A:D",
valueRenderOption: 'FORMATTED_VALUE'
}, (err, res) => {})
这将为您提供每个值的长度一致的数组,并在空单元格值的位置返回一个空白字符串“”。
我能找到的唯一解决方案是编写您自己的函数:
def _safe_get(data, r, c):
try:
return data[r][c]
except IndexError:
return ''
def read(range_name, service):
result = service[0].spreadsheets().values().get(spreadsheetId=service[1],
range=range_name).execute()
return result.get('values', [])
def safe_read(sheet, row, col, to_row='', to_col='', service=None):
range_name = '%s!%s%i:%s%s' % (sheet, col, row, to_col, to_row)
data = read(range_name, service)
if to_col == '':
cols = max(len(line) for line in data)
else:
cols = ord(to_col.lower()) - ord(col.lower()) + 1
if to_row == '':
rows = len(data)
else:
rows = to_row - row + 1
return [[_safe_get(data, r, c)
for c in range(cols)]
for r in range(rows)]
我知道这太晚了,但为了防止将来遇到此问题的其他人想要修复它,我将分享我为解决此问题所做的工作。 我所做的是将我正在寻找的单元格范围的长度增加一个。然后在我正在阅读的 Google 电子表格中,我添加了一行“."s in the extra column (The column added to the array now that the desired range of cells has increased). Then I protected that line of periods so that it can't be changed from the "”。 这种方式为您提供了一个数组,其中包含您要查找的所有内容,包括空结果,但确实会将数组大小增加 1。但是如果这让您感到困扰,您可以创建一个没有数组最后一个索引的新数组。
如果您从 google sheet API v4 中拉出一个范围,则如果空行数据位于所选范围的开头或中间,则包含空行数据。 仅省略范围末尾没有数据的单元格。使用此假设,您可以 'fill' 应用代码中的无数据单元格。
例如,如果您选择 A1:A5 而 A1 没有值,它仍将在行数据中返回为 {}
。
如果缺少 A5,那么您将得到一个长度为 4 的数组,因此知道要填充空的 A5。 如果 A4 和 A5 为空,那么您将得到一个长度为 3 的数组,依此类推。
如果范围 none 包含数据,那么您将收到一个空对象。
如果行中的最后一个单元格有值,则该行将完全返回 例如:
行数:
|Nick|29 years|Minsk|
|Mike| |Pinsk|
|Boby| | |
Return:
[
["Nick", "29 years", "Minsk"],
["Mike", "", "Pinsk"]
["Boby"]
]
因此,当您添加一个包含空单元格而不是空单元格(""
或 null
)的新行时,只需使用 space " "
然后当您读取值时,只需将 space " "
中的所有项目映射到空 ""
行数:
|Nick|29 years|Minsk|
|Mike| |Pinsk|
|Boby| |" " |
Return:
[
["Nick", "29 years", "Minsk"],
["Mike", "", "Pinsk"]
["Boby", "", " "]
]
只需添加:
values.add("");
之前:
cells = values.get(0);
这将确保您不会因为空白单元格或行而查询空列表。
另一个选项是遍历返回的行,检查行的长度并附加您期望返回的任何数据。我发现这比将垃圾数据添加到我的数据集更可取。
我来晚了,但还有另一种选择:
def read_sheet(service, SPREADSHEET_ID, range) -> pd.DataFrame:
result = service.spreadsheets().values().get(spreadsheetId=SPREADSHEET_ID, range=range).execute()
rows = result.get('values', [])
df = pd.DataFrame(rows[0:])
df.columns = df.iloc[0]
df = df.drop(axis=0, index=0)
return df
要使此解决方案生效,您需要在要阅读的电子表格的所有列中输入 headers(列名)。它将加载没有 headers(列名)规范的 pandas df,用第一行替换列名,然后删除它。
Sheets API V4,应该 return 所有空白直到最后填充的列。
这将填补空白:
values = result.get('values', [])
print(values[1:5]) # [['Spinach Lasagna', '10', '5', '', 'x'], ['Hot Dish', '10', '5', '', '', '', 'x'], ['Tuna-Noodle Casserole', '10', '5', '', 'x', '', '', 'x'], ['Sausage and Peppers', '10', '3', '', '', '', '', '', 'x']]
n_col = 14 # hard code
n_col = max([len(i) for i in values]) # if last column is occupied at least once
n_col = len(values[0]) # if you have header
values = [lst + ([''] * (n_col - len(lst))) for lst in values]
print(values[1:4]) # [['Spinach Lasagna', '10', '5', '', 'x', '', '', '', '', '', '', '', '', ''], ['Hot Dish', '10', '5', '', '', '', 'x', '', '', '', '', '', '', ''], ['Tuna-Noodle Casserole', '10', '5', '', 'x', '', '', 'x', '', '', '', '', '', '']]