1

我正在尝试使用 Google 的应用程序 api 授权我的 python 程序查询 google-cloud-print 队列。我正在使用来自https://developers.google.com/cloud-print/docs/pythonCode的所有信息。在包括我的登录名、密码和客户端 ID 后,我从谷歌的云应用程序中创建。我仍然收到 404 错误。Gaia 方法在令牌字典中不返回任何内容。有没有人有这方面的经验?还是使用他们新的 OAuth2 系统?我似乎在谷歌上找不到任何关于这个问题的信息。

这是我的登录详细信息已编辑的程序。

import base64
import httplib
import sys
import os
import time
import logging
import mimetools
import urllib
import urllib2
import optparse
import string
import ConfigParser
import json

CRLF = '\r\n'
BOUNDARY = mimetools.choose_boundary()

# The following are used for authentication functions.
FOLLOWUP_HOST = 'www.google.com/cloudprint'
FOLLOWUP_URI = 'select%2Fgaiaauth'
GAIA_HOST = 'www.google.com'
LOGIN_URI = '/accounts/ServiceLoginAuth'
LOGIN_URL = 'https://www.google.com/accounts/ClientLogin'
SERVICE = 'cloudprint'
OAUTH = '175351968146.apps.googleusercontent.com'

# The following are used for general backend access.
CLOUDPRINT_URL = 'http://www.google.com/cloudprint'
# CLIENT_NAME should be some string identifier for the client you are writing.
CLIENT_NAME = 'google-cloud-print'

# The following object is used in the sample code, but is not necessary.
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)




def EncodeMultiPart(fields, files, file_type='application/xml'):
    """Encodes list of parameters and files for HTTP multipart format.

    Args:
      fields: list of tuples containing name and value of parameters.
      files: list of tuples containing param name, filename, and file contents.
      file_type: string if file type different than application/xml.
    Returns:
      A string to be sent as data for the HTTP post request.
    """
    lines = []
    for (key, value) in fields:
      lines.append('--' + BOUNDARY)
      lines.append('Content-Disposition: form-data; name="%s"' % key)
      lines.append('')  # blank line
      lines.append(value)
    for (key, filename, value) in files:
      lines.append('--' + BOUNDARY)
      lines.append(
          'Content-Disposition: form-data; name="%s"; filename="%s"'
          % (key, filename))
      lines.append('Content-Type: %s' % file_type)
      lines.append('')  # blank line
      lines.append(value)
    lines.append('--' + BOUNDARY + '--')
    lines.append('')  # blank line
    return CRLF.join(lines)

def GetUrl(url, tokens, data=None, cookies=False, anonymous=False):
  """Get URL, with GET or POST depending data, adds Authorization header.

  Args:
    url: Url to access.
    tokens: dictionary of authentication tokens for specific user.
    data: If a POST request, data to be sent with the request.
    cookies: boolean, True = send authentication tokens in cookie headers.
    anonymous: boolean, True = do not send login credentials.
  Returns:
    String: response to the HTTP request.
  """
  request = urllib2.Request(url)
  if not anonymous:
    if cookies:
      logger.debug('Adding authentication credentials to cookie header')
      request.add_header('Cookie', 'SID=%s; HSID=%s; SSID=%s' % (
          tokens['SID'], tokens['HSID'], tokens['SSID']))
    else:  # Don't add Auth headers when using Cookie header with auth tokens.   
      request.add_header('Authorization', 'GoogleLogin auth=%s' % tokens['Auth'])
  request.add_header('X-CloudPrint-Proxy', 'api-prober')
  if data:
    request.add_data(data)
    request.add_header('Content-Length', str(len(data)))
    request.add_header('Content-Type', 'multipart/form-data;boundary=%s' % BOUNDARY)

  # In case the gateway is not responding, we'll retry.
  retry_count = 0
  while retry_count < 5:
    try:
      result = urllib2.urlopen(request).read()
      return result
    except urllib2.HTTPError, e:
      # We see this error if the site goes down. We need to pause and retry.
      err_msg = 'Error accessing %s\n%s' % (url, e)
      logger.error(err_msg)
      logger.info('Pausing %d seconds', 60)
      time.sleep(60)
      retry_count += 1
      if retry_count == 5:
        return err_msg

