PyInstaller打包Google Sheets API脚本为exe后报UnknownApiNameOrVersion错误
问题:PyInstaller打包Google Sheets脚本为.exe后执行报错
我编写了Python脚本用于读写Google Sheet数据,使用PyInstaller打包为.exe文件后无法执行,报错信息如下:
File "GoogleSheet.py", line 9, in __init__ File "Google_Process.py", line 31, in __init__ File "googleapiclient\_helpers.py", line 130, in positional_wrapper File "googleapiclient\discovery.py", line 287, in build File "googleapiclient\discovery.py", line 404, in _retrieve_discovery_doc googleapiclient.errors.UnknownApiNameOrVersion: name: sheets version: v4
相关代码文件:
GoogleSheet.py
from Google_Process import GoogleAPIClient import pandas as pd class GoogleSheets(GoogleAPIClient): def __init__(self, status = 'DONE', order_number = '') -> None: self.status = status self.order_number = order_number # 调用GoogleAPIClient.__init__,传入服务名、版本、权限范围 super().__init__( 'sheets', 'v4', ['https://www.googleapis.com/auth/spreadsheets'], ) def appendWorksheet(self): if self.status == 'DONE': df=pd.DataFrame( {'Order': [self.order_number], 'Status': ['DONE'], 'Mark': ['-']} ) self.googleAPIService.spreadsheets().values().append( spreadsheetId='<ID>', range='sheet1', valueInputOption='USER_ENTERED', body={ 'majorDimension': 'ROWS', 'values': df.values.tolist() }, ).execute() return
Google_Process.py
import os.path from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build class GoogleAPIClient: SECRET_PATH = '.\PackingElf\.credentials\client_secrets_file.json' CREDS_PATH = '.\PackingElf\.credentials\cred.json' def __init__(self, serviceName: str, version: str, scopes: list) -> None: self.creds = None # client_secret.json用于存储用户的访问和刷新令牌,首次授权完成后自动创建 if os.path.exists(self.CREDS_PATH): self.creds = Credentials.from_authorized_user_file(self.CREDS_PATH, scopes) # 若无有效凭证,引导用户登录授权 if not self.creds or not self.creds.valid: if self.creds and self.creds.expired and self.creds.refresh_token: self.creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( self.SECRET_PATH, scopes) self.creds = flow.run_local_server(port=0) # 保存凭证供下次使用 with open(self.CREDS_PATH, 'w') as token: token.write(self.creds.to_json()) self.googleAPIService = build(serviceName, version, credentials=self.creds) if __name__ == '__main__': googleSheetAPI = GoogleAPIClient( 'sheets', 'v4', ['https://www.googleapis.com/auth/spreadsheets'], ) print(googleSheetAPI.googleAPIService)
解决方案
报错原因是PyInstaller打包时未包含Google API客户端的发现文档,导致build()方法无法获取到Sheets API的服务定义。以下是两种可行解决方法:
方法一:修改PyInstaller打包命令,包含发现文档
在打包时,通过--add-data参数将Google API客户端的发现文档目录包含到exe中:
# 替换<Python路径>为你的Python安装路径,比如C:\Python39 pyinstaller --onefile --add-data "<Python路径>\Lib\site-packages\googleapiclient\discovery_docs;googleapiclient\discovery_docs" GoogleSheet.py
该命令会将本地Python环境中googleapiclient的discovery_docs目录复制到打包后的程序目录对应位置,让build()方法能找到离线的API定义。
方法二:修改代码,使用本地离线发现文档
- 下载Sheets v4的发现文档:访问API官方定义地址,将内容保存为
sheets_v4.json,放到项目根目录。 - 修改
Google_Process.py代码,添加路径处理逻辑并指定离线发现文档:
import os.path import sys from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build class GoogleAPIClient: def __init__(self, serviceName: str, version: str, scopes: list) -> None: self.creds = None # 获取程序运行路径(打包后用sys._MEIPASS,未打包用当前脚本路径) base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))) # 修正凭证文件路径,避免打包后找不到 self.SECRET_PATH = os.path.join(base_path, 'PackingElf', '.credentials', 'client_secrets_file.json') self.CREDS_PATH = os.path.join(base_path, 'PackingElf', '.credentials', 'cred.json') if os.path.exists(self.CREDS_PATH): self.creds = Credentials.from_authorized_user_file(self.CREDS_PATH, scopes) if not self.creds or not self.creds.valid: if self.creds and self.creds.expired and self.creds.refresh_token: self.creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( self.SECRET_PATH, scopes) self.creds = flow.run_local_server(port=0) with open(self.CREDS_PATH, 'w') as token: token.write(self.creds.to_json()) # 使用本地离线发现文档 discovery_doc_path = os.path.join(base_path, 'sheets_v4.json') self.googleAPIService = build( serviceName, version, credentials=self.creds, discoveryServiceUrl=f'file://{discovery_doc_path}' ) if __name__ == '__main__': googleSheetAPI = GoogleAPIClient( 'sheets', 'v4', ['https://www.googleapis.com/auth/spreadsheets'], ) print(googleSheetAPI.googleAPIService)
- 打包时将
sheets_v4.json和凭证文件也包含进去:
pyinstaller --onefile --add-data "sheets_v4.json;." --add-data "PackingElf\.credentials\client_secrets_file.json;PackingElf\.credentials" GoogleSheet.py
内容的提问来源于stack exchange,提问作者Alexllll
相关产品推荐
相关产品推荐

