Как сделать submit формы для авторизации в вконтакте

Рейтинг: 1Ответов: 1Опубликовано: 01.05.2015

Пытаюсь авторизоваться в вконтакте:

url_open = urllib.request.urlopen("http://vk.com/")
page_r = lxml.html.document_fromstring(url_open.read())
form = page_r.forms[0]
form.inputs['email'].value = 'мой_email'
form.inputs['pass'].value = 'мой_пароль'

Но на response = form.submit() или response = form.submit_form() получаю такую ошибку:

Traceback (most recent call last):
File "<pyshell#76>", line 1, in <module>
response = form.submit()
AttributeError: 'FormElement' object has no attribute 'submit'

Что я делаю не так и как еще можно нажать на кнопку "Войти"? Заранее спасибо.

Ответы

▲ 1Принят

Для начала есть проблема в том, что отправка формы производится через функцию submit_form, а не через методы submit или submit_form.

Вторая проблема состоит в том, что у реализации lxml под Python 3 есть баг с кодировкой отправляемых значений. Этой же проблеме посвящено обсуждение на главном сайте.

Самым простым, но непереносимым решением будет следующее:
Открыть файл <путь-к-библиотекам-python3>/lxml/html/__init__.py
Найти в нём функцию open_http_urllib и в её предпоследней строке заменить data = urlencode(values) на data = urlencode(values).encode('utf-8')
(т.е. повторить действия pull-request)

Более правильно будет завести свою функцию open_http:

def open_http(method, url, values):
    from urllib.request import urlopen
    from urllib.parse import urlencode

    data = urlencode(values).encode('utf-8')
    return urlopen(url, data)

Это упрощённая, работающая только с POST-запросами функция, которая считает, что переданные аргументы корректны.

Эту функцию нужно передать в submit_form:

lxml.html.submit_form(form, open_http=open_http)

Могу предложить альтернативное и более удобное решение, с использованием библиотеки requests.

Для того, чтобы отправить ваши данные (в этом случае), нужно использовать POST запрос, в котором уже указать логин и пароль.

Посмотреть, какие данные требуется передать POST-запросом, можно, например, через средства разработчика браузера, вручную залогинившись.

Сейчас контакт, например, передаёт следующие параметры этим POST-запросом:

act: login
role: al_frame
expire: 
captcha_sid: 
captcha_key: 
_origin: http://vk.com
ip_h: <ip_h>
email: <email>
pass: <pass>

Конкретные значения смотрите самостоятельно, в вашем случае они могут отличаться.

Заметьте также, что запрос на авторизацию отправляется уже на другой адрес: https://login.vk.com/?act=login


В случае использования библиотеки requests, код будет иметь примерно такой вид:

import requests

with requests.Session() as session:
    login_url = 'https://login.vk.com/?act=login'

    login_data = {
        'act': 'login',
        'role': 'al_frame',
        'expire': '',
        'captcha_sid': '',
        'captcha_key': '',
        '_origin': 'http://vk.com',
        'ip_h': '<ip_h>',
        'email': '<email>',
        'pass': '<pass>'
    }

    headers = {
        'referer': 'http://vk.com/'
    }

    session.post(login_url, data=login_data, headers=headers)
    page = session.get('https://vk.com/settings')
    print(page.content)

Также, возможно, стоит посмотреть в сторону vk API.