def GetCookie(cookie_key, cookie_string):
    """Extract the cookie value from a set-cookie string.

    Args:
      cookie_key: string, cookie identifier.
      cookie_string: string, from a set-cookie command.
    Returns:
      string, value of cookie.
    """
    logger.debug('Getting cookie from %s', cookie_string)
    id_string = cookie_key + '='
    cookie_crumbs = cookie_string.split(';')
    for c in cookie_crumbs:
      if id_string in c:
        cookie = c.split(id_string)
        return cookie[1]
    return None

def ConvertJson(json_str):    
  """Convert json string to a python object.

  Args:
    json_str: string, json response.
  Returns:
    dictionary of deserialized json string.
  """
  j = {}
  try:
    j = json.loads(json_str)
    j['json'] = True
  except ValueError, e:
    # This means the format from json_str is probably bad.
    logger.error('Error parsing json string %s\n%s', json_str, e)
    j['json'] = False
    j['error'] = e

  return j

def GetKeyValue(line, sep=':'):
    """Return value from a key value pair string.

    Args:
      line: string containing key value pair.
      sep: separator of key and value.
    Returns:
      string: value from key value string.
    """
    s = line.split(sep)
    return StripPunc(s[1])

def StripPunc(s):
  """Strip puncuation from string, except for - sign.

  Args:
    s: string.
  Returns:
    string with puncuation removed.
  """
  for c in string.punctuation:
    if c == '-':  # Could be negative number, so don't remove '-'.
      continue
    else:
      s = s.replace(c, '')
  return s.strip()

def Validate(response):
  """Determine if JSON response indicated success."""
  if response.find('"success": true') > 0:
    return True
  else:
    return False

def GetMessage(response):
  """Extract the API message from a Cloud Print API json response.

  Args:
    response: json response from API request.
  Returns:
    string: message content in json response.
  """
  lines = response.split('\n')
  for line in lines:
    if '"message":' in line:
      msg = line.split(':')
      return msg[1]

  return None

def ReadFile(pathname):
  """Read contents of a file and return content.

  Args:
    pathname: string, (path)name of file.
  Returns:
    string: contents of file.
  """
  try:
    f = open(pathname, 'rb')
    try:
      s = f.read()
    except IOError, e:
      logger('Error reading %s\n%s', pathname, e)
    finally:
      f.close()
      return s
  except IOError, e:
    logger.error('Error opening %s\n%s', pathname, e)
    return None

def WriteFile(file_name, data):
  """Write contents of data to a file_name.

  Args:
    file_name: string, (path)name of file.
    data: string, contents to write to file.
  Returns:
    boolean: True = success, False = errors.
  """
  status = True

  try:
    f = open(file_name, 'wb')
    try:
      f.write(data)
    except IOError, e:
      logger.error('Error writing %s\n%s', file_name, e)
      status = False
    finally:
      f.close()
  except IOError, e:
    logger.error('Error opening %s\n%s', file_name, e)
    status = False

  return status

def Base64Encode(pathname):
  """Convert a file to a base64 encoded file.

  Args:
    pathname: path name of file to base64 encode..
  Returns:
    string, name of base64 encoded file.
  For more info on data urls, see:
    http://en.wikipedia.org/wiki/Data_URI_scheme
  """
  b64_pathname = pathname + '.b64'
  file_type = mimetypes.guess_type(pathname)[0] or 'application/octet-stream'
  data = ReadFile(pathname)

  # Convert binary data to base64 encoded data.
  header = 'data:%s;base64,' % file_type
  b64data = header + base64.b64encode(data)

  if WriteFile(b64_pathname, b64data):
    return b64_pathname
  else:
    return None



