Есть ли способ сделать HTTP PUT в Python

220

Мне нужно загрузить некоторые данные на сервер, используя HTTP PUTв Python. Из моего краткого прочтения документации по urllib2, это только HTTP POST. Есть ли способ сделать HTTP PUTв Python?

Рори
источник

Ответы:

312

В прошлом я использовал различные библиотеки Python HTTP, и я остановился на « Запросах », как на моем любимом. Существующие библиотеки имели довольно удобные интерфейсы, но в итоге код может оказаться слишком длинным для простых операций. Базовый PUT в запросах выглядит так:

payload = {'username': 'bob', 'email': 'bob@bob.com'}
>>> r = requests.put("http://somedomain.org/endpoint", data=payload)

Затем вы можете проверить код статуса ответа с помощью:

r.status_code

или ответ с:

r.content

В Requests много синактического сахара и ярлыков, которые сделают вашу жизнь проще.

Джон Картер
источник
11
Несмотря на то, что приведенный выше код выглядит очень просто, не делайте вывод, что «запросы» никоим образом не хватает или недостаточно. Это чрезвычайно способный, только с очень аккуратным интерфейсом.
Джонатан Хартли
5
Интересно, сколько времени понадобится этому ответу, чтобы постепенно набирать голоса, пока он не станет новым ответом с наибольшим количеством голосов?
Джонатан Хартли
2
Вы не понимаете, насколько это здорово !!! Я боролся с грязной библиотекой Java! ... Я думаю, что я люблю тебя за указание на "Запросы"!
Shehaaz
3
Используйте json=payloadпараметр, если вы хотите, чтобы данные были в теле.
ManuelSchneid3r
1
Я хочу быстро указать, что этот интерфейс лучше, чем другой ответ, потому что это функциональное программирование. Зачем создавать объект, когда подойдет функция с простыми структурами данных в качестве параметров. Я хотел бы, чтобы другие библиотеки Python последовали его примеру.
Марк
242
import urllib2
opener = urllib2.build_opener(urllib2.HTTPHandler)
request = urllib2.Request('http://example.org', data='your_put_data')
request.add_header('Content-Type', 'your/contenttype')
request.get_method = lambda: 'PUT'
url = opener.open(request)
Флориан Бош
источник
4
Выглядит как грязный взлом, но, кажется, работает элегантно и полно
Рори
6
Было бы меньше взломать, если бы вы создали подкласс urllib2.Request вместо того, чтобы его патчить.
Джейсон Р. Кумбс
23
Этот ответ был блестящим, когда он был написан, но в настоящее время гораздо проще использовать пакет «запросов», см. Ответ Джона Картера. «Запросы» ни в коем случае не игрушка - они чрезвычайно способны.
Джонатан Хартли,
5
Этот ответ канонический, но устаревший. Пожалуйста, рассмотрите возможность использования requestsбиблиотеки.
jsalonen
13
Спасибо, я не хотел ничего использовать вне стандартной библиотеки Python, и это прекрасно работает. Я не совсем понимаю, почему urllib2 предназначен только для GET и POST в качестве стандарта, но это обходной путь. Можно ли повторно использовать urllib2.build_opener (urllib2.HTTPHandler) в нескольких вызовах?
WeNeedОтветы
46

Httplib кажется более чистым выбором.

import httplib
connection =  httplib.HTTPConnection('1.2.3.4:1234')
body_content = 'BODY CONTENT GOES HERE'
connection.request('PUT', '/url/path/to/put/to', body_content)
result = connection.getresponse()
# Now result.status and result.reason contains interesting stuff
Spooles
источник
Не используйте httplib, если вам (или любому из ваших потенциальных пользователей) нужна поддержка прокси. Смотрите эту статью для деталей.
Джейсон Р. Кумбс
Почему ты так говоришь? В вашей статье четко указано, что это работает. Посмотрите ответ Рольфа Вестера, он говорит, что urllib не работает, но httplib работает.
Spooles
httplib работает только тогда, когда пользователь явно подключается к прокси и изменяет запрос, чтобы включить полный URL-адрес в параметр GET. Причина сбоя urllib заключалась в том, что http_proxy не был установлен правильно. urllib использует httplib под сценами, но также обрабатывает перенаправления, прокси и т. д.
Джейсон Р. Кумбс
Хотя это решение будет работать, решение, использующее запросы, намного проще, элегантнее и, на мой взгляд, лучше.
tgrosinger
1
@tgrosinger Я согласен. Этот ответ был опубликован до того, как появились запросы. На данный момент единственный случай, когда это решение было бы лучше, это если бы была доступна только стандартная библиотека Python. В противном случае, я бы также рекомендовал использовать запросы.
Spooles
8

Вы должны взглянуть на модуль httplib . Он должен позволять вам делать любые запросы HTTP.

Джон Монтгомери
источник
Хорошее решение, тихий pythonic, но слишком близко к металлу и вовлекающее написание уже большого количества другого кода
Rory
8

