如何用Python在我的Google Fusion表中插入一行?

1 投票
1 回答
2833 浏览
提问于 2025-04-17 18:36

我正在做一个项目,其中一部分需要通过一个Python脚本向Google Fusion Table插入数据行。我花了几天时间试图弄明白该怎么做,但现在我真的有点困惑。

根据我的研究,我发现需要使用Oauth 2.0来访问API。通过这个方式,我可以成功获取一个访问令牌,但我似乎无法成功获取刷新令牌。我不确定这是否会影响我将Fusion Table与Python代码成功集成的能力。

我遇到的第二个问题是,我不太明白如何编写代码来插入一行到我的表格中。我找到的大部分资料都是关于已经不再支持的Fusion Tables SQL API的,我对新的操作方式还不是很了解。

我还是个初学者,任何帮助我理解的方向都非常感谢!

编辑:

到目前为止,我的代码看起来是这样的:

client_id = "<client_i>"
client_secret = "<client_secret>"
table_id = "<table_id>"

access_token = ""
refresh_token = "<refresh_token>"

#   the refresh token is used to request a new access token
data = urllib.urlencode({
  'client_id': client_id,
  'client_secret': client_secret,
  'refresh_token': refresh_token,
  'grant_type': 'refresh_token'})
request = urllib2.Request(
  url='https://accounts.google.com/o/oauth2/token',
  data=data)
request_open = urllib2.urlopen(request)
response = request_open.read()
request_open.close()
tokens = json.loads(response)
access_token = tokens['access_token']

#   Read the table
request_read = urllib2.Request(
  url='https://www.google.com/fusiontables/api/query?%s' % \
    (urllib.urlencode({'access_token': access_token,
                       'sql': 'SELECT * FROM table_id'})))
request_open = urllib2.urlopen(request_read)
response = request_open.read()
request_open.close()
print response

这是我尝试向表格插入新行的代码:

date = str(datetime.now().date())
time = str(datetime.now().time())
query = 'INSERT INTO table_id (Date,Time,Saskatoon,Regina,MeadowLake)VALUES(date,time,60.01,60.02,59.99)'
data = urllib2.Request(
  url='https://www.google.com/fusiontables/api/query?%s' % \
    (urllib.urlencode({'access_token': access_token,
                       'sql': query})))
request_open = urllib2.urlopen(data)

当我运行这个时,我得到的错误是:

HTTP错误400:HTTP GET只能用于选择查询。

我知道插入数据时应该使用POST而不是GET,但我不确定我的代码需要做什么更改才能实现这一点。抱歉,我还是个菜鸟。

第二次编辑:

抱歉让这个变得更长,但我觉得展示我到目前为止的进展是很重要的。我切换到了requests库,事情变得稍微简单了一些,但我仍然没有成功进行POST操作。我的新行导入代码如下:

def importRows(self):
    print 'IMPORT ROWS'
    date = str(datetime.now().date())
    time = str(datetime.now().time())
    data = {'Date': date,
            'Time': time,
            'Saskatoon': '60.01',
            'Regina': '59.95'}
    url = 'https://www.googleapis.com/upload/fusiontables/v1/tables/%s/import/%s' % \
          (tableid, self.params) # self.params is access token
    importRow = requests.post(url, params=data)

    print importRow.status_code
    print importRow.text

这段代码给我的结果是:

400
{
 "error": {
  "errors": [
   {
    "domain": "fusiontables",
    "reason": "badImportInputEmpty",
    "message": "Content is empty."
   }
  ],
  "code": 400,
  "message": "Content is empty."
 }
}

1 个回答

1

如果你的应用需要离线访问Google的API,那么请求授权码时需要加上一个叫做access_type的参数,值设置为offline。

https://developers.google.com/accounts/docs/OAuth2WebServer#offline

然后,要使用刷新令牌获取访问令牌,你需要发送一个POST请求,里面包含grant_type,值为refresh_token

简单来说,SQL的工作方式是你通过POST请求发送一部分SQL语句,格式是https://www.googleapis.com/fusiontables/v1/query?sql=STATEMENT_HERE

可以参考以下链接:

https://developers.google.com/fusiontables/docs/v1/reference/query https://developers.google.com/fusiontables/docs/v1/sql-reference

补充:

因为你在使用urllib2时没有设置数据参数,所以默认是GET请求。要解决这个问题,你可以使用其他HTTP库,像是requests或者httplib,或者可以这样做:

query = "INSERT INTO %s(EXAMPLE_COL1,EXAMPLE_COL2) VALUES"\
        "('EXAMPLE_INFO1','EXAMPLE_INFO2')" % table_id # Single quotes
opener = urllib2.build_opener(urllib2.HTTPHandler)
request = urllib2.Request('https://www.google.com/fusiontables/api/query?%s' % \
    (urllib.urlencode({'access_token': access_token,
                       'sql': query})),
    headers={'Content-Length':0})      # Manually set length to avoid 411 error
request.get_method = lambda: 'POST'    # Change HTTP request method
response = opener.open(request).read()
print response

需要注意的是:

  1. 需要修改方法来实现我们想要的(用空主体的POST请求),否则会收到HTTP Error 400: HTTP GET can only be used for SELECT queries的错误。

  2. 要手动指定我们没有主体(Content-Length0),否则会收到HTTP Error 411: Length Required的错误。

  3. 提交字符串时必须使用双引号包裹,内部用单引号,或者转义内部引号。换句话说,"INSERT INTO %s(EXAMPLE_COL1,EXAMPLE_COL2) VALUES(EXAMPLE_INFO1,EXAMPLE_INFO2)" % table_id是行不通的。

    如果我们尝试使用上面的代码,会得到类似HTTP Error 400: Parse error near 'SOME_STRING' (line X, position Y)的错误。

关于如何用urllib2更改请求方法的信息,可以查看:

Is there any way to do HTTP PUT in python

撰写回答