Возможно, кто-то из читателей сталкивался с этой проблемой. В багтрекере 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())