How can I send an xml body using requests library?
Just send xml bytes directly:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
import requests
xml = """<?xml version='1.0' encoding='utf-8'?>
<a>б</a>"""
headers = {'Content-Type': 'application/xml'} # set what your server accepts
print requests.post('http://httpbin.org/post', data=xml, headers=headers).text
Output
{
"origin": "x.x.x.x",
"files": {},
"form": {},
"url": "http://httpbin.org/post",
"args": {},
"headers": {
"Content-Length": "48",
"Accept-Encoding": "identity, deflate, compress, gzip",
"Connection": "keep-alive",
"Accept": "*/*",
"User-Agent": "python-requests/0.13.9 CPython/2.7.3 Linux/3.2.0-30-generic",
"Host": "httpbin.org",
"Content-Type": "application/xml"
},
"json": null,
"data": "<?xml version='1.0' encoding='utf-8'?>\n<a>\u0431</a>"
}
POST XML file with requests
You want to give the XML data from a file to requests.post
. But, this function will not open a file for you. It expects you to pass a file object to it, not a file name. You need to open the file before you call requests.post.
Try this:
import requests
# Set the name of the XML file.
xml_file = "xxx.xml"
headers = {'Content-Type':'text/xml'}
# Open the XML file.
with open(xml_file) as xml:
# Give the object representing the XML file to requests.post.
r = requests.post('https://example.com/serverxml.asp', data=xml, headers=headers)
print (r.content);
XML POST with Python Requests
Not a requests
method, but here's a real simple recipe using urllib2
from my codebase:
import urllib2
from elementtree import ElementTree
def post(url, data, contenttype):
request = urllib2.Request(url, data)
request.add_header('Content-Type', contenttype)
response = urllib2.urlopen(request)
return response.read()
def postxml(url, elem):
data = ElementTree.tostring(elem, encoding='UTF-8')
return post(url, data, 'text/xml')
I suspect what you're missing is the use of tostring
to convert the ElementTree
Element
that you named root
.
How do I send an XML ElementTree with Python Requests?
Use ElementTree.tostring() to create a string representation of the xml.
requests.post(
'http://localhost/wfc/XmlService',
data=ET.tostring(root),
headers=headers
)
send an XML file to rest API using python requests
Your API takes XML, not JSON. When you say, data = json.dumps(...)
, you are passing JSON to your API. This is the reason for your first error message -- 503 (API not able to get the right input).
requests.post()
takes ether a dictionary, a string, or a file-like object as its data=
parameter. When you do data = foo.readlines()
, you are passing in a list (which is neither a string nor a dictionary. This is the reason for your second error message -- "ValueError: too many values to unpack".
Without knowing your API, it is hard to guess what is correct. Having said that, try this:
filename = 'test.xml'
response = requests.post(api_url, data=open(filename).read())
Or, nearly equivalently, this:
filename = 'test.xml'
response = requests.post(api_url, data=open(filename))
How do I send an xml request and receive an xml response in Python?
You can use the urllib2
module that comes with Python to make requests to a URL that can consume this.
The Python website has a decent tutorial on how to use this module to fetch internet resources. The next step is learning how to generate/consume XML.
Related SO answers for those steps:
- Generating XML
- Consuming XML
Send XML file to REST API in Python3
Ok this took a lot of trial and error to figure out the right pieces here but I have finally figured it out. @Brennen Sprimont's answer was very helpful in understanding what cURL was doing.
As he pointed out - cURL was actually sending a full file and my initial requests were not.
My first clue came from a website I found which converts cURL commands to python - Link
When I put my cURL command into that site it returned this as part of the result:
data = {'reqxml' : (None, open(xml_file, 'rb'))}
(note: in my question I used 'x'but here I used 'data' for that variable)
The None
parameter was something missing from my original - also I am reading binary now.
My next major issue was they way I was passing the file - When I execute this from a browser the syntax is:
https://<ipaddress><port>/webconsole/APIController?reqxml=<Login></Login>
Here we can see the data defined by the attribute reqxml=
In cURL this looks like the following:
curl -k https://10.244.1.2:4444/webconsole/APIController? -F "reqxml=MYxml.xml"
There we can the attribute isn't actually passed in the url but with the file
The last mistake I was making was trying to pass the reqxml
attribute with the '=' sign. Unlike in cURL or through the browser, requests does not want that. In this case it wanted the values passed as a dictionary without the equals symbol.
Below is a small function which I used to test and works with Sophos XG v17
data_file = 'Myxml.xml'
ipaddress = '10.244.1.2'
def api_call(api_ip, xml_file):
api_url = r'https://{}:4444/webconsole/APIController?'.format(api_ip)
data = {'reqxml' : (None, open(xml_file, 'rb'))}
r = requests.post(api_url, files=data, verify=False)
print(r.text)
api_call(ipaddress, data_file)
Related Topics
Pandas: Valueerror: Cannot Convert Float Nan to Integer
Return SQL Table as JSON in Python
Ioerror: [Errno 22] Invalid Mode ('R') or Filename: 'C:\\Python27\Test.Txt'
Unbalanced Data and Weighted Cross Entropy
Django Rest Framework Post Nested Objects
Valueerror: Unknown Ms Compiler Version 1900
Python Argparse Conditionally Required Arguments
String Similarity Metrics in Python
Python Parsing Bracketed Blocks
Installing Numpy and Scipy on 64-Bit Windows (With Pip)
Argparse with Required Subparser
Convert Bytes to Floating Point Numbers
How to Remove Leading Whitespace in Python
Python Float to Int Conversion
How Does Python's "Super" Do the Right Thing