Python调用GitHub GraphQL API格式化查询触发KeyError问题求助
Fixing KeyError When Formatting GitHub GraphQL Audit Log Query in Python
我看你遇到的问题是Python脚本里的str.format()抛出了KeyError,这是因为你的GraphQL查询字符串里充满了花括号{},而Python的format()方法会把所有未转义的{}都当成占位符来处理——但你只准备了两个要替换的值(组织名和after参数),其他的花括号属于GraphQL语法,却被误判成需要填充的占位符,所以才会出现KeyError: '\n organization(login'这种错误。
解决方案:转义GraphQL中的花括号
要解决这个问题,你需要把GraphQL查询里所有不需要替换的花括号都转义成双花括号{{}},这样Python的format()方法就会把它们当成普通的单花括号输出,而只处理你指定的两个占位符。
修正后的查询字符串应该是这样的:
# 转义所有GraphQL语法的花括号,只保留需要替换的两个{} Query = """ query {{ organization(login: '{}') {{ auditLog(first: 100, {}) {{ edges {{ node {{ ... on RepositoryAuditEntryData {{ repository {{ name }} }} ... on OrganizationAuditEntryData {{ organizationResourcePath organizationName organizationUrl }} ... on TeamAuditEntryData {{ teamName }} ... on TopicAuditEntryData {{ topicName }} ... on OauthApplicationAuditEntryData {{ oauthApplicationName }} ... on EnterpriseAuditEntryData {{ enterpriseResourcePath enterpriseUrl enterpriseSlug }} ... on AuditEntry {{ actorResourcePath action actorIp actorLogin operationType createdAt actorLocation {{ countryCode country regionCode region city }} #User 'Action' was performed on userLogin userResourcePath userUrl }} }} cursor }} pageInfo {{ endCursor hasNextPage hasPreviousPage }} }} }} }} """
另外,我注意到你原来的第二个占位符加了单引号'{}',其实可以去掉——因为当after变量是空字符串时,这部分会变成空,不会破坏GraphQL语法;当有值时,你已经在after = 'after: "%s"' % ...里加了正确的格式,替换后会变成auditLog(first: 100, after: "XYZ"),和你在Insomnia/Postman里的正确查询结构一致。
额外优化建议
- 检查请求状态码:除了检查返回的JSON里的
errors,最好先判断result.status_code == 200,避免因为网络问题或权限错误导致的非JSON响应。 - 打印调试查询:在发送请求前可以先打印格式化后的查询字符串,确认语法是否正确:
formatted_query = Query.format(org, after) print(formatted_query) result = requests.post('https://api.github.com/graphql', json={'query': formatted_query}, headers=headers) - 确保headers正确:你的
headers变量需要包含GitHub的认证token,比如:
注意token需要有headers = {"Authorization": "Bearer YOUR_GITHUB_PERSONAL_ACCESS_TOKEN"}read:audit_log权限才能拉取审计日志。
修正后的完整脚本片段
import requests import json import time headers = {"Authorization": "Bearer YOUR_GITHUB_TOKEN"} # 转义后的GraphQL查询模板 Query = """ query {{ organization(login: '{}') {{ auditLog(first: 100, {}) {{ edges {{ node {{ ... on RepositoryAuditEntryData {{ repository {{ name }} }} ... on OrganizationAuditEntryData {{ organizationResourcePath organizationName organizationUrl }} ... on TeamAuditEntryData {{ teamName }} ... on TopicAuditEntryData {{ topicName }} ... on OauthApplicationAuditEntryData {{ oauthApplicationName }} ... on EnterpriseAuditEntryData {{ enterpriseResourcePath enterpriseUrl enterpriseSlug }} ... on AuditEntry {{ actorResourcePath action actorIp actorLogin operationType createdAt actorLocation {{ countryCode country regionCode region city }} userResourcePath userUrl }} }} cursor }} pageInfo {{ endCursor hasNextPage hasPreviousPage }} }} }} }} """ org_list = ["CoreDevOpsTools", "JIRA-Cloud"] res = [] for org in org_list: after = '' while True: formatted_query = Query.format(org, after) # 可选:打印调试查询 # print(formatted_query) result = requests.post('https://api.github.com/graphql', json={'query': formatted_query}, headers=headers) # 检查请求是否成功 if result.status_code != 200: print(f"Request failed with status code: {result.status_code}") break json_data = json.loads(result.text) if 'errors' in json_data: print(json_data['errors']) break res_list = json_data['data']['organization']['auditLog'] for items in res_list['edges']: res.append(items) if not res_list['pageInfo']['hasNextPage']: break after = 'after: "%s"' % res_list['edges'][-1]['cursor'] time.sleep(1) # 处理结果 print(f"Total audit log entries fetched: {len(res)}")
这样修改后,你的脚本应该就能正常运行,不会再抛出KeyError了。
内容的提问来源于stack exchange,提问作者Kishan Kumar Gupta
相关产品推荐
相关产品推荐

