urllib2 HTTPPasswordMgr не работи - грешка при неизпратени идентификационни данни

Следното извикване на python curl има следните успешни резултати:

>>> import subprocess
>>> args = [
        'curl',
        '-H', 'X-Requested-With: Demo',
        'https://username:[email protected]/qps/rest/3.0/count/was/webapp' ] 
>>> xml_output = subprocess.check_output(args).decode('utf-8')
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
138   276    0   276    0     0    190      0 --:--:--  0:00:01 --:--:--   315
>>> xml_output
u'<?xml version="1.0" encoding="UTF-8"?>\n<ServiceResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://qualysapi.qualys.com/qps/xsd/3.0/was/webapp.xsd">\n<responseCode>SUCCESS</responseCode>\n  <count>33</count>\n</ServiceResponse>'

За съжаление, това извикване не се превежда успешно към urllib2. Получавам различен XML отговор, в който се посочва, че потребителят не е предоставил идентификационни данни за оторизация:

>>> import urllib2
>>> # Create a password manager.
... password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
>>> # Add the username and password.
... top_level_url = 'https://qualysapi.qualys.com'
>>> password_mgr.add_password(None, top_level_url, username, password)
>>> handler = urllib2.HTTPBasicAuthHandler(password_mgr)
>>> opener = urllib2.build_opener(handler)
>>> urllib2.install_opener(opener)
>>> headers = {'X-Requested-With':'Demo'}
>>> uri = 'https://qualysapi.qualys.com/qps/rest/3.0/count/was/webapp'
>>> req = urllib2.Request(uri,None,headers)
>>> result = urllib2.urlopen(req)
>>> result
'<ServiceResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://qualysapi.qualys.com/qps/xsd/3.0/was/webapp.xsd">\n  <responseCode>INVALID_CREDENTIALS</responseCode>\n  <responseErrorDetails>\n    <errorMessage>User did not supply any authentication headers</errorMessage>\n  </responseErrorDetails>\n</ServiceResponse>'

Между другото, получавам същото съобщение за грешка с httplib:

>>> import httplib, base64
>>> auth = 'Basic ' + string.strip(base64.encodestring(username + ':' + password))
>>> h = httplib.HTTPSConnection('qualysapi.qualys.com')
>>> h.request("GET", "/qps/rest/3.0/count/was/webapp/")
>>> r1 = h.getresponse()
>>> print r1.status, r1.reason
200 OK
>>> data1 = r1.read()
>>> data1
'<ServiceResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://qualysapi.qualys.com/qps/xsd/3.0/was/webapp.xsd">\n  <responseCode>INVALID_CREDENTIALS</responseCode>\n  <responseErrorDetails>\n    <errorMessage>User did not supply any authentication headers</errorMessage>\n  </responseErrorDetails>\n</ServiceResponse>'

Разбирам, че httplib & urllib2 може да работи само ако SSL е компилиран в сокет, който SSL е компилиран в модула на сокета. Всъщност използвах urllib2 успешно за други извиквания на различен API. Проблемът е изолиран за този конкретен API.

Какво прави urllib2 (и httplib) различно от curl?

Забележка: Използваните потребителско име и парола са еднакви във всички примери.

Актуализация:

Проблемът е с основния мениджър на пароли за удостоверяване. Когато ръчно добавя основната заглавка за оторизация, urllib2 cal работи:

>>> import base64
>>> base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
>>> req.add_header("Authorization", "Basic %s" % base64string)
>>> # Make request to fetch url.
... result = urllib2.urlopen(req)
>>> # Read xml results.
... xml = result.read()
>>> xml
'<?xml version="1.0" encoding="UTF-8"?>\n<ServiceResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://qualysapi.qualys.com/qps/xsd/3.0/was/webapp.xsd">\n  <responseCode>SUCCESS</responseCode>\n  <count>33</count>\n</ServiceResponse>'

person paragbaxi    schedule 29.02.2012    source източник


Отговори (2)


От Проблем с базовото удостоверяване на Python urllib2

Проблемът [е], че библиотеките на Python, според HTTP-стандарта, първо изпращат неудостоверена заявка и след това само ако се отговори с повторен опит 401, се изпращат правилните идентификационни данни. Ако ... сървърите не извършват "напълно стандартно удостоверяване", тогава библиотеките няма да работят.

Този конкретен API не отговаря с 401 Неупълномощен при първия опит, той отговаря с XML отговор, съдържащ съобщението, че идентификационните данни не са изпратени с код на отговор 200 OK.

person paragbaxi    schedule 02.03.2012

Опитайте да зададете потребителския агент, може би това пречи. urllib2 се идентифицира като Python-urllib/x.y (където x и y са основните и второстепенните номера на версията на версията на Python, напр. Python-urllib/2.5) това може да е причината сайтът да блокира заявката ви. Разгледайте техния robots.txt.. ето пример за настройка на потребителския агент, така че вашият скрипт да се идентифицира като браузър:

import urllib
import urllib2

url = 'http://www.someserver.com/cgi-bin/register.cgi'
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
headers = { 'User-Agent' : user_agent }
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
the_page = response.read()
person WeaselFox    schedule 29.02.2012
comment
Благодаря, но това води до същия отговор <ServiceResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://qualysapi.qualys.com/qps/xsd/3.0/was/webapp.xsd">\n <responseCode>INVALID_CREDENTIALS</responseCode>\n <responseErrorDetails>\n <errorMessage>User did not supply any authentication headers</errorMessage>\n </responseErrorDetails>\n</ServiceResponse>. - person paragbaxi; 29.02.2012
comment
Използван код от горния коментар: headers = { 'X-Requested-With':'Demo', 'User-Agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' } - person paragbaxi; 29.02.2012