How to Send an Xml Body Using Requests Library

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



Leave a reply



Submit