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 Basic Auth Problem

Проблема [в том], что библиотеки Python в соответствии со стандартом HTTP сначала отправляют неаутентифицированный запрос, а затем только в том случае, если на него ответили повторной попыткой 401, отправляются правильные учетные данные. Если ... серверы не выполняют «полностью стандартную аутентификацию», то библиотеки работать не будут.

Этот конкретный API не отвечает 401 Unauthorized с первой попытки, он отвечает 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