python urllib2 post request [duplicate] - python

This question already has answers here:
Is there any way to do HTTP PUT in python
(14 answers)
Closed 9 years ago.
Is it posisble to adapt this piece of code for make put request:
#!/usr/bin/python
import urllib2, base64, urllib
dir="https://domain.com/api/v1/"
use="one#two.com"
pas="123456"
base64string = base64.encodestring('%s:%s' % (use, pas)).replace('\n', '')
request = urllib2.Request(dir, headers={"Authorization" : "Basic %s" % base64string})
response = urllib2.urlopen(request).read()
print response
I try with this other code, but I think that it do a get request, isn't it?
#!/usr/bin/python
import urllib2, base64, urllib
dir="https://domain.com/api/v1/"
use="one#two.com"
pas="123456"
values = {
'list' :["201.22.44.12","8.7.6.0/24"]
}
data = urllib.urlencode(values)
base64string = base64.encodestring('%s:%s' % (use, pas)).replace('\n', '')
request = urllib2.Request(dir, data, headers={"Authorization" : "Basic %s" % base64string})
response = urllib2.urlopen(request).read()

I am not sure It will work or not for you but check this piece of code
You can encode a dict using urllib like this:
import urllib
import urllib2
url = 'http://example.com/...'
values = { 'productslug': 'bar','qty': 'bar' }
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
result = response.read()
print result

Related

How to download a file from password protected URL in python?

from urllib.request import Request, urlopen
import base64
import logging
import urllib
import urllib.request
import requests
def run(file_path,password):
if file_path:
try:
request = Request(file_path)
base64string = base64.b64encode('{}:{}'.format('', password).encode())
#input_file = tempfile.NamedTemporaryFile()
request.add_header("Authorization", "Basic %s" % base64string)
result = urlopen(request)
print (result)
ur = result.geturl()
a = ur.split("/")[:-1]
print (a)
', '.join(a[0:])
url = '/'.join(a)
print (url)
b = ur + "/download"
filename = "myfile"
input_file = requests.get(b,filename)
except Exception as e:
print(e)
l = run("https://cloud.abc.co.uk/s/523aX3O8B5uOWlP","test123")
print (l)
This is the URL https://cloud.abc.co.uk/s/523aX3O8B5uOWlP which is password protected.
I have tried using urllib and base64 for authentication.
This gives mehttps://cloud.abc.co.uk/s/523aX3O8B5uOWlP/authenticate.
This URL redirects to https://cloud.abc.co.uk/s/523aX3O8B5uOWlP/download from where the file can be downloaded.
request = Request(file_path)
base64string = base64.b64encode('{}{}'.format('',password).encode())
request.add_header("Authorization", "Basic %s" % base64string)
result = urlopen(request)
I want to download the file bypassing authentication credentials.
I had a same problem several weeks ago with JSON file. Tried something like this. Hope it works for you as well.
import urllib2
url = "url"
password_mgr = HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, url, 'username', 'password')
handler = HTTPBasicAuthHandler(password_mgr)
opener = build_opener(handler)
response = opener.open(url)

Trying to get json data from API, got TypeError

TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.
import json
import urllib.request as req
from urllib.parse import urlencode
url = "https://apiurl.example/search/"
payload = {"SearchString":"mysearch"}
response = req.urlopen(url, urlencode(payload))
data = response.read()
print(data.decode("utf-8"))
What am I doing wrong? There is nothing wrong with the url or "payload" as i tried it in the API's online interface. Before I added the urlencode and utf-8 decode I got an error saying: "TypeError: can't concat str to bytes". At some point it returned an empty list, but don't remember what I did then. Anyway it should return some data as mentioned. Thanks for your time.
I've never used requests that way. Here's an example of how I've done it, checking the result code and decoding the JSON if it was successful:
import json
import requests
action_url = "https://apiurl.example/search/"
# Prepare the headers
header_dict = {}
header_dict['Content-Type'] = 'application/json'
# make the URL request
result = requests.get(action_url, headers=header_dict)
status_code = result.status_code
if (status_code == requests.codes.ok):
records = json.loads(result.content)
print 'Success. Records:'
print records
else:
print 'ERROR. Status: {0}'.format(status_code)
print 'headers: {0}'.format(header_dict)
print 'action_url: {0}'.format(action_url)
# Show the error messages.
print result.text
I found out now.
import urllib.request
import urllib.parse
url = "https://apiurl.example/search"
search_input = input("Search ")
payload = {"SearchString":search_input}
params = urllib.parse.urlencode(payload)
params = params.encode('utf-8')
f = urllib.request.urlopen(url, params)
output = f.read()
print(output)

How to send a HTTP POST with Python 2.7

I'm trying to send a HTTP POST request with Python. I can get it to work with 3.0, but I couldn't find a good example on 2.7.
hdr = {"content-type": "application/json"}
payload= ("<html><body><h1>Sorry it's not Friday yet</h1> </body></html>")
r = requests.post("http://my-url/api/Html", json={"HTML": payload})
with open ('c:/temp/a.pdf', 'wb') as f:
b64str = json.loads(r.text)['BinaryData'] #base 64 string is in BinaryData attr
binStr = binascii.a2b_base64(b64str) #convert base64 string to binary
f.write(binStr)
The api takes a json in this format:
{
HTML : "a html string"
}
and returns a json in this format:
{
BinaryData: 'base64 encoded string'
}
In Python 2.x it should be like this
import json
import httplib
body =("<html><body><h1>Sorry it's not Friday yet</h1> </body></html>")
payload = {'HTML' : body}
hdr = {"content-type": "application/json"}
conn = httplib.HTTPConnection('my-url')
conn.request('POST', '/api/Html', json.dumps(payload), hdr)
response = conn.getresponse()
data = response.read() # same as r.text in 3.x
The standard way is with the urllib2 module
from urllib import urlencode
import urllib2
def http_post(url, data):
post = urlencode(data)
req = urllib2.Request(url, post)
response = urllib2.urlopen(req)
return response.read()