Некоторое время назад мне нужно было решить эту проблему, чтобы я мог выступать в роли клиента для RESTful API. Я остановился на httplib2, потому что это позволило мне отправлять PUT и DELETE в дополнение к GET и POST. Httplib2 не является частью стандартной библиотеки, но вы можете легко получить ее из магазина сыров.

Майк
источник
2
httplib2 является пограничной заброшенной программой. Он содержит длинный список ошибок, которые не исправлены, несмотря на вклады сообщества (исправления). Я предлагаю дважды подумать, прежде чем использовать httplib2 в любых производственных средах.
Джейсон Р. Кумбс
8

Вы можете использовать библиотеку запросов, она намного упрощает вещи по сравнению с подходом urllib2. Сначала установите его из pip:

pip install requests

Подробнее об установке запросов .

Затем настройте поставленный запрос:

import requests
import json
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}

# Create your header as required
headers = {"content-type": "application/json", "Authorization": "<auth-key>" }

r = requests.put(url, data=json.dumps(payload), headers=headers)

Смотрите быстрый старт для библиотеки запросов . Я думаю, что это намного проще, чем urllib2, но требует установки и импорта этого дополнительного пакета.

radtek
источник
Разве запросы не поддерживают PUT?
Джиф
запросы поддерживает получить, поставить, опубликовать, удалить голову и параметры. Исправлен пример использования пут. Проверьте запросы быстрого запуска.
Радтек
@RPradeep Спасибо за это.
Радтек
8

Это было улучшено в python3 и задокументировано в документации stdlib

urllib.request.RequestКласс получил method=...параметр в Python3.

Пример использования:

req = urllib.request.Request('https://example.com/', data=b'DATA!', method='PUT')
urllib.request.urlopen(req)
Энтони Соттиль
источник
6

Я также рекомендую httplib2 Джо Грегарио. Я использую это регулярно вместо httplib в стандартной lib.

Кори Голдберг
источник
3

Вы посмотрели на put.py ? Я использовал это в прошлом. Вы также можете просто взломать свой собственный запрос с помощью urllib.

Уильям Келлер
источник
Я действительно не хочу использовать http библиотеку случайных парней
Рори
попытка импорта put получение # pip install put Загрузка / распаковка put Не удалось найти файлы для загрузки, удовлетворяющие требованию put Очистка ... Не найдено ни одного дистрибутива для put
Ashish Karpe
# tail -f /root/.pip/pip.log Traceback (последний вызов был последним): файл "/usr/lib/python2.7/dist-packages/pip/basecommand.py", строка 122, в основном состоянии = self.run (options, args) Файл "/usr/lib/python2.7/dist-packages/pip/commands/install.py", строка 278, в прогоне require_set.prepare_files (finder, force_root_egg_info = self.bundle, bundle = self.bundle) Файл "/usr/lib/python2.7/dist-packages/pip/req.py", строка 1178, в prepare_files
Ашиш Карпе
url = finder.find_requirement (req_to_install, upgrade = self.upgrade) Файл "/usr/lib/python2.7/dist-packages/pip/index.py", строка 277, в find_requirement поднимает DistributionNotFound ('Распределения вообще не найдено для% s '% req) DistributionNotFound: для пут не найдено ни одного распределения
Ашиш Карпе
2

Конечно, вы можете свернуть свои собственные существующие библиотеки на любом уровне, от сокетов до настройки urllib.

http://pycurl.sourceforge.net/

«PyCurl - это интерфейс Python для libcurl».

«libcurl - это бесплатная и простая в использовании клиентская библиотека для передачи URL, ... поддерживает ... HTTP PUT»

«Основным недостатком PycURL является то, что он является относительно тонким слоем по сравнению с libcurl без какой-либо из этих хороших иерархий классов Pythonic. Это означает, что у него довольно крутая кривая обучения, если вы уже не знакомы с C API libcurl».

wnoise
источник
Я уверен, что это сработает, но я хочу что-то более питоническое
Рори
2

Если вы хотите остаться в стандартной библиотеке, вы можете создать подкласс urllib2.Request:

import urllib2

class RequestWithMethod(urllib2.Request):
    def __init__(self, *args, **kwargs):
        self._method = kwargs.pop('method', None)
        urllib2.Request.__init__(self, *args, **kwargs)

    def get_method(self):
        return self._method if self._method else super(RequestWithMethod, self).get_method()


def put_request(url, data):
    opener = urllib2.build_opener(urllib2.HTTPHandler)
    request = RequestWithMethod(url, method='PUT', data=data)
    return opener.open(request)
Уилфред Хьюз
источник
0

Более правильный способ сделать это с requests:

import requests

payload = {'username': 'bob', 'email': 'bob@bob.com'}

try:
    response = requests.put(url="http://somedomain.org/endpoint", data=payload)
    response.raise_for_status()
except requests.exceptions.RequestException as e:
    print(e)
    raise

Это вызывает исключение, если в запросе HTTP PUT есть ошибка.

Адам Эриксон
источник