Bawię się, próbując napisać kod, aby użyć interfejsów API tr.im do skrócenia adresu URL.
Po przeczytaniu http://docs.python.org/library/urllib2.html próbowałem:
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 to 200 (myślę, że powinno być 202). adres url jest prawidłowy, ale wydaje się, że podstawowe uwierzytelnianie HTTP nie zadziałało, ponieważ skróconego adresu URL nie ma na mojej liście adresów URL (pod adresem http://tr.im/?page=1 ).
Po przeczytaniu http://www.voidspace.org.uk/python/articles/authentication.shtml#doing-it-properly spróbowałem też:
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()
Ale mam takie same wyniki. (kod odpowiedzi to 200, a adres URL jest prawidłowy, ale nie został zapisany na moim koncie pod adresem http://tr.im/ .)
Jeśli używam parametrów ciągu zapytania zamiast podstawowego uwierzytelniania HTTP, na przykład:
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()
... to nie tylko adres URL jest prawidłowy, ale jest zapisywany na moim koncie tr.im. (Chociaż kod odpowiedzi to nadal 200.)
Jednak musi być coś nie tak z moim kodem (a nie z API tr.im), ponieważ
$ curl -u yacitus:xxxx http://api.tr.im/api/trim_url.json?url=http://www.google.co.uk
...zwroty:
{"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"}
... a adres URL pojawia się na mojej liście adresów URL pod adresem http://tr.im/?page=1 .
A jeśli biegnę:
$ curl -u yacitus:xxxx http://api.tr.im/api/trim_url.json?url=http://www.google.co.uk
... znowu otrzymuję:
{"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"}
Kod notatki to 201, a wiadomość to „Tr.im URL Already Created [yacitus]”.
Nie mogę poprawnie wykonywać podstawowego uwierzytelniania HTTP (w żadnej z prób). Czy widzisz mój problem? Może powinienem spojrzeć i zobaczyć, co jest przesyłane przez drut? Nigdy wcześniej tego nie robiłem. Czy istnieją interfejsy API Pythona, których mogę używać (być może w pdb)? A może jest inne narzędzie (najlepiej dla Mac OS X), którego mogę użyć?
źródło
"WWW-Authenticate"
i kod 401, zanim urllib2 (lub httplib2) wyśle Twoje poświadczenia. Zobacz moją odpowiedź poniżej .Odpowiedzi:
Wydaje się, że działa naprawdę dobrze (zaczerpnięte z innego wątku)
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)
źródło
request.add_header('Authorization', b'Basic ' + base64.b64encode(username + b':' + password))
Naprawdę tanie rozwiązanie:
urllib.urlopen('http://user:[email protected]/api')
(co możesz zdecydować, że nie jest odpowiednie z wielu powodów, takich jak bezpieczeństwo adresu URL)
Przykład Github API :
>>> import urllib, json >>> result = urllib.urlopen('https://personal-access-token:[email protected]/repos/:owner/:repo') >>> r = json.load(result.fp) >>> result.close()
źródło
Spójrz na tę odpowiedź na SO, a także na ten samouczek dotyczący podstawowego uwierzytelniania z brakującego podręcznika urllib2 .
Aby podstawowe uwierzytelnianie urllib2 działało, odpowiedź http musi zawierać kod HTTP 401 Unauthorized i klucz
"WWW-Authenticate"
z wartością, w"Basic"
przeciwnym razie Python nie wyśle twoich danych logowania i będziesz musiał albo użyć żądań , albourllib.urlopen(url)
z loginem w URL lub dodać nagłówek jak w @ Flowpoke za odpowiedź .Możesz zobaczyć swój błąd, umieszczając swój
urlopen
w bloku próbnym:try: urllib2.urlopen(urllib2.Request(url)) except urllib2.HTTPError, e: print e.headers print e.headers.has_key('WWW-Authenticate')
źródło
Zalecanym sposobem jest użycie
requests
modułu :#!/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
Oto
urllib2
wariant oparty na jednym źródle Python 2/3 zgodny z :#!/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+ wprowadza,
HTTPPasswordMgrWithPriorAuth()
który umożliwia:#!/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()
Jest to łatwe do wymiany
HTTPBasicAuthHandler()
wProxyBasicAuthHandler()
razie potrzeby w tym przypadku.źródło
Sugerowałbym, że obecnym rozwiązaniem jest użycie mojego pakietu urllib2_prior_auth, który całkiem ładnie to rozwiązuje (pracuję nad włączeniem do standardowego lib.
źródło
urrlib.request.HTTPBasicPriorAuthHandler
Stosowane są te same rozwiązania, co Python urllib2 Basic Auth Problem .
zobacz https://stackoverflow.com/a/24048852/1733117 ; możesz podklasę,
urllib2.HTTPBasicAuthHandler
aby dodaćAuthorization
nagłówek do każdego żądania, które pasuje do znanego adresu 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
źródło
strip
zbędne pob64encode
?Wypróbuj python-request lub python-grab
źródło