def GaiaLogin(email, password):
    """Login to gaia using HTTP post to the gaia login page.

    Args:
      email: string,
      password: string
    Returns:
      dictionary of authentication tokens.
    """
    tokens = {}
    cookie_keys = ['SID', 'LSID', 'HSID', 'SSID']
    email = email.replace('+', '%2B')
    # Needs to be some random string.
    galx_cookie = base64.b64encode('%s%s' % (email, time.time()))

    # Simulate submitting a gaia login form.
    form = ('ltmpl=login&fpui=1&rm=hide&hl=en-US&alwf=true'
            '&continue=https%%3A%%2F%%2F%s%%2F%s'
            '&followup=https%%3A%%2F%%2F%s%%2F%s'
            '&service=%s&Email=%s&Passwd=%s&GALX=%s' % (FOLLOWUP_HOST,
            FOLLOWUP_URI, FOLLOWUP_HOST, FOLLOWUP_URI, SERVICE, email,
            password, galx_cookie))
    login = httplib.HTTPS(GAIA_HOST, 443)
    login.putrequest('POST', LOGIN_URI)
    login.putheader('Host', GAIA_HOST)
    login.putheader('content-type', 'application/x-www-form-urlencoded')
    login.putheader('content-length', str(len(form)))
    login.putheader('Cookie', 'GALX=%s' % galx_cookie)
    logger.info('Sent POST content: %s', form)
    login.endheaders()
    logger.info('HTTP POST to https://%s%s', GAIA_HOST, LOGIN_URI)
    login.send(form)

    (errcode, errmsg, headers) = login.getreply()
    login_output = login.getfile()
    logger.info(headers)
    login_output.close()
    login.close()
    logger.info('Login complete.')

    if errcode != 302:
      logger.error('Gaia HTTP post returned %d, expected 302', errcode)
      logger.error('Message: %s', errmsg)

    for line in str(headers).split('\r\n'):
      if not line: continue
      (name, content) = line.split(':', 1)
      if name.lower() == 'set-cookie':
        for k in cookie_keys:
          if content.strip().startswith(k):
            tokens[k] = GetCookie(k, content)

    if not tokens:
      logger.error('No cookies received, check post parameters.')
      return None
    else:
      logger.debug('Received the following authorization tokens.')
      for t in tokens:
        logger.debug(t)
      return tokens

def GetAuthTokens(email, password):
    """Assign login credentials from GAIA accounts service.

    Args:
      email: Email address of the Google account to use.
      password: Cleartext password of the email account.
    Returns:
      dictionary containing Auth token.
    """
    # First get GAIA login credentials using our GaiaLogin method.
    logger.debug("GetAuthTokens")
    tokens = GaiaLogin(email, password)
    print tokens
    if tokens:

      # We still need to get the Auth token.    
      params = {'accountType': 'GOOGLE',
                'Email': email,
                'Passwd': password,
                'service': SERVICE,
                'source': CLIENT_NAME}
      stream = urllib.urlopen(LOGIN_URL, urllib.urlencode(params))

      for line in stream:
        if line.strip().startswith('Auth='):
          tokens['Auth'] = line.strip().replace('Auth=', '')

# All of the calls to GetUrl assume you've run something like this:
tokens = GetAuthTokens('email', 'password')

所有这些代码都直接来自 google-cloud-print 开发者网站。

这是输出的最后一位。

INFO:__main__:Login complete.
ERROR:__main__:Gaia HTTP post returned 404, expected 302
ERROR:__main__:Message: Not Found
ERROR:__main__:No cookies received, check post parameters.
None

提前致谢!

4

2 回答 2

1

替换此代码

GAIA_HOST = 'www.google.com'
LOGIN_URI = '/accounts/ServiceLoginAuth'

这样

GAIA_HOST = 'accounts.google.com'
LOGIN_URI = '/ServiceLoginAuth'
于 2013-11-27T12:14:49.757 回答
1

我有同样的问题。如果您希望可以使用我刚刚发布的简单库和命令行程序。

https://github.com/escube/GoogleCloudSpooler

于 2014-07-22T12:32:50.020 回答