Я играю, пытаясь написать код для использования API tr.im для сокращения URL-адреса.
Прочитав http://docs.python.org/library/urllib2.html , я попробовал:
TRIM_API_URL = 'http://api.tr.im/api'
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(realm='tr.im',
uri=TRIM_API_URL,
user=USERNAME,
passwd=PASSWORD)
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
response = urllib2.urlopen('%s/trim_simple?url=%s'
% (TRIM_API_URL, url_to_trim))
url = response.read().strip()
response.code - 200 (думаю, должно быть 202). URL-адрес действителен, но базовая HTTP-аутентификация, похоже, не сработала, потому что сокращенного URL-адреса нет в моем списке URL-адресов ( http://tr.im/?page=1 ).
Прочитав http://www.voidspace.org.uk/python/articles/authentication.shtml#doing-it-properly, я также попробовал:
TRIM_API_URL = 'api.tr.im/api'
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, TRIM_API_URL, USERNAME, PASSWORD)
auth_handler = urllib2.HTTPBasicAuthHandler(password_mgr)
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
response = urllib2.urlopen('http://%s/trim_simple?url=%s'
% (TRIM_API_URL, url_to_trim))
url = response.read().strip()
Но получаю те же результаты. (response.code - 200, а url действителен, но не записан в моей учетной записи на http://tr.im/ .)
Если я использую параметры строки запроса вместо базовой HTTP-аутентификации, например:
TRIM_API_URL = 'http://api.tr.im/api'
response = urllib2.urlopen('%s/trim_simple?url=%s&username=%s&password=%s'
% (TRIM_API_URL,
url_to_trim,
USERNAME,
PASSWORD))
url = response.read().strip()
... тогда URL-адрес не только действителен, но и записан в моей учетной записи tr.im. (Хотя response.code по-прежнему 200.)
Что-то должно быть не так с моим кодом (а не с API tr.im), потому что
$ curl -u yacitus:xxxx http://api.tr.im/api/trim_url.json?url=http://www.google.co.uk
... возвращает:
{"trimpath":"hfhb","reference":"nH45bftZDWOX0QpVojeDbOvPDnaRaJ","trimmed":"11\/03\/2009","destination":"http:\/\/www.google.co.uk\/","trim_path":"hfhb","domain":"google.co.uk","url":"http:\/\/tr.im\/hfhb","visits":0,"status":{"result":"OK","code":"200","message":"tr.im URL Added."},"date_time":"2009-03-11T10:15:35-04:00"}
... и URL-адрес действительно отображается в моем списке URL-адресов на http://tr.im/?page=1 .
А если я бегу:
$ curl -u yacitus:xxxx http://api.tr.im/api/trim_url.json?url=http://www.google.co.uk
... снова я получаю:
{"trimpath":"hfhb","reference":"nH45bftZDWOX0QpVojeDbOvPDnaRaJ","trimmed":"11\/03\/2009","destination":"http:\/\/www.google.co.uk\/","trim_path":"hfhb","domain":"google.co.uk","url":"http:\/\/tr.im\/hfhb","visits":0,"status":{"result":"OK","code":"201","message":"tr.im URL Already Created [yacitus]."},"date_time":"2009-03-11T10:15:35-04:00"}
Код заметки - 201, а сообщение - «URL tr.im уже создан [yacitus]».
Я не должен правильно выполнять базовую аутентификацию HTTP (ни в одной из этих попыток). Вы можете определить мою проблему? Может, мне стоит посмотреть, что передается по сети? Я никогда раньше этого не делал. Могу ли я использовать Python API (возможно, в pdb)? Или есть другой инструмент (желательно для Mac OS X), который я могу использовать?
источник
"WWW-Authenticate"
код 401, прежде чем urllib2 (или httplib2) отправит ваши учетные данные. Смотрите мой ответ ниже .Ответы:
Кажется, это действительно хорошо работает (взято из другого потока)
import urllib2, base64 request = urllib2.Request("http://api.foursquare.com/v1/user") base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '') request.add_header("Authorization", "Basic %s" % base64string) result = urllib2.urlopen(request)
источник
request.add_header('Authorization', b'Basic ' + base64.b64encode(username + b':' + password))
Действительно дешевое решение:
urllib.urlopen('http://user:xxxx@api.tr.im/api')
(который вы можете решить, не подходит по ряду причин, например, безопасность URL-адреса)
Пример Github API :
>>> import urllib, json >>> result = urllib.urlopen('https://personal-access-token:x-oauth-basic@api.github.com/repos/:owner/:repo') >>> r = json.load(result.fp) >>> result.close()
источник
Взгляните на этот ответ на сообщение SO, а также посмотрите этот учебник по базовой аутентификации из руководства по отсутствию urllib2 .
Чтобы базовая аутентификация urllib2 работала, HTTP-ответ должен содержать HTTP-код 401 Unauthorized и ключ
"WWW-Authenticate"
со значением,"Basic"
иначе Python не отправит ваши данные для входа, и вам нужно будет либо использовать запросы , либоurllib.urlopen(url)
указать свой логин в URL, или добавить заголовок , как в @ Flowpoke в ответ .Вы можете просмотреть свою ошибку, поместив ее
urlopen
в блок попытки:try: urllib2.urlopen(urllib2.Request(url)) except urllib2.HTTPError, e: print e.headers print e.headers.has_key('WWW-Authenticate')
источник
Рекомендуемый способ - использовать
requests
модуль :#!/usr/bin/env python import requests # $ python -m pip install requests ####from pip._vendor import requests # bundled with python url = 'https://httpbin.org/hidden-basic-auth/user/passwd' user, password = 'user', 'passwd' r = requests.get(url, auth=(user, password)) # send auth unconditionally r.raise_for_status() # raise an exception if the authentication fails
Вот
urllib2
вариант с одним исходным кодом, совместимый с Python 2/3 :#!/usr/bin/env python import base64 try: from urllib.request import Request, urlopen except ImportError: # Python 2 from urllib2 import Request, urlopen credentials = '{user}:{password}'.format(**vars()).encode() urlopen(Request(url, headers={'Authorization': # send auth unconditionally b'Basic ' + base64.b64encode(credentials)})).close()
Python 3.5+ представляет,
HTTPPasswordMgrWithPriorAuth()
что позволяет:#!/usr/bin/env python3 import urllib.request as urllib2 password_manager = urllib2.HTTPPasswordMgrWithPriorAuth() password_manager.add_password(None, url, user, password, is_authenticated=True) # to handle 404 variant auth_manager = urllib2.HTTPBasicAuthHandler(password_manager) opener = urllib2.build_opener(auth_manager) opener.open(url).close()
Это легко заменить
HTTPBasicAuthHandler()
с ,ProxyBasicAuthHandler()
если это необходимо в данном случае.источник
Я бы предположил, что текущее решение - использовать мой пакет urllib2_prior_auth, который решает эту проблему довольно хорошо (я работаю над включением в стандартный lib.
источник
urrlib.request.HTTPBasicPriorAuthHandler
Применяются те же решения, что и у Python urllib2 Basic Auth .
см. https://stackoverflow.com/a/24048852/1733117 ; вы можете создать подкласс,
urllib2.HTTPBasicAuthHandler
чтобы добавитьAuthorization
заголовок к каждому запросу, который соответствует известному URL-адресу.class PreemptiveBasicAuthHandler(urllib2.HTTPBasicAuthHandler): '''Preemptive basic auth. Instead of waiting for a 403 to then retry with the credentials, send the credentials if the url is handled by the password manager. Note: please use realm=None when calling add_password.''' def http_request(self, req): url = req.get_full_url() realm = None # this is very similar to the code from retry_http_basic_auth() # but returns a request object. user, pw = self.passwd.find_user_password(realm, url) if pw: raw = "%s:%s" % (user, pw) auth = 'Basic %s' % base64.b64encode(raw).strip() req.add_unredirected_header(self.auth_header, auth) return req https_request = http_request
источник
strip
избыточности не являетсяb64encode
?Попробуйте python-request или python-grab
источник