Equivalent Python code for the following Java http get requests

I am trying to convert the following Java code to Python. Not sure what I am doing wrong, but I end up with an internal server error 500 with python.
Is the "body" in httplib.httpConnection method equivalent to Java httpentity?
Any other thoughts on what could be wrong?
The input information I collect is correct for sure.
Any help will be really appreciated. I have tried several things, but end up with the same internal server error.
Java Code:
HttpEntity reqEntitiy = new StringEntity("loginTicket="+ticket);
HttpRequestBase request = reMethod.getRequest(uri, reqEntitiy);
request.addHeader("ticket", ticket);
HttpResponse response = httpclient.execute(request);
HttpEntity responseEntity = response.getEntity();
StatusLine responseStatus = response.getStatusLine();
Python code:
url = serverURL + "resources/slmservices/templates/"+templateId+"/options"
#Create the request
ticket = ticket.replace("'",'"')
headers = {"ticket":ticket}
print "ticket",ticket
reqEntity = "loginTicket="+ticket
body = "loginTicket="+ticket
url2 = urlparse.urlparse(serverURL)
h1 = httplib.HTTPConnection(url2.hostname,8580)
print "h1",h1
url3 = urlparse.urlparse(url)
print "url path",url3.path
ubody = {"loginTicket":ticket}
data = urllib.urlencode(ubody)
conn = h1.request("GET",url3.path,data,headers)
#conn = h1.request("GET",url3.path)
response = h1.getresponse()
lines = response.read()
print "response.status",response.status
print "response.reason",response.reason
You don't need to go this low level. Using urllib2 instead:
import urllib2
from urllib import urlencode
url = "{}resources/slmservices/templates/{}/options".format(
serverURL, templateId)
headers = {"ticket": ticket}
params = {"loginTicket": ticket}
url = '{}?{}'.format(url, urlencode(params))
request = urllib2.Request(url, headers=headers)
response = urllib2.urlopen(request)
print 'Status', response.getcode()
print 'Response data', response.read()
Note that the parameters are added to the URL to form URL query parameters.
You can do this simpler still by installing the requests library:
import requests
url = "{}resources/slmservices/templates/{}/options".format(
serverURL, templateId)
headers = {"ticket": ticket}
params = {"loginTicket": ticket}
response = requests.get(url, params=params, headers=headers)
print 'Status', response.status
print 'Response data', response.content # or response.text for Unicode
Here requests takes care of URL-encoding the URL query string parameters and adding it to the URL for you, just like Java does.

Not possible to set content-type to application/json using urllib2

This little baby:
import urllib2
import simplejson as json
opener = urllib2.build_opener()
opener.addheaders.append(('Content-Type', 'application/json'))
response = opener.open('http://localhost:8000',json.dumps({'a': 'b'}))
Produces the following request (as seen with ngrep):
sudo ngrep -q -d lo '^POST .* localhost:8000'
T 127.0.0.1:51668 -> 127.0.0.1:8000 [AP]
POST / HTTP/1.1..Accept-Encoding: identity..Content-Length: 10..Host: localhost:8000..Content-Type: application/x-www-form-urlencoded..Connection: close..User-Agent:
Python-urllib/2.7....{"a": "b"}
I do not want that Content-Type: application/x-www-form-urlencoded. I am explicitely saying that I want ('Content-Type', 'application/json')
What's going on here?!
If you want to set custom headers you should use a Request object:
import urllib2
import simplejson as json
opener = urllib2.build_opener()
req = urllib2.Request('http://localhost:8000', data=json.dumps({'a': 'b'}),
headers={'Content-Type': 'application/json'})
response = opener.open(req)
I got hit by the same stuff and came up with this little gem:
import urllib2
import simplejson as json
class ChangeTypeProcessor(BaseHandler):
def http_request(self, req):
req.unredirected_hdrs["Content-type"] = "application/json"
return req
opener = urllib2.build_opener()
self.opener.add_handler(ChangeTypeProcessor())
response = opener.open('http://localhost:8000',json.dumps({'a': 'b'}))
You just add a handler for HTTP requests that replaces the header that OpenerDirector previously added.
Python version:Python 2.7.15
I found that in urllib2.py:1145:
for name, value in self.parent.addheaders:
name = name.capitalize()
if not request.has_header(name):
request.add_unredirected_header(name, value)
...
def has_header(self, header_name):
return (header_name in self.headers or
header_name in self.unredirected_hdrs)
Otherwise,application/x-www-form-urlencoded has been in unredirected_hdrs and it won't be overwrite
You can solve like
import urllib.request
from http.cookiejar import CookieJar
import json
url = 'http://www.baidu.com'
req_dict = {'k': 'v'}
cj = CookieJar()
handler = urllib.request.HTTPCookieProcessor(cj)
opener = urllib.request.build_opener(handler)
req_json = json.dumps(req_dict)
req_post = req_json.encode('utf-8')
headers = {}
#headers['Content-Type'] = 'application/json'
req = urllib.request.Request(url=url, data=req_post, headers=headers)
#urllib.request.install_opener(opener)
#res = urllib.request.urlopen(req)
# or
res = opener.open(req)
res = res.read().decode('utf-8')
The problem is the capitalization of the Header name. You should use Content-type and not Content-Type.

Categories