I am trying to log into the Robinhood API using:
import requests
def login():
u = "myusername"
p = "mypassword"
url = "https://api.robinhood.com/api-token-auth/"
r = requests.get(url, username=u, password=p)
#r = requests.get(url)
return r.text
print login()
I have a way to do it in Curl which is:
'curl -v https://api.robinhood.com/api-token-auth/ -H "Accept: application/json" -d "username='+username+'&password='+password+'"'
When using Python-requests I get the following error:
Traceback (most recent call last):
File "rhood.py", line 12, in <module>
print login()
File "rhood.py", line 8, in login
r = requests.get(url, username=u, password=p)
File "C:\Python27\Lib\site-packages\requests\api.py", line 75, in get
return request('get', url, params=params, **kwargs)
File "C:\Python27\Lib\site-packages\requests\api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
TypeError: request() got an unexpected keyword argument 'username'
You need to create a dictionary containing the parameters you wish to send with the request (see data in the code below). Then include the dictionary in your request by using the json parameter.
Also note, Robinhood API documentation seems to suggest a POST request is required, as opposed to a GET request. Therefore, the code below uses requests.post(...).
import requests
def login():
u = "myusername"
p = "mypassword"
url = "https://api.robinhood.com/api-token-auth/"
data = {"username": u, "password": p}
r = requests.post(url, json=data)
return r.text
print login()
Check out the authentication modules in the requests library
http://docs.python-requests.org/en/master/user/authentication/
Related
I am attempting to authenticate with Microsoft Defender for Endpoint's API service by following this learn article:
https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/run-advanced-query-sample-python?view=o365-worldwide#get-token
I typically use the "request" library for REST calls, so I didn't follow the above code snippet exactly. When running my version of the above code:
import json
import requests
MDE_CLIENT_ID = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX'
MDE_CLIENT_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
TENANT_ID = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX'
AUTHORITY = 'https://login.microsoftonline.com/'
MDE_URI = 'https://api.securitycenter.microsoft.com'
class RESTError(Exception):
def __init__(self, status_code, message):
self.status_code = status_code
self.message = str(self.status_code) + ' ' + json.dumps(message)
super().__init__(self.message)
def authenticate_mde():
headers = {
'content-type': 'application/x-www-form-urlencoded'
}
body = {
'resource': MDE_URI,
'client_id': MDE_CLIENT_ID,
'client_secret': MDE_CLIENT_SECRET,
'grant_type': 'client_credentials'
}
response = requests.post(AUTHORITY + TENANT_ID + '/oauth2/token', data = json.dumps(body), headers = headers)
if (response.status_code < 200 or response.status_code > 299):
raise RESTError(response.status_code, response.json())
return response.json()['access_token']
def main():
token = authenticate_mde()
print(token)
if (__name__ == '__main__'):
main()
When I run this code I receive a 400 error back from the authentication service complaining about a missing body parameter 'grant_type'. However, as you can see in the code, I clearly have that included in the same fashion as the code snippet from MSFT.
Traceback (most recent call last):
File "C:\Users\24724\Documents\code\python\scripts\mde-executor.py", line 42, in <module>
main()
File "C:\Users\24724\Documents\code\python\scripts\mde-executor.py", line 38, in main
token = authenticate_mde()
File "C:\Users\24724\Documents\code\python\scripts\mde-executor.py", line 32, in authenticate_mde
raise RESTError(response.status_code, response.json())
__main__.RESTError: 400 {"error": "invalid_request", "error_description": "AADSTS900144: The request body must contain the following parameter: 'grant_type'.\r\nTrace ID: e4d0d06e-aae6-4b6d-80e2-2b3997f74302\r\nCorrelation ID: 5788089d-f94e-4e9a-8667-d6e36c183af8\r\nTimestamp: 2023-01-06 17:00:23Z", "error_codes": [900144], "timestamp": "2023-01-06 17:00:23Z", "trace_id": "e4d0d06e-aae6-4b6d-80e2-2b3997f74302", "correlation_id": "5788089d-f94e-4e9a-8667-d6e36c183af8", "error_uri": "https://login.microsoftonline.com/error?code=900144"}
I also tried copying MSFT's code snippet exactly and inserting my own global var info but receive the same error. I have tried moving the body to url parameters, headers, splitting it up between body, params, and headers. No luck. I have tried different content-types in the header as well and tried without any headers. None seems to work and I am stumped at this point.
I resolved the issue. Passing 'resource' into the body was apparently screwing it up, even though their python example here shows that:
import json
import urllib.request
import urllib.parse
tenantId = '00000000-0000-0000-0000-000000000000' # Paste your own tenant ID here
appId = '11111111-1111-1111-1111-111111111111' # Paste your own app ID here
appSecret = '22222222-2222-2222-2222-222222222222' # Paste your own app secret here
url = "https://login.microsoftonline.com/%s/oauth2/token" % (tenantId)
resourceAppIdUri = 'https://api.securitycenter.microsoft.com'
body = {
'resource' : resourceAppIdUri,
'client_id' : appId,
'client_secret' : appSecret,
'grant_type' : 'client_credentials'
}
data = urllib.parse.urlencode(body).encode("utf-8")
req = urllib.request.Request(url, data)
response = urllib.request.urlopen(req)
jsonResponse = json.loads(response.read())
aadToken = jsonResponse["access_token"]
https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/run-advanced-query-sample-python?view=o365-worldwide#get-token
Following the example they give for cURL here and using the 'scope' parameter instead fixed it.
curl -i -X POST -H "Content-Type:application/x-www-form-urlencoded" -d "grant_type=client_credentials" -d "client_id=%CLIENT_ID%" -d "scope=https://securitycenter.onmicrosoft.com/windowsatpservice/.default" -d "client_secret=%CLIENT_SECRET%" "https://login.microsoftonline.com/%TENANT_ID%/oauth2/v2.0/token" -k
https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/exposed-apis-create-app-webapp?view=o365-worldwide#use-curl
I am trying to send a turtle file via a Python script using REST api to the local repository but the System is returning the following error
MALFORMED DATA: Illegal subject value: "-"^^http://www.w3.org/2001/XMLSchema#integer [line 1]
400
The used code is as follows:
import requests
url = 'http://localhost:7200/repositories/metaphactory1/statements'
with open("graph-29.ttl", "rb") as ttl_file:
file_dict = {"graph-29.ttl" : ttl_file}
headers = {
"Content-type": "application/x-turtle;charset=UTF-8",
}
r = requests.post(url, files=file_dict, headers=headers)
print(r.text)
print(r.status_code)
The same file when tried with a Curl command is working fine:
curl -X POST -H "Content-Type: application/x-turtle" -T graph-29.ttl 'http://localhost:7200/repositories/metaphactory1/statements'
Any idea regarding this issue is welcome
I think your problem come from the way you pass your file to the post request.
You should try using the data parameter of the post request. For example:
import requests
url = 'http://localhost:7200/repositories/metaphactory1/statements'
file_path = '/path/to/your/file/graph-29.ttl'
graph_name = 'http://graph-29'
headers = {
'Content-type': 'application/x-turtle',
}
params = {'graph': graph_name} #optional
response = requests.post(url, headers=headers, params=params, data=open(file_path,'r', encoding='utf-8').read())
I am trying to receive a file in python flask endpoint via post request, and then send it to another endpoint. I receive a file on my API but I do not know how to wrap it for the next request.
The code looks like this
#app.route('/file', methods=['POST'])
def get_task_file():
response_obj = {}
if 'file' not in request.files:
abort(400)
print(request.files["file"].filename)
# TEXT EXTRACT
url1 = 'http://localhost:5001/text/api'
headers = {'Content-type': 'multipart/form-data'}
print(type(request.files['file']))
r1 = requests.request("POST", url1, files={'file':request.files['file']}, headers=headers)
print(r1.text)
Right now the file type is <class 'werkzeug.datastructures.FileStorage'> and I am getting 400 errors. I just want to add that the logic on the second API is similar, should I change it?
I got code:400 as return or it shows the file I upload is empty, I found requests in flask is a little bit tricky.
change this
r1 = requests.request("POST", url1, files={'file':request.files['file']}, headers=headers)
into:
file = request.files['file']
r1 = requests.post(url1, files={'file':(file.filename, file.stream, file.content_type, file.headers)})
I have this minimally complete, verifiable example Chalice application:
from chalice import Chalice, Response
from urllib.request import Request, urlopen
from urllib.parse import unquote
import io
app = Chalice(app_name='photo')
app.api.binary_types =['*/*']
#app.route('/get-photo/{url}/{maxWidth}/{maxHeight}', methods=['GET'])
def getPhoto(url, maxWidth, maxHeight):
return Response(
load(unquote(url), int(maxWidth), int(maxHeight)),
headers={ 'Content-Type': 'image/jpeg' },
status_code=200)
def load(url, maxWidth, maxHeight):
print(url)
req = Request(url)
req.add_header('accept', 'image/jpeg')
image = urlopen(req).read()
return thumbnail(image, maxWidth, maxHeight)
from PIL import Image
def thumbnail(image, maxWidth, maxHeight):
im = Image.open(io.BytesIO(image))
im.thumbnail((maxWidth,maxHeight), Image.ANTIALIAS)
with io.BytesIO() as output:
im.save(output, format="JPEG")
return output.getvalue()
#app.route('/echo', methods=['POST'])
def preload():
# MCVE
return Response(app.current_request.json_body, status_code=200)
As it stands, the /get-photo route works fine, but the /echo endpoint fails when invoked with curl -H "Content-Type: application/json" -X POST -d '{"test":1}' https://...
[ERROR] ValueError: Expected bytes type for body with binary Content-Type. Got <class 'str'> type body instead.
Traceback (most recent call last):
File "/var/task/chalice/app.py", line 836, in __call__
response = response.to_dict(self.api.binary_types)
File "/var/task/chalice/app.py", line 375, in to_dict
self._b64encode_body_if_needed(response, binary_types)
File "/var/task/chalice/app.py", line 392, in _b64encode_body_if_needed
body = self._base64encode(body)
File "/var/task/chalice/app.py", line 400, in _base64encode
% type(data))
If I remove the app.api.binary_types =['*/*'], then the /echo works fine but I run instead into the issue described in Chalice Framework: Request did not specify an Accept header with image/jpeg
How can I get both of these routes working in the same application?
Fixed by changing the last line to
return Response(json.dumps(app.current_request.json_body).encode('utf-8'), status_code=200)
UPDATE
This worked for a while until I ran into additional issues. Then I ended up splitting the application into two based on the return type.
I'm having a similar issue to this recently answered question: Authenticate & Embed Tableau Rest API using python 2.7
I'm using the same code, but getting a different error. Confirmed that I am calling the correct API version for my Tableau server version.
from urllib2 import urlopen, Request
import xml.etree.ElementTree as ET # for parsing XML responses
server_name = "http://dashboard.myorg.org"
user_name = "abc"
password = "abc"
site_url_id = ""
signin_url = "{server}/api/2.4/auth/signin".format(server=server_name)
request_xml = ET.Element('tsRequest')
credentials = ET.SubElement(request_xml, 'credentials',
name=user_name, password=password)
site_element = ET.SubElement(credentials, 'site',
contentUrl=site_url_id)
request_data = ET.tostring(request_xml)
req = Request(signin_url, data=request_data)
req = urlopen(req)
server_response = req.read
response_xml = ET.fromstring(server_response)
token = response_xml.find('.//t:credentials',
namespaces={'t': "http://tableau.com/api"}).attrib['token']
site_id = response_xml.find('.//t:site',
namespaces={'t': "http://tableau.com/api"}).attrib['id']
print('Sign in successful!')
print('/tToken: {token}'.format(token=token))
print('/tSite ID: {site_id}'.format(site_id=site_id))
headers = {'X-tableau-auth': token}
signout_url = "{server}/api/2.4/auth/signout".format(server=server_name)
req = Request(signout_url, headers=headers, data=b'')
req = urlopen(req)
print('Sign out successful!')
My error is:
Traceback (most recent call last):
File "api_call.py", line 20, in <module>
response_xml = ET.fromstring(server_response)
File "C:\Python27\lib\xml\etree\ElementTree.py", line 1311, in XML
parser.feed(text)
File "C:\Python27\lib\xml\etree\ElementTree.py", line 1311, in feed
self._parser.Parse(data, 0)
TypeError: Parse() argument 1 must be string or read-only buffer, not instancemethod
As mentioned by #mzjn, issue is resolved by updating
server_response = req.read
to
server_response = req.read()