我刚刚在Heroku部署了我的电报机器人和python电报机器人。
我的webhooks机器人使用blogger发布某些内容。到目前为止,我都是使用模块google\u apli\u客户机上稍加修改的sample\u tools自定义版本来完成这项工作的。
my\u工具
:
"""
dependencies:
pip3 install --upgrade google-api-python-client
This is a slightly modified implementation
for substituting googleapiclient.sample_tools. It helps customizing some paths
for my project files under different environments
"""
from __future__ import absolute_import
from environments import get_active_env
__all__ = ['init']
import argparse
import os
from googleapiclient import discovery
from googleapiclient.http import build_http
from oauth2client import tools, file, client
def init(argv, name, version, doc, scope=None, parents=[],
discovery_filename=None):
"""A common initialization routine for samples.
Many of the sample applications do the same initialization, which has now
been consolidated into this function. This function uses common idioms found
in almost all the samples, i.e. for an API with name 'apiname', the
credentials are stored in a file named apiname.dat, and the
client_secrets.json file is stored in the same directory as the application
main file.
Args:
argv: list of string, the command-line parameters of the application.
name: string, name of the API.
version: string, version of the API.
doc: string, description of the application. Usually set to __doc__.
file: string, filename of the application. Usually set to __file__.
parents: list of argparse.ArgumentParser, additional command-line flags.
scope: string, The OAuth scope used.
discovery_filename: string, name of local discovery file (JSON). Use
when discovery doc not available via URL.
Returns:
A tuple of (service, flags), where service is the service object and flags
is the parsed command-line flags.
"""
if scope is None:
scope = 'https://www.googleapis.com/auth/' + name
# Parser command-line arguments.
parent_parsers = [tools.argparser]
parent_parsers.extend(parents)
parser = argparse.ArgumentParser(
description=doc,
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=parent_parsers)
flags = parser.parse_args(argv[1:])
# Name of a file containing the OAuth 2.0 information for this
# application, including client_id and client_secret, which are found
# on the API Access tab on the Google APIs
# Console <http://code.google.com/apis/console>.
client_secrets = os.path.join(os.path.dirname(__file__), get_active_env(),
'client_secrets.json')
# Set up a Flow object to be used if we need to authenticate.
flow = client.flow_from_clientsecrets(client_secrets,
scope=scope,
message=tools.message_if_missing(client_secrets))
# Prepare credentials, and authorize HTTP object with them.
# If the credentials don't exist or are invalid,
# run through the native client flow.
# The Storage object will ensure that if successful the good
# credentials will get written back to a file in google_core directory.
storage_file_path = os.path.join(os.path.dirname(__file__), name + '.dat')
storage = file.Storage(storage_file_path)
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = tools.run_flow(flow, storage, flags)
http = credentials.authorize(http=build_http())
if discovery_filename is None:
# Construct a service object via the discovery service.
service = discovery.build(name,
version,
http=http,
cache_discovery=False)
else:
# Construct a service object using a local discovery document file.
with open(discovery_filename) as discovery_file:
service = discovery.build_from_document(
discovery_file.read(),
base='https://www.googleapis.com/',
http=http)
service = discovery.build(name,
version,
http=http,
cache_discovery=False)
return (service, flags)
有了它,我可以进行身份验证,操作系统中的浏览器将很好地打开,并允许我(或最终用户)授权应用程序使用我(或用户)的博客。
使用my\u工具的初始代码段
:
service, flags = my_tools.init(
[], 'blogger', 'v3', __doc__,
scope='https://www.googleapis.com/auth/blogger')
try:
posts = service.posts()
# This new_post is a custom object, but the important thing here
# is getting the authorization, and then the service at the top
insert = posts.insert(blogId=new_post.blog_id, body=new_post.body(), isDraft=new_post.is_draft)
posts_doc = insert.execute()
return posts_doc
except client.AccessTokenRefreshError:
print('The credentials have been revoked or expired, please re-run the application to re-authorize')
但现在我不能这样做,因为它在heroku中,日志中会显示以下消息:
app[web.1]: Your browser has been opened to visit:
app[web.1]:
app[web.1]: https://accounts.google.com/o/oauth2/auth?client_id=<client_id>&redirect_uri=http%3A%2F%2Flocalhost%3A8090%2F&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fblogger&access_type=offline&response_type=code
app[web.1]:
app[web.1]: If your browser is on a different machine then exit and re-run this
app[web.1]: application with the command-line parameter
app[web.1]:
app[web.1]: --noauth_local_webserver
app[web.1]:
我需要自动授权heroku应用程序,因为它只能从仅限于某些用户的telegram bot访问,所以不需要让用户访问浏览器并授权。
我需要一些方法让机器人可以使用blogger,用户可以在需要时通过简单的方式授权,或者使用服务器中已经存储的授权文件来使用机器人。
我在谷歌上搜索并查看了以下资源:
https://developers.google.com/api-client-library/python/auth/web-app
https://github.com/burnash/gspread/wiki/How-to-get-OAuth-access-token-in-console%3F
Django oauth2 google not working on server
但我完全不知道该怎么做,该怎么做。我觉得我需要一个傻瓜式的解释。
已编辑
:我已被指向此网站
https://developers.google.com/api-client-library/python/auth/service-accounts
所以我尝试了这个新代码。
新建代码段
:
from oauth2client import service_account
import googleapiclient.discovery
import os
from environments import get_active_env
SERVICE_ACCOUNT_FILE = os.path.join(os.path.dirname(__file__), os.pardir, 'google_core', get_active_env(),
'service_account.json')
credentials = service_account.ServiceAccountCredentials.from_json_keyfile_name(
SERVICE_ACCOUNT_FILE, scopes=['https://www.googleapis.com/auth/blogger'])
service = googleapiclient.discovery.build('blogger', 'v3', credentials=credentials)
try:
posts = service.posts()
insert = posts.insert(blogId=new_post.blog_id, body=new_post.body(), isDraft=new_post.is_draft)
posts_doc = insert.execute()
return posts_doc
except client.AccessTokenRefreshError:
print('The credentials have been revoked or expired, please re-run the application to re-authorize')
因此,我现在在日志中看到了这一点(我认为403 HttpError就是问题所在,关于memcache或oauth2client.contrib.locked\u文件未导入的另一个错误也没什么大不了的):
heroku[web.1]: Unidling
heroku[web.1]: State changed from down to starting
heroku[web.1]: Starting process with command `python my_bot.py`
heroku[web.1]: State changed from starting to up
heroku[router]: at=info method=POST path="/<bot_token>" host=telegram-bot-alfred.herokuapp.com request_id=<request_id> fwd="<ip>" dyno=web.1 connect=1ms service=2ms status=200 bytes=97 protocol=https
app[web.1]: INFO - Input: post_asin
app[web.1]: INFO - Input ASIN: B079Z8THTF
app[web.1]: INFO - Printing offers for asin B079Z8THTF:
app[web.1]: INFO - EUR 36.98
app[web.1]: INFO - URL being requested: GET https://www.googleapis.com/discovery/v1/apis/blogger/v3/rest
app[web.1]: INFO - Attempting refresh to obtain initial access_token
app[web.1]: INFO - URL being requested: POST https://www.googleapis.com/blogger/v3/blogs/2270688467086771731/posts?isDraft=true&alt=json
app[web.1]: INFO - Refreshing access_token
app[web.1]: WARNING - Encountered 403 Forbidden with reason "forbidden"
app[web.1]: ERROR - Error with asin B079Z8THTF. We go to the next.
app[web.1]: Traceback (most recent call last):
app[web.1]: File "my_bot.py", line 171, in process_asin_string
app[web.1]: send_post_to_blogger(update.message, post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 85, in send_post_to_blogger
app[web.1]: response = post_at_blogger(post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 72, in post_at_blogger
app[web.1]: posts_doc = insert.execute()
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/googleapiclient/http.py", line 844, in execute
app[web.1]: raise HttpError(resp, content, uri=self.uri)
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/oauth2client/_helpers.py", line 133, in positional_wrapper
app[web.1]: return wrapped(*args, **kwargs)
app[web.1]: googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/blogger/v3/blogs/2270688467086771731/posts?isDraft=true&alt=json returned "We're sorry, but you don't have permission to access this resource.">
app[web.1]: ERROR - Exception HttpError not handled
app[web.1]: Traceback (most recent call last):
app[web.1]: File "my_bot.py", line 171, in process_asin_string
app[web.1]: send_post_to_blogger(update.message, post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 85, in send_post_to_blogger
app[web.1]: response = post_at_blogger(post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 72, in post_at_blogger
app[web.1]: posts_doc = insert.execute()
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/googleapiclient/http.py", line 844, in execute
app[web.1]: raise HttpError(resp, content, uri=self.uri)
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/oauth2client/_helpers.py", line 133, in positional_wrapper
app[web.1]: return wrapped(*args, **kwargs)
app[web.1]: googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/blogger/v3/blogs/2270688467086771731/posts?isDraft=true&alt=json returned "We're sorry, but you don't have permission to access this resource.">
app[web.1]:
app[web.1]: During handling of the above exception, another exception occurred:
app[web.1]:
app[web.1]: Traceback (most recent call last):
app[web.1]: File "/app/exceptions/errors.py", line 47, in alfred
app[web.1]: message.reply_text(rnd.choice(answers[type(exception)]))
app[web.1]: KeyError: <class 'googleapiclient.errors.HttpError'>
app[web.1]: WARNING - Error with asin B079Z8THTF. We go to the next