更新:Leeのコメントに基づいて、コードを非常に単純なスクリプトに凝縮し、コマンドラインから実行することにしました。
import urllib2
import sys
username = sys.argv[1]
password = sys.argv[2]
url = sys.argv[3]
print("calling %s with %s:%s\n" % (url, username, password))
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, url, username, password)
urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(passman)))
req = urllib2.Request(url)
f = urllib2.urlopen(req)
data = f.read()
print(data)
残念ながら、まだ[Wirevarごとに] Authorization
ヘッダーは生成されません:(
Urllib2経由で基本的なAUTHを送信する際に問題が発生しています。 この記事 を見て、例に従いました。私のコード:
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, "api.foursquare.com", username, password)
urllib2.install_opener(urllib2.build_opener(urllib2.HTTPBasicAuthHandler(passman)))
req = urllib2.Request("http://api.foursquare.com/v1/user")
f = urllib2.urlopen(req)
data = f.read()
Wireshark経由でWireに次のメッセージが表示されます。
GET /v1/user HTTP/1.1
Host: api.foursquare.com
Connection: close
Accept-Encoding: gzip
User-Agent: Python-urllib/2.5
Curlを介してリクエストを送信した場合と比べて、認証が送信されていないことがわかります:curl -u user:password http://api.foursquare.com/v1/user
GET /v1/user HTTP/1.1
Authorization: Basic =SNIP=
User-Agent: curl/7.19.4 (universal-Apple-darwin10.0) libcurl/7.19.4 OpenSSL/0.9.8k zlib/1.2.3
Host: api.foursquare.com
Accept: */*
何らかの理由で、私のコードは認証を送信しないようです-誰かが私が見逃しているものを見ますか?
ありがとう
-サイモン
問題は、Pythonライブラリ、HTTP-Standardごとに、最初に認証されていない要求を送信し、401再試行で応答された場合にのみ、正しい資格情報が送信されることです。 「完全に標準的な認証」をしないと、ライブラリは機能しません。
認証を行うためにヘッダーを使用してみてください:
import urllib2, base64
request = urllib2.Request("http://api.foursquare.com/v1/user")
base64string = base64.b64encode('%s:%s' % (username, password))
request.add_header("Authorization", "Basic %s" % base64string)
result = urllib2.urlopen(request)
あなたと同じ問題があり、このスレッドから解決策を見つけました: http://forums.shopify.com/categories/9/posts/27662
MailChimpのAPIにアクセスしようとしたときに発生した同様の問題に対処するために使用しているものを次に示します。これは同じことを行いますが、フォーマットが良くなりました。
import urllib2
import base64
chimpConfig = {
"headers" : {
"Content-Type": "application/json",
"Authorization": "Basic " + base64.encodestring("hayden:MYSECRETAPIKEY").replace('\n', '')
},
"url": 'https://us12.api.mailchimp.com/3.0/'}
#perform authentication
datas = None
request = urllib2.Request(chimpConfig["url"], datas, chimpConfig["headers"])
result = urllib2.urlopen(request)
(copy-paste/adapted from https://stackoverflow.com/a/24048772/1733117 )。
最初にurllib2.BaseHandler
またはurllib2.HTTPBasicAuthHandler
をサブクラス化し、http_request
を実装して、各リクエストに適切なAuthorization
ヘッダーを付けることができます。
import urllib2
import base64
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
次に、あなたが私のように怠け者であれば、ハンドラーをグローバルにインストールします
api_url = "http://api.foursquare.com/"
api_username = "johndoe"
api_password = "some-cryptic-value"
auth_handler = PreemptiveBasicAuthHandler()
auth_handler.add_password(
realm=None, # default realm.
uri=api_url,
user=api_username,
passwd=api_password)
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
2番目のパラメーターは、ドメイン名ではなくURIでなければなりません。つまり.
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, "http://api.foursquare.com/", username, password)
現在の解決策は、パッケージ rllib2_prior_auth を使用することで、これをかなりうまく解決することをお勧めします(標準ライブラリに対して inclusion に取り組んでいます)。