beginner
beginner

Reputation: 183

How to execute Curl in Python

I'm trying to execute curl command in python script and couldn't pass a password with symbols.

import os;
os.system("curl -H 'Content-Type: text/xml;charset=UTF-8' -u 'appuser:appuser!@3pass' -i -v 'http://app.com/webservice/getUserData' -o userdata.xml")

And I get Access Denied message in return, the username and password are correct. I guess it is because of the special characters in the password. I have tried escape the characters like appuser\!\@3pass but didn't help.

Can anyone guide through this?

Upvotes: 1

Views: 1242

Answers (1)

Jean-François Fabre
Jean-François Fabre

Reputation: 140168

the command you're using cannot work because single quotes have no special meaning in Windows, they're passed literally to the curl program. So if you copied the command line from Linux (where it would work), that won't work here (spurious quotes are passed to curl for instance for the login/password field which recieves 'appuser and appuser!@3pass', also Content-Type: text/xml;charset=UTF-8 isn't protected at all and is understood as 2 separate arguments)

Simple test from the console:

K:\progs\cli>curl.exe -V
curl 7.50.3 (x86_64-pc-win32) libcurl/7.50.3 OpenSSL/1.0.2h nghttp2/1.14.1
Protocols: dict file ftp ftps gopher http https imap imaps ldap pop3 pop3s rtsp smb smbs smtp smtps
telnet tftp
Features: AsynchDNS IPv6 Largefile NTLM SSL HTTP2

(also works if I use "-V" with double quotes), but if I use simple quoting on the version arg I get:

K:\progs\cli>curl.exe '-V'
curl: (6) Could not resolve host: '-V'

As o11c commented, there's a python module to handle curl, you'd be better off with it.

For other cases when you can't do otherwise, using os.system is deprecated. Using subprocess.check_call for instance is better (python 3.5 has a unified run function):

  • return code checked, exception raised if error
  • ability to pass & quote arguments without doing it manually.

Let's fix your example:

subprocess.check_call(["curl","-H","Content-Type: text/xml;charset=UTF-8","-u",'appuser:appuser!@3pass',"-i","-v",'http://app.com/webservice/getUserData',"-o","userdata.xml"])

note that I purposedly mixed single & double quotes. Python doesn't care. And if there's a space in the argument, check_call mechanism manages to handle argument protection/quoting automatically.

when calling this script I get userdata.xml filled in like:

HTTP/1.1 301 Moved Permanently
Date: Fri, 15 Sep 2017 20:49:50 GMT
Server: Apache
Location: http://www.app.com/webservice/getUserData
Content-Type: text/html; charset=iso-8859-1
Transfer-Encoding: chunked

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://www.app.com/webservice/getUserData">here</a>.</p>
</body></html>

Upvotes: 4

Related Questions