21

I'm trying to convert the following working request in curl to a python request (using Requests).

curl --data 'query={"tags":["test1","test2"]}' http://www.test.com/match

(I've used a fake url but the command does work with the real url)

The receiving end (ran in Flask) does this:

@app.route("/match", methods=['POST'])
def tagmatch():
    query = json.loads(request.form['query'])
    tags = query.get('tags')
    # ... does stuff ...
    return json.dump(stuff)

In curl (7.30), ran on Mac OS X (10.9) the command above properly returns a JSON list that's filtered using the tag query.

My Python script is as follows, it returns a 400 Bad Request error.

import requests

payload = {"tags":["test1", "test2"]}
# also tried  payload = 'query={"tags":["test1","test2"]}'
url = 'http://www.test.com/match'

r = requests.post(url, data=payload)

if __name__=='__main__':
     print(r.text)
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
zalc
  • 213
  • 1
  • 2
  • 4
  • payload = {'query': '{"tags":["test1","test2"]}'} works, but flyer pointed me in the right direction. Thank you. I wasn't properly forming the python dict. – zalc Dec 09 '13 at 04:32

7 Answers7

40

There is an open source cURL to Python Requests conversion helper at https://curlconverter.com/. It isn't perfect, but helps out a lot of the time. Especially for converting Chrome "Copy as cURL" commands. There is also a node library if you need to do the conversions programmatically

screenshot of curlconverter.com converting the given command to Python

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
Gourneau
  • 12,660
  • 8
  • 42
  • 42
13

Your server is expecting JSON, but you aren't sending it. Try this:

import requests
import json

payload = {'query': json.dumps({"tags":["test1", "test2"]})}
url = 'http://www.test.com/match'

r = requests.post(url, data=payload)

if __name__=='__main__':
    print r.text
Lukasa
  • 14,599
  • 4
  • 32
  • 34
6

Save your life

A simpler approach would be:

  1. Open POSTMAN
  2. Click on the "import" tab on the upper left side.
  3. Select the Raw Text option and paste your cURL command.
  4. Hit import and you will have the command in your Postman builder!

Hope this helps!

credit: Onkaar Singh

MKRNaqeebi
  • 573
  • 10
  • 16
  • We need a solution to automate something, Postman is used only for inspecting or playing with APIs. My purpose is send 1000 of request from "Copy as Curl" and for that we need to automate this process. Save your life! – rohitcoder May 14 '20 at 14:08
6

Try to use uncurl library. It is pretty nice to do its job. I've tried it.

u = uncurl.parse(
        "curl -X GET 'https://mytesturl.com/' -H  'accept: application/json' -H  'Authorization: 1234567890'")
    print(u)

It prints,

requests.get("https://mytesturl.com/",
    headers={
        "Authorization": "1234567890",
        "accept": "application/json"
    },
    cookies={},
)
3

try this:

https://github.com/spulec/uncurl

import uncurl

print uncurl.parse("curl 'https://pypi.python.org/pypi/uncurl' -H 
'Accept-Encoding: gzip,deflate,sdch'")
Pegasus
  • 1,398
  • 15
  • 20
2

I wrote an HTTP client plugin for Sublime Text called Requester, and one of its features is to convert calls to cURL to Requests, and vice versa.

If you're using Sublime Text this is probably your fastest, easiest option. If not, here's the code that actually handles the conversion from cURL to Requests. It's based uncurl, but with various improvements and bug fixes.

import argparse
import json
try:
    from urllib.parse import urlencode, parse_qsl
except ImportError:  # works for Python 2 and 3
    from urllib import urlencode
    from urlparse import parse_qsl


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('command')
    parser.add_argument('url')
    parser.add_argument('-X', '--request', default=None)
    parser.add_argument('-d', '--data', default=None)
    parser.add_argument('-G', '--get', action='store_true', default=False)
    parser.add_argument('-b', '--cookie', default=None)
    parser.add_argument('-H', '--header', action='append', default=[])
    parser.add_argument('-A', '--user-agent', default=None)
    parser.add_argument('--data-binary', default=None)
    parser.add_argument('--compressed', action='store_true')

    parsed_args = parser.parse_args()

    method = 'get'
    if parsed_args.request:
        method = parsed_args.request

    base_indent = ' ' * 4
    post_data = parsed_args.data or parsed_args.data_binary or ''
    if post_data:
        if not parsed_args.request:
            method = 'post'
        try:
            post_data = json.loads(post_data)
        except ValueError:
            try:
                post_data = dict(parse_qsl(post_data))
            except:
                pass

    cookies_dict = {}

    if parsed_args.cookie:
        cookies = parsed_args.cookie.split(';')
        for cookie in cookies:
            key, value = cookie.strip().split('=')
            cookies_dict[key] = value

    data_arg = 'data'
    headers_dict = {}
    for header in parsed_args.header:
        key, value = header.split(':', 1)
        if key.lower().strip() == 'content-type' and value.lower().strip() == 'application/json':
            data_arg = 'json'

        if key.lower() == 'cookie':
            cookies = value.split(';')
            for cookie in cookies:
                key, value = cookie.strip().split('=')
                cookies_dict[key] = value
        else:
            headers_dict[key] = value.strip()
    if parsed_args.user_agent:
        headers_dict['User-Agent'] = parsed_args.user_agent

    qs = ''
    if parsed_args.get:
        method = 'get'
        try:
            qs = '?{}'.format(urlencode(post_data))
        except:
            qs = '?{}'.format(str(post_data))
        print(post_data)
        post_data = {}

    result = """requests.{method}('{url}{qs}',{data}\n{headers},\n{cookies},\n)""".format(
        method=method.lower(),
        url=parsed_args.url,
        qs=qs,
        data='\n{}{}={},'.format(base_indent, data_arg, post_data) if post_data else '',
        headers='{}headers={}'.format(base_indent, headers_dict),
        cookies='{}cookies={}'.format(base_indent, cookies_dict),
    )
    print(result)

You could make a script with this code, e.g. curl_to_request.py, and call this script from the command line like so. It will work for both Python 2 and Python 3.

python curl_to_request.py curl -X POST -d 'key2=value2&key1=value1' 'http://httpbin.org/post'

python curl_to_request.py curl -X POST -H 'Content-Type: application/json' -d '{"key2": "value2", "key1": "value1"}' 'http://httpbin.org/post'

python curl_to_request.py curl -X POST -H 'Content-Type: application/json' -d '[1, 2, 3]' 'http://httpbin.org/post'

python curl_to_request.py curl -X POST -H 'Content-Type: application/json' -d '{"name": "Jimbo", "age": 35, "married": false, "hobbies": ["wiki", "pedia"]}' 'http://httpbin.org/post'

python curl_to_request.py curl -X GET 'http://httpbin.org/get?key2=value2&key1=value1'

python curl_to_request.py curl -X GET -H 'key1: value1' -H 'key2: value2' 'http://httpbin.org/headers'

python curl_to_request.py curl -X GET -b 'key1=value1;key2=value2' 'http://httpbin.org/cookies'
kylebebak
  • 483
  • 5
  • 11
  • I just wanted to say thank you for this example. It's proven to be a very useful technique for converting other commands plus options to Python. – David Feb 19 '19 at 04:17
0

From your code using requests and in Flask, it seems like you don't post the right data format. The payload should be like this:

payload = {'query': {'tags': ['test1', 'test2']},}

This seems not normal as post data when using requests.post(). So if you have posted the html form here, it may have been more clear to solve the problem.
Here is another similar question: Using Python Requests to pass through a login/password

Community
  • 1
  • 1
flyer
  • 9,280
  • 11
  • 46
  • 62