Как работает базовая аутентификация
Наряду с аутентификацией при помощи формы, существует и более простая -- так наз. "базовая аутентификация":- При первой попытке зайти на сайт сервер проверяет, если среди заголовков запроса поле 'Authorization'. Если нет или там содержится неверное значение, возвращается ошибка 401.
- Браузер открывает всплывающее окошко для ввода имени пользователя логин и пароля
- Пользователь вводит имя и пароль, нажимает OK и браузер делает повторный запрос, вставив в заголовок запроса: Authorization: Basic данные.
- Сервер проверяет логин с паролем и если все в порядке, возвращает запрошенную страницу с кодом 200.
Эта защита считается не самой надежной и применяется чаще всего в технических целях. Например, чтобы закрыть доступ к порталу всем, кроме заказчиков, разработчиков и тестировщиков, пока не закончена работа.
В одной из заметок был продемонстрирован краулер, способный обходить сайт и проверять, все ли ссылки правильно работают. Поскольку использоваться он будет чаще всего на этапе тестирования сайтов, ему недостает умения заходить на защищенные таким способом страницы.
Базовая аутентификация и urllib2
Для базовой аутентификации средствами питоновской библиотеки urllib2 нужно использовать два встроенных класса:- HTTPPasswordMgr
- HTTPBasicAuthHandler
Простейший вариант HTTPPasswordMgr
class KnownPasswordMgr(HTTPPasswordMgr):
"""
Хранит заранее заданную пару логин/пароль
"""
def __init__(self, username, password):
HTTPPasswordMgr.__init__(self)
self.username = username
self.password = password
def find_user_password(self, realm, authuri):
"""
Возвращает заранее известную пару значений
"""
retval = HTTPPasswordMgr.find_user_password(self, realm, authuri)
if not (retval[0] or retval[1]):
return (self.username, self.password)
return retval
"""
Хранит заранее заданную пару логин/пароль
"""
def __init__(self, username, password):
HTTPPasswordMgr.__init__(self)
self.username = username
self.password = password
def find_user_password(self, realm, authuri):
"""
Возвращает заранее известную пару значений
"""
retval = HTTPPasswordMgr.find_user_password(self, realm, authuri)
if not (retval[0] or retval[1]):
return (self.username, self.password)
return retval
HTTPBasicAuthHandler
В конструктор класса UserAgent добавим необязательный параметр: credentials. Если он присутствует, к набору handler-ов будет добавлен HTTPBasicAuthHandler.class UserAgent(object):
"""
Краулер.
Именованные аргументы конструктора и значения по умолчанию:
agentname -- имя ('Test/1.0')
email -- адрес разработчика (пустая строка)
hdrs -- словарь HTTP-заголовков (DEFAULT_HEADERS)
ignore_robots -- True, если следует игнорировать robots.txt (False)
credentials -- словарь с ключами 'логин' и 'пароль', если нужна
базовая аутентификация (None).
"""
def __init__(self,
agentname=DEFAULT_AGENTNAME,
email=DEFAULT_EMAIL,
hdrs=None,
ignore_robots=False,
credentials=None):
if not hdrs:
hdrs = {}
self.agentname = agentname
self.email = email
self.cookies_handler = SessionCookieHandler()
handlers = [ self.cookies_handler, ]
if not ignore_robots:
handlers.append(RobotsHTTPHandler(self.agentname))
if credentials:
handlers.append(
HTTPBasicAuthHandler(KnownPasswordMgr(**credentials))
)
self.opener = urllib2.build_opener(*handlers)
# переопределение заголовков по умолчанию
headers = copy(DEFAULT_HEADERS)
headers.update(hdrs)
op_headers = [ (k, v) for k, v in headers.iteritems() ]
op_headers.append(('User-Agent', self.agentname))
# если email не задан, HTTP-заголовок 'From' не нужен
if self.email:
op_headers.append(('From', self.email))
self.opener.addheaders = op_headers
class TestAuth(unittest.TestCase):
def setUp(self):
self.crawler = crawler.UserAgent(
agentname='Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
ignore_robots=True,
credentials = dict(username='ЛОГИН', password='ПАРОЛЬ')
)
def _on_success(self, *args):
self.assertTrue(1)
def _on_failure(self, url, err):
self.fail('Authentication failed: %s' % err)
def test_authentication(self):
self.crawler.visit('АДРЕС САЙТА',
on_success=self._on_success,
on_failure=self._on_failure )
6 комментариев:
Прочитал все 12 статей, очень понравилось. Только не нашел собранных воедино исходников краулера.
Сам планирую написать краулер по ежедневному анализу форума.
Спасибо за отзыв, рад, если что-то пригодится.
К сожалению, в блоггер неудобно помещать исходники. Как освобожусь немного, сделаю отдельный сайт, куда помещу и исходники и готовый к установке пакет.
Мне интересно Вы писали "В 2007 году, когда я писал краулера на Питоне для поискового проекта, именно отсутствие надежного HTML-парсера заставила меня пересесть на Perl. Ни SGMLParser ни HTMLParser из стандартных библиотек не в состоянии справиться со страницами, выходящими за рамки академического гипертекста."
Так какая библиотека способна понять все многообразие интернета ? Я думаю, что наверно из движка Mozill-ы если только собранная.
То есть я предполагаю, в инете найти подобное хотя сам не искал. Даже думал над тем, что бывают парсеры с векторной отладкой. Наподобие дай мне координаты Rect элемента на предполагаемой странице браузера. Это наверно мечты)))
Кажется, html5lib вполне справляется c парсингом. Я знаю, что есть еще библиотека python-spidermonkey, которая понимает JavaScript на страницах. А вот что касается "векторной отладки" -- не уверен, что существует нечто подобное, задача-то явно нетривиальная.
Отправить комментарий