I want to send a Telegram message using the native Python requests so that the "First Name" is received in using in BOLD. I have tried HTML and Markdown syntax but it's not showing.
import json
import requests
# Telegram bot configurations
TELE_TOKEN='TOKEN'
URL = "https://api.telegram.org/bot{}/".format(TELE_TOKEN)
def send_message(text, chat_id):
url = URL + "sendMessage?text={}&chat_id={}".format(text, chat_id)
requests.get(url)
# AWS Lambda handler
def lambda_handler(event, context):
message = json.loads(event['body'])
chat_id = message['message']['chat']['id']
first_name = message['message']['chat']['first_name']
text = message['message']['text']
# How can the first name be in BOLD?
reply = "Hello " + first_name + "! You have said:" + text
send_message(reply, chat_id)
return {
'statusCode': 200
}
Telegram supports formatting in either HTML or Markdown. For formatting, you have to set the parse_mode parameter to either HTML,Markdown (legacy), orMarkdownV2.
E.g.: To get the output as "bold text", you could use,
text=<b>bold text</b>&parse_mode=HTML or
text=*bold text*&parse_mode=Markdown or
text=*bold text*&parse_mode=MarkdownV2.
You could simply do that change in your code snippet;
def send_message(text, chat_id):
url = URL + "sendMessage?text={}&chat_id={}&parse_mode=MarkdownV2".format(text, chat_id)
requests.get(url)
# AWS Lambda handler
def lambda_handler(event, context):
...
# How can the first name be in BOLD?
reply = "Hello *" + first_name + "*! You have said:" + text
...
Read more about the formatting options here: https://core.telegram.org/bots/api#formatting-options
Related
I'm trying to create a python telegram bot that send random news every x time, and it works when i give the method news() the chat_id statically directly on the method, I tried passing it directly on the method start(), that execute a run_repeating job like that:
def start():
context.job_queue.run_repeating(news(update=update, context=context), interval=newsTimer, first=1)
but after you run the command for the first time (and works) it trows a lot of errors.
Instead I hardcoded the chat_id inside the news() method.
Anyone has any hint on how could I pass the variable update to the news() method?
Here's my full code:
from dotenv import load_dotenv
import telegram.ext
import requests
import datetime
import random
import json
import os
load_dotenv()
token = os.getenv('TOKEN')
api = os.getenv('API')
languages = "en"
newsTimer = 600
query = "world"
pageSize = "100"
yesterday = str(datetime.datetime.now() - datetime.timedelta(days=1))
today = str(datetime.datetime.now())
api_url = "https://newsapi.org/v2/everything?q=" + query + "&from=" + yesterday + "&to=" + today + "&sortBy=popularity&pageSize=+"+ pageSize +"&apiKey=" + api
def start(update, context):
context.job_queue.run_repeating(news, interval=newsTimer, first=1)
def help(update, context):
update.message.reply_text("""
Available commands:
/start - start bot
/help - help
""")
def news(context):
response = requests.get(api_url)
json_data = json.loads(response.text)
i = random.randint(0, 99)
title = json_data['articles'][i]['title']
image = json_data['articles'][i]['urlToImage']
description = json_data['articles'][i]['description']
author = json_data['articles'][i]['author']
article = json_data['articles'][i]
if title is None:
title = "No title"
if image is None:
image = "https://www.alfasolare.ru/a_solar_restyle/wp-content/themes/consultix/images/no-image-found-360x260.png"
if description is None:
description = "No Content"
if author is None:
author = "No Author"
if article is None:
i = random.randint(0, len(json_data['articles']))
caption = "<a>" + title + "\n" + description + "\n Author: " + author + "</a>"
chat_id = "XXXXXXXXX" #my own chat id
context.bot.send_photo(
chat_id=chat_id,
photo=image,
caption=caption,
parse_mode=telegram.ParseMode.HTML
)
if __name__ == '__main__':
updater = telegram.ext.Updater(token, use_context=True)
dispatcher = updater.dispatcher
dispatcher.add_handler(telegram.ext.CommandHandler('start', start))
dispatcher.add_handler(telegram.ext.CommandHandler('help', help))
if updater.start_polling():
print("Bot started successfully!")
if updater.idle():
print("Bot stopped")
context.job_queue.run_repeating(news(update=update, context=context), interval=newsTimer, first=1)
this can't work since the callback argument of JobQueue.run_* must be a function. However, news(update=update, context=context) is the return value of that function call, which is None as news doesn't return anything.
To pass additional data to the job callback, you can use the context argument of JobQueue.run_*. This is also explained in PTBs wiki page on JobQueue and showcased in the timerbot.py example.
Disclaimer: I'm currently the maintainer of python-telegram-bot
I am trying to send an authentificated message over an API at iconomi.com.
I am used to sign message when dealing with other exchange API, but can't be authentificated with this specific one.
I read the official documentation for authentification:
You generate the ICN-SIGN header by creating a sha512 HMAC using the
base64-decoded secret key on the prehash string timestamp + method +
requestPath + body (where + represents string concatenation) and
base64-encode the output, where:
the timestamp value is the same as the ICN-TIMESTAMP header. the body
is the request body string or omitted if there is no request body
(typically for GET requests). method must always be in upper case
Example: base64_encode(HMAC_SHA512(secret_key, timestamp + upper_case(method) + requestPath + body))
I found also a java client example on the official github, please see bellow signature generation in java :
private String generateServerDigest(String method, String uri, long timestamp, String body) {
//return timestamp + request.getMethodValue() + uri + body;
String checkDigestString = timestamp + method + uri + body;// "GET+/v1/daa-list+123123123"; //timestamp in epoch milliseconds
// hash server composited digest with algorithm and apikeys secret
SecretKeySpec signingKey = new SecretKeySpec(apiSecret.getBytes(), "HmacSHA512");
Mac mac;
try {
mac = Mac.getInstance(signingKey.getAlgorithm());
mac.init(signingKey);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
log.warn("Could not ={}", signingKey.getAlgorithm());
return null;
}
return Base64.getEncoder().encodeToString(mac.doFinal(checkDigestString.getBytes()));
}
Please note that checkDigestString code timestamp + method + uri + body and comment GET+/v1/daa-list+123123123 are already different on the official doc.
And this is my python implementation attempt :
def sign(timestamp,method,requestPath,body):
global api_secret
base64_decoded_secret_key = base64.b64decode(api_secret)
content_to_hash = (str(timestamp) + method.upper() + requestPath + body).encode('utf-8')
sign_digest = hmac.new(base64_decoded_secret_key, content_to_hash , hashlib.sha512).digest()
return base64.b64encode(sign_digest).decode('utf-8')
When I try this signature method with requestPath = "/v1/user/balance" (which required to be authentificated), it fail without error...
Does any one used with both java and python may help me to convert this signature method to python ?
This code will work for GET:
import time,requests
import hashlib,hmac,base64
api_key = "my api key"
api_secret = "my api secret"
defaut_encoding = "utf8"
uri = "https://api.iconomi.com"
requestPath = "/v1/user/balance"
api_url_target = uri+requestPath # https://api.iconomi.com/v1/user/balance
method="GET"
body=""
icn_timestamp = int(1000.*time.time())
message = (str(icn_timestamp) + method.upper() + requestPath + body).encode(defaut_encoding)
signature_digest = hmac.new(api_secret.encode(defaut_encoding), message, hashlib.sha512).digest() #here digest is byte
b64_signature_digest= base64.b64encode(signature_digest).decode(defaut_encoding)
headers_sign= {
"ICN-API-KEY":api_key,
"ICN-SIGN":b64_signature_digest,
"ICN-TIMESTAMP":str(icn_timestamp)
}
s=requests.session()
res = s.get(api_url_target,headers=headers_sign,timeout=3, verify=True).content
print (res)
Update for #Karl comment, this code will work for POST:
import time,requests
import hashlib,hmac,base64,json
api_key = "my api key"
api_secret = "my api secret"
ticker = "my ticker strategy"
defaut_encoding = "utf8"
uri = "https://api.iconomi.com"
requestPath = "/v1/strategies/"+ticker+"/structure"
api_url_target = uri+requestPath # https://api.iconomi.com/v1/strategies/{my ticker strategy}/structure
method="POST"
body="{'ticker': ticker, 'values': [{'rebalancedWeight': 1., 'targetWeight':1., 'assetTicker': 'XMR', 'assetName': 'Monero', 'assetCategory': 'Privacy'}]}"
icn_timestamp = int(1000.*time.time())
message = (str(icn_timestamp) + method.upper() + requestPath + body).encode(defaut_encoding)
signature_digest = hmac.new(api_secret.encode(defaut_encoding), message, hashlib.sha512).digest() #here digest is byte
b64_signature_digest= base64.b64encode(signature_digest).decode(defaut_encoding)
headers_sign= {
"ICN-API-KEY":api_key,
"ICN-SIGN":b64_signature_digest,
"ICN-TIMESTAMP":str(icn_timestamp)
}
s=requests.session()
res = s.post(api_url_target,headers=headers_sign,json = json.loads(body), timeout=3, verify=True).content
print (res)
I get Successful status code for my POST requests , Login is working fine , but the SMS is not sent
I have gone through all codes on internet, most of them are out-dated, as the site has changed its code.
import requests as req
def login_way2sms():
with req.Session() as mySession:
url = 'http://www.way2sms.com/re-login'
home_url = 'http://www.way2sms.com/'
mobile = [your registered mobile number]
password = [your password]
headers = dict(Referrer="http://www.way2sms.com/")
before = mySession.get(home_url)
login_data = dict(mobileNo=mobile, password=password, CatType='', redirectPage='', pid='')
mySession.post(url, data=login_data, headers=headers)
after = mySession.get(home_url)
return mySession
def send_msg(mysession): #saw sendsms-toss in Inspect under Network tab
url = 'http://www.way2sms.com/smstoss'
home_url = 'http://www.way2sms.com/'
sms_url = 'http://www.way2sms.com/send-sms'
group_contact_url = 'http://www.way2sms.com/GroupContacts'
web_msg_count_url = 'http://www.way2sms.com/CheckWebMsgCount'
headers = dict(Referrer="http://www.way2sms.com/send-sms")
before = mysession.get(home_url)
token = '2B7CF7C9D2F14935795B08DAD1729ACF'
message = 'How to make this work?'
mobile = '[a valid phone number]'
ssaction = 'undefined'
senderid = 'WAYSMS'
msg_data = dict(Token=token, message=message, toMobile=mobile, ssaction=ssaction, senderId=senderid)
mysession.post(url, data=msg_data, headers=headers)
after = mysession.get(home_url)
mysession.post(group_contact_url, headers=headers)
group_contacts = mysession.get(sms_url)
mysession.post(web_msg_count_url, headers=headers)
web_msg_count = mysession.get(sms_url)
# last 2 POST requests send after clicking the Send Msg button
def main():
login_way2sms() #login using username and password
send_msg(currsession) #send sms
main()
I finally got it right , Thanks for replying. We can do it without using the apikey and secret keys as well, Here take a look at this. And init is just another script where constant urls and login is defined, nothing much there.
import requests as req
import init
def login_way2sms(credential):
with req.Session() as mySession:
mobile = credential.username
password = credential.password
headers = dict(Referrer="http://www.way2sms.com/")
login_data = dict(mobileNo=mobile, password=password, CatType='', redirectPage='', pid='')
mySession.post(init.login_url, data=login_data, headers=headers)
return mySession
def get_token(mysession):
cookies = mysession.cookies['JSESSIONID']
token = cookies[4:]
return token
def send_msg(mysession, token):
"""
:rtype: req.Session()
"""
headers = dict(Referrer="http://www.way2sms.com/send-sms")
message = 'Hi, I am Upgraded a little!!!'
mobile = '[valid phone]'
msg_data = dict(Token=token, message=message, toMobile=mobile, ssaction=init.ssaction, senderId=init.senderid)
mysession.post(init.sms_url, data=msg_data, headers=headers)
def main():
credential = init.enter_credentials()
currsession = login_way2sms(credential)
reply = currsession.get(init.home_url)
page_content: str = str(reply.content)
if (reply.status_code == 200) and (page_content.find('send-sms', 10, 200) != -1):
print("Login Successful!\n")
else:
print("Login Failed , Try again\n")
credential = init.enter_credentials()
currsession = login_way2sms(credential)
token = get_token(currsession)
send_msg(currsession, token)
main()
The following method and code worked for me after creating a free account at way2sms (I hope you already did it). Then click on API tab then campaign at left. Then create test API and Secret Key (free with 25 message limit). Then use the following code--
import requests
import json
URL = 'http://www.way2sms.com/api/v1/sendCampaign'
# get request
def sendPostRequest(reqUrl, apiKey, secretKey, useType, phoneNo, senderId, textMessage):
req_params = {
'apikey':'your_apiKey',
'secret':'your_secretKey',
'usetype':'stage'
'phone': 'receiving_phone_number',
'message':'The textMessage I want to send',
'senderid':'Your Name'
}
return requests.post(reqUrl, req_params)
# get response
response = sendPostRequest(URL, 'provided-api-key', 'provided-secret', 'prod/stage', 'valid-to-mobile', 'active-sender-id', 'message-text' )
"""
Note:-
you must provide apikey, secretkey, usetype, mobile, senderid and message values
and then requst to api
"""
# print response if you want
print response.text
Just fill the fields and run in python 2.7. Working perfectly on any Indian number.
I am developing a Facebook messenger bot using Flask and want to utilize the Twitter API for a feature of the bot. I am therefore using Tweepy to simplify the process. However, I am unable to get OAuth working in my program. I believe the source of the issue is that the request token is not saving or being received properly, because when I do auth.get_access_token I get an error - either "OAuth has no object request_token" or "string indices must be integers" depending on how I'm saving the OAuth handler instance. Sometimes, it also fails to get the request_token and doesn't send the link back to the user. I tried to check this by printing out the request token in my oauth_verification() function and it was blank. I've been stuck on this for a few hours, and any help would be greatly appreciated. My code is as follows:
PAT = '[pat here]'
auth = tweepy.OAuthHandler('[key here]', '[secret here]')
auth_req_token = ''
#app.route('/', methods=['GET'])
def handle_verification():
print("Handling Verification.")
if request.args.get('hub.verify_token', '') == '[verification token]':
print("Verification successful!")
return request.args.get('hub.challenge', '')
else:
print("Verification failed!")
return 'Error, wrong validation token'
#app.route('/', methods=['POST'])
def handle_messages():
print("Handling Messages")
payload = request.get_data()
print(payload)
for sender, message in messaging_events(payload):
print("Incoming from %s: %s" % (sender, message))
parse_message(PAT, sender, message)
return "ok"
def parse_message(PAT, sender, message):
original_message = message
message = str(message.decode('unicode_escape'))
message = message.replace("?", "")
if message.isdigit():
oauth_verification(PAT, sender, original_message.decode("utf-8"))
else:
split_msg = message.split(" ")
print(split_msg)
try:
platform = split_msg[split_msg.index("followers") - 1]
does_location = split_msg.index("does") + 1
have_location = split_msg.index("have")
name = split_msg[does_location:have_location]
name = " ".join(name)
print("Name: " +name + " Platform: " + platform)
init_oauth(name, PAT, sender)
except ValueError:
reply_error(PAT, sender)
def init_oauth(name, token, recipient):
try:
redirect_url = auth.get_authorization_url()
auth_req_token = auth.request_token
r = requests.post("https://graph.facebook.com/v2.6/me/messages",
params={"access_token": token},
data=json.dumps({
"recipient": {"id": recipient},
"message": {"text": "Please login to Twitter, and reply with your verification code " + redirect_url}
}),
headers={'Content-type': 'application/json'})
except tweepy.TweepError:
print('Error! Failed to get request token.')
def oauth_verification(token, recipient, verifier):
auth.request_token = auth_req_token
try:
auth.get_access_token(verifier) # issue is here - I am able to get authentication link, but not able to get access token
api = tweepy.API(auth)
r = requests.post("https://graph.facebook.com/v2.6/me/messages",
params={"access_token": token},
data=json.dumps({
"recipient": {"id": recipient},
"message": {"text": "Successfully authenticated Twitter!"}
}),
headers={'Content-type': 'application/json'})
except tweepy.TweepError:
print('Error! Failed to get access token.')
As auth_req_token is a global variable, you need to use the global keyword to change its value in init_oauth:
def init_oauth(name, token, recipient):
global auth_req_token
try:
redirect_url = auth.get_authorization_url()
auth_req_token = auth.request_token
# ...
I'm having an awfully hard time with Yahoo's authentication/authorization. I've enabled BOSS in my account, set up a payment method, and now I'm trying to run a search using some python code:
import urllib2
import oauth2 as oauth
import time
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
def oauth_request(url, params, method="GET"):
params['oauth_version'] = "1.0",
params['oauth_nonce'] = oauth.generate_nonce(),
params['oauth_timestamp'] = int(time.time())
consumer = oauth.Consumer(key=OAUTH_CONSUMER_KEY,
secret=OAUTH_CONSUMER_SECRET)
params['oauth_consumer_key'] = consumer.key
req = oauth.Request(method=method, url=url, parameters=params)
req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, None)
return req
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web"
req = oauth_request(url, params={"q": "cats dogs"})
req_url = req.to_url()
print req_url
result = urllib2.urlopen(req_url)
I keep getting a urllib2.HTTPError: HTTP Error 401: Unauthorized exception. I can't figure out whether there's something wrong with my key, or the method of signing, or if I'm somehow tampering with my data after signing, or what the deal is. Anyone have suggestions?
I made some small changes to make your example work. See code for comments.
import urllib2
import oauth2 as oauth
import time
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
def oauth_request(url, params, method="GET"):
# Removed trailing commas here - they make a difference.
params['oauth_version'] = "1.0" #,
params['oauth_nonce'] = oauth.generate_nonce() #,
params['oauth_timestamp'] = int(time.time())
consumer = oauth.Consumer(key=OAUTH_CONSUMER_KEY,
secret=OAUTH_CONSUMER_SECRET)
params['oauth_consumer_key'] = consumer.key
req = oauth.Request(method=method, url=url, parameters=params)
req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, None)
return req
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web"
req = oauth_request(url, params={"q": "cats dogs"})
# This one is a bit nasty. Apparently the BOSS API does not like
# "+" in its URLs so you have to replace "%20" manually.
# Not sure if the API should be expected to accept either.
# Not sure why to_url does not just return %20 instead...
# Also, oauth2.Request seems to store parameters as unicode and forget
# to encode to utf8 prior to percentage encoding them in its to_url
# method. However, it's handled correctly for generating signatures.
# to_url fails when query parameters contain non-ASCII characters. To
# work around, manually utf8 encode the request parameters.
req['q'] = req['q'].encode('utf8')
req_url = req.to_url().replace('+', '%20')
print req_url
result = urllib2.urlopen(req_url)
Here is a Python code snippet that works for me against Yahoo! BOSS:
import httplib2
import oauth2
import time
OAUTH_CONSUMER_KEY = "Blah"
OAUTH_CONSUMER_SECRET = "Blah"
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web?q=cats%20dogs"
consumer = oauth2.Consumer(key=OAUTH_CONSUMER_KEY,secret=OAUTH_CONSUMER_SECRET)
params = {
'oauth_version': '1.0',
'oauth_nonce': oauth2.generate_nonce(),
'oauth_timestamp': int(time.time()),
}
oauth_request = oauth2.Request(method='GET', url=url, parameters=params)
oauth_request.sign_request(oauth2.SignatureMethod_HMAC_SHA1(), consumer, None)
oauth_header=oauth_request.to_header(realm='yahooapis.com')
# Get search results
http = httplib2.Http()
resp, content = http.request(url, 'GET', headers=oauth_header)
print resp
print content
Im using an Authenticate Header to submit the OAuth signature.
So I decided to ditch Python and try Perl, and it Just Worked. Here's a minimal code sample:
use strict;
use Net::OAuth;
use LWP::UserAgent;
my $CC_KEY = "blahblahblah";
my $CC_SECRET = "blah";
my $url = 'http://yboss.yahooapis.com/ysearch/web';
print make_request($url, {q => "cat dog", format => "xml", count => 5});
sub make_request {
my ($url, $args) = #_;
my $request = Net::OAuth->request("request token")
->new(
consumer_key => $CC_KEY,
consumer_secret => $CC_SECRET,
request_url => $url,
request_method => 'GET',
signature_method => 'HMAC-SHA1',
timestamp => time,
nonce => int(rand 10**6),
callback => 'oob',
extra_params => $args,
protocol_version => Net::OAuth::PROTOCOL_VERSION_1_0A,
);
$request->sign;
my $res = LWP::UserAgent->new(env_proxy=>1)->get($request->to_url);
return $res->content if $res->is_success;
die $res->status_line;
}
Here's another solution, this time back in python-land. This was put together by Tom De Smedt, author of the Pattern web-mining kit.
I'll communicate with the author of python-oauth2 to see if it can be fixed.
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
import urllib
import hmac
import time
import random
import base64
try:
from hashlib import sha1
from hashlib import md5
except:
import sha as sha1
import md5; md5=md5.new
def hmac_sha1(key, text):
return hmac.new(key, text, sha1).digest()
def oauth_nonce(length=40):
h = "".join([str(random.randint(0, 9)) for i in range(length)])
h = md5(str(time.time()) + h).hexdigest()
return h
def oauth_timestamp():
return str(int(time.time()))
def oauth_encode(s):
return urllib.quote(s, "~")
def oauth_signature(url, data={}, method="get", secret="", token=""):
# Signature base string: http://tools.ietf.org/html/rfc5849#section-3.4.1
base = oauth_encode(method.upper()) + "&"
base += oauth_encode(url.rstrip("?")) + "&"
base += oauth_encode("&".join(["%s=%s" % (k, v) for k, v in sorted(data.items())]))
# HMAC-SHA1 signature algorithm: http://tools.ietf.org/html/rfc5849#section-3.4.2
signature = hmac_sha1(oauth_encode(secret) + "&" + token, base)
signature = base64.b64encode(signature)
return signature
q = "cat"
url = "http://yboss.yahooapis.com/ysearch/" + "web" # web | images | news
data = {
"q": q,
"start": 0,
"count": 50, # 35 for images
"format": "xml",
"oauth_version": "1.0",
"oauth_nonce" : oauth_nonce(),
"oauth_timestamp" : oauth_timestamp(),
"oauth_consumer_key" : OAUTH_CONSUMER_KEY,
"oauth_signature_method" : "HMAC-SHA1",
}
data["oauth_signature"] = oauth_signature(url, data, secret=OAUTH_CONSUMER_SECRET)
complete_url = url + "?" + urllib.urlencode(data)
response = urllib.urlopen(complete_url)
print response.read()
Here is sample code to access Yahoo! BOSS API v2 using with python-oauth as oauth liberary.
OAUTH_CONSUMER_KEY = "<oauth consumer key>"
OAUTH_CONSUMER_SECRET = "<oauth consumer secret>"
URL = "http://yboss.yahooapis.com/ysearch/web"
import urllib
import oauth.oauth as oauth
data = {
"q": "yahoo boss search",
"start":0,
"count":2,
"format":"json"
}
consumer = oauth.OAuthConsumer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET)
signature_method_plaintext = oauth.OAuthSignatureMethod_PLAINTEXT()
signature_method_hmac_sha1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
oauth_request = oauth.OAuthRequest.from_consumer_and_token(consumer, token=None, http_method='GET', http_url=URL, parameters=data)
oauth_request.sign_request(signature_method_hmac_sha1, consumer, "")
complete_url = oauth_request.to_url()
response = urllib.urlopen(complete_url)
print "REQUEST URL => %s" % complete_url
print ""
print "RESPONSE =>"
print response.read()
I stepped into the urllib2.open code using the debugger, and found that the response has this header:
WWW-Authenticate: OAuth oauth_problem="version_rejected", realm="yahooapis.com"
So I guess I'm having some kind of version mismatch of OAuth.