Github-api дает 404 при передаче json-данных с помощью python + urllib2

У меня есть следующий код, который должен выполнить первую часть создания новой загрузки на github. Он должен отправлять json-данные с помощью POST.

jsonstring = '{"name": "test", "size": "4"}'
req = urllib2.Request("https://api.github.com/repos/<user>/<repo>/downloads")
req.add_header('Authorization', 'token ' + '<token>')
result = urllib2.urlopen(req, jsonstring)

Если я удалю , jsonstring из urlopen(), он не выйдет из строя и выдаст мне список доступных загрузок. Однако, если я попытаюсь отправить json-строку POST, я получу ошибку 404.

Проблема должна быть с json или с тем, как я его отправляю, но я не могу понять, в чем проблема. Строки в <...> находятся прямо в реальном коде, я просто удалил их из поста.

Я попробовал примерно то же самое с curl в командной строке, с немного другим методом аутентификации, и это сработало.

Проверено:

Работает (возвращает нужный json):

curl -u "user:password" --data "json..." https://api.github.com/repos/<user>/<repo>/downloads

Работает:

curl -H 'Authorization: token <token>' https://api.github.com/

Не работает (возвращает "неверные учетные данные"):

curl -H 'Authorization: token <invalid_token>' https://api.github.com/

Не работает ("не найдено"):

curl -H 'Authorization: token <valid_token>' --data "json..." https://api.github.com/repos/<user>/<repo>/downloads

Это не похоже на проблему, специфичную для кода Python. Данные json POST, кажется, в порядке, и авторизация токена OAuth, кажется, (по крайней мере, частично) работает. Но когда они собраны вместе, это перестает работать.


person varesa    schedule 28.04.2012    source источник
comment
Вареза или @pelson, какой немного другой метод работает с завитком? Вы не можете использовать этот метод здесь?   -  person blahdiblah    schedule 17.07.2012
comment
@blahdiblah Другой метод заключался в использовании -u user:passwd вместо токена авторизации. Я пробовал с токеном и завитком, та же проблема   -  person varesa    schedule 18.07.2012


Ответы (4)


Я, наконец, смог разобраться, почему это не сработало.

У меня не были правильно установлены области авторизации для токена авторизации. Токен, который я использовал, не был «авторизован» для выполнения каких-либо модификаций, и каждое действие с его использованием, которое пыталось что-то изменить (добавить загрузку), терпело неудачу.

Мне пришлось добавить правильные области действия в авторизацию, чтобы она заработала.

person varesa    schedule 17.07.2012
comment
Ну ладно, я думал, что у нас та же проблема, отсюда и щедрость. Я добавлю свое собственное решение, которое может помочь другим в будущем (включая меня). - person pelson; 24.07.2012

Я предоставил ответ о том, как отправить данные JSON в API V3 без какой-либо аутентификации, но, как вы определили, исходная проблема заключалась в неправильной настройке ваших токенов OAUTH, я подумал, что предоставлю программное решение для получения one (эта реализация получает токен каждый раз при запуске скрипта, тогда как на практике это будет сделано только один раз, и токен будет храниться локально).

import urllib2
import json
import getpass
import base64

# Generate a token from the username and password.
# NOTE: this is a naive implementation. Store pre-retrieved tokens if possible.
username = 'pelson'
passwd = getpass.getpass() # <- this just puts a string in passwd (plaintext)

req = urllib2.Request("https://api.github.com/authorizations")

# add the username and password info to the request
base64string = base64.encodestring('%s:%s' % (username, passwd)).replace('\n', '')
req.add_header("Authorization", "Basic %s" % base64string)

data = json.dumps({"scopes":["repo"], "note":"Access to your repository."})
result = urllib2.urlopen(req, data)
result = json.loads('\n'.join(result.readlines()))
token = result['token']

Если у вас есть этот токен, его можно использовать для любых действий в области «репо». Давайте добавим новую задачу в репозиторий:

# add an issue to the tracker using the new token
repo = 'name_of_repo'
data = json.dumps({'title': 'My automated issue.'})
req = urllib2.Request("https://api.github.com/repos/%s/%s/issues" % (username, repo))
req.add_header("Authorization", "token %s" % token)
result = urllib2.urlopen(req, data)

result = json.loads('\n'.join(result.readlines()))
print result['number']

Надеюсь, это поможет кому-то.

person pelson    schedule 23.07.2012

API-интерфейс github v3 имеет приятную функцию, позволяющую конвертировать уценку в html. Для запроса этой информации не требуется аутентификация, поэтому это хороший пример, который можно попробовать, прежде чем углубляться в более сложный мир аутентификации.

В документах по API указано:

Визуализация произвольного документа Markdown

POST/уценка ввода

text Обязательная строка — текст Markdown для отображения

И даже приведите пример строки уценки, которую нужно преобразовать:

{"text": "Hello world github/linguist#1 **cool**, and #1!"}

Учитывая эту информацию, давайте создадим запрос urllib2 для html-версии этой уценки.

import urllib2
import json


data = {"text": "Hello world github/linguist#1 **cool**, and #1!"}
json_data = json.dumps(data)

req = urllib2.Request("https://api.github.com/markdown")
result = urllib2.urlopen(req, json_data)

print '\n'.join(result.readlines())

И в результате получается HTML-код, представляющий уценку.

Учитывая этот пример, не JSON вызывает 404 при публикации вашего запроса, а, скорее всего, аутентификация (как вы уже ответили).

person pelson    schedule 23.07.2012

Разве данные не предназначены для кодирования URL, а не JSON? Пытаться:

data = {"name": "test", "size": "4"}
req = urllib2.Request("https://api.github.com/repos/<user>/<repo>/downloads")
req.add_header('Authorization', 'token ' + '<token>')
result = urllib2.urlopen(req, urllib.parse.urlencode(data))
person MRAB    schedule 17.07.2012
comment
AttributeError: объект «модуль» не имеет атрибута «анализ». Я использую питон 2.6.6 - person varesa; 18.07.2012
comment
Нет, API v3 принимает JSON в качестве данных POST. Первый абзац документации (developer.github.com/v3) гласит: Все данные отправлены и получен в формате JSON. - person pelson; 24.07.2012