Возможно, кто-то из читателей сталкивался с этой проблемой. В багтрекере GAE она уже давно висит в виде незакрытого Issue 3379. Кажется, изначально проблема касалась только Java, но сейчас она наблюдается и в Python (по крайней мере в 2.7). Описание ошибки и решение для Java можно найти, например, там, а в этом топике речь пойдёт про Python.
Коротко о сути. Часто сайты пытаются установить более одной cookie за раз. Делают они это путём указания нескольких заголовков Set-Cookie в ответе на запрос. По странному ведёт себя в этом случае urlfetch (и базирующиеся на нём urllib/urllib2): все эти заголовки склеиваются в один и разделяются запятыми. Надо ли напоминать, что запятые также присутствуют в полях expiries, а порой и в самих значениях cookie, что очень затрудняет обратный разбор такой строки. А стандартный HTTPCookieProcessor из urllib2 и mechanize просто не справляется с такой ситуацией.
Итак, если ваш проект использует поддержку cookies «из коробки» в urllib2 или mechanize, то вам безусловно подойдёт следующее простое решение.
Создадим обработчик, разделяющий проблемные заголовки до того, как они перейдут к HTTPCookieProcessor:
Используемое в качестве разделителя регулярное выражение может давать в тяжёлых случаях ложные срабатывания, но я с таким кривыми cookie на практике не сталкивался.
Осталось только добавить наш обработчик в новый OpenDirector (или в имеющийся с помощью add_handler()):
Всё, пользуемся:
В случае, если вы (как и я) используете mechanize, просто замените везде urllib2 на mechanize, а вместо mechanize.build_opener() естественнее воспользоваться следующей конструкцией:
Коротко о сути. Часто сайты пытаются установить более одной cookie за раз. Делают они это путём указания нескольких заголовков Set-Cookie в ответе на запрос. По странному ведёт себя в этом случае urlfetch (и базирующиеся на нём urllib/urllib2): все эти заголовки склеиваются в один и разделяются запятыми. Надо ли напоминать, что запятые также присутствуют в полях expiries, а порой и в самих значениях cookie, что очень затрудняет обратный разбор такой строки. А стандартный HTTPCookieProcessor из urllib2 и mechanize просто не справляется с такой ситуацией.
Итак, если ваш проект использует поддержку cookies «из коробки» в urllib2 или mechanize, то вам безусловно подойдёт следующее простое решение.
Создадим обработчик, разделяющий проблемные заголовки до того, как они перейдут к HTTPCookieProcessor:
import urllib2, re class SplitCookiesHandler(urllib2.BaseHandler): handler_order = 0 def http_response(self, req, response): headers = response.info().headers for h in headers[:]: matched = re.match("(?i)set-cookie:(.*)\n$", h) if matched is not None: headers.remove(h) for cookie in re.split(",(?= \w+[\w\d]*=)", matched.group(1)): headers.append("set-cookie:" + cookie + "\n") return response
Используемое в качестве разделителя регулярное выражение может давать в тяжёлых случаях ложные срабатывания, но я с таким кривыми cookie на практике не сталкивался.
Осталось только добавить наш обработчик в новый OpenDirector (или в имеющийся с помощью add_handler()):
import cookielib cj = cookielib.CookieJar() opener = urllib2.build_opener(SplitCookiesHandler(), urllib2.HTTPCookieProcessor(cj))
Всё, пользуемся:
r = opener.open("http://www.yandex.ru/")
В случае, если вы (как и я) используете mechanize, просто замените везде urllib2 на mechanize, а вместо mechanize.build_opener() естественнее воспользоваться следующей конструкцией:
br = mechanize.Browser() br.add_handler(SplitCookiesHandler())
