Python - Solicitudes / RoboBrowser - ASPX POST JavaScript

Estoy portando un script bash que usa curl y POSTs las cargas útiles en el código a las URL y funciona. El problema básico es que, con robobrowser, tengo problemas para publicar usando los formularios de página.

Recorriendo el sitio:

Inicie sesión en /SubLogin.aspxEl inicio de sesión exitoso redirige /OptionsSummary.aspxGET /FindMe.aspx con paramsBotón POST /FindMe.aspx "Listas de teléfonos" (la página debería cargar la tabla "Listas de teléfonos" con un elemento "Trabajo")Al seleccionar el elemento "Trabajo" se ejecuta una POST a /PhoneLists.aspx (esto debería cargar una tabla "Trabajo" con la lista de usuarios.

He podido autenticarme con éxito en el sitio y realizar GET con RoboBrowser y Requests + bs4, sin embargo, estoy confundido al POSTAR de nuevo en las páginas.

Usando RoboBrowser (liboncall.py)

#!/usr/bin/python

from robobrowser import RoboBrowser
from bs4 import BeautifulSoup as BS

oc_mailbox = '123456'
oc_password_hashed = 'ABCDEFG'

base_uri = 'http://example.com'
auth_uri = oc_base_uri + '/SubLogin.aspx'
find_uri = oc_base_uri + '/FindMe.aspx'
phne_uri = oc_base_uri + '/PhoneLists.aspx'


p_auth_payload = {
        'SubLoginControl:javascriptTest': 'true',
        'SubLoginControl:mailbox': mailbox,
        'SubLoginControl:phoneNumber': '',
        'SubLoginControl:password': password_hashed,
        'SubLoginControl:btnLogOn': 'Logon',
        'SubLoginControl:webLanguage': 'en-US',
        'SubLoginControl:initialLanguage': 'en-US',
        'SubLoginControl:errorCallBackNumber': 'Entered telephone number contains non-dialable characters.',
        'SubLoginControl:cookieMailbox': 'mailbox',
        'SubLoginControl:cookieCallbackNumber': 'callbackNumber',
        'SubLoginControl:serverDomain': ''
        }

p_find_payload = {
        'FindMeControl:enableFindMe': 'on',
        'FindMeControl:MasterDataControl:focusElement': '',
        'FindMeControl:MasterDataControl:masterList:_ctl0:enabled': 'on',
        'FindMeControl:MasterDataControl:masterList:_ctl0:itemGuid': '',
        'FindMeControl:MasterDataControl:hidSelectedScheduleName': '',
        'FindMeControl:MasterDataControl:hidbtnStatus': '',
        'FindMeControl:MasterDataControl:hidScheduleXML': '',
        'FindMeControl:MasterDataControl:tempScheduleXML': '',
        'FindMeControl:MasterDataControl:hidSelectedScheduleGUID': '',
        'FindMeControl:MasterDataControl:hidChangedScheduleList': '',
        'FindMeControl:btnPhoneLists': 'Phone Lists',
        'FindMeControl:enableFindMeHidden': '',
        'FindMeControl:applySet': 'false'
        }

p_phne_payload = {
        '__EVENTARGUMENT': '',
        '__EVENTTARGET': 'PhoneListsControl$MasterDataControl$masterList$_ctl0$SelectButton',
        'PhoneListsControl:MasterDataControl:focusElement': '',
        'PhoneListsControl:MasterDataControl:masterList:_ctl0:itemGuid': '',
        'PhoneListsControl:MasterDataControl:hidSelectedScheduleName': '',
        'PhoneListsControl:MasterDataControl:hidbtnStatus': '',
        'PhoneListsControl:MasterDataControl:hidScheduleXML': '',
        'PhoneListsControl:MasterDataControl:tempScheduleXML': '',
        'PhoneListsControl:MasterDataControl:hidSelectedScheduleGUID': '',
        'PhoneListsControl:MasterDataControl:hidChangedScheduleList': '',
        'PhoneListsControl:applySet': 'false'
        }


def auth(mailbox, password):
    browser = RoboBrowser(history=False)
    browser.open(oc_auth_uri)

    signin = browser.get_form(id='aspnetForm')
    signin['SubLoginControl:mailbox'].value = mailbox
    signin['SubLoginControl:password'].value = password
    signin['SubLoginControl:javascriptTest'].value = 'true'
    signin['SubLoginControl:btnLogOn'].value = 'Logon'
    signin['SubLoginControl:webLanguage'].value = 'en-US'
    signin['SubLoginControl:initialLanguage'].value = 'en-US'
    signin['SubLoginControl:errorCallBackNumber'].value = 'Entered+telephone+number+contains+non-dialable+characters.'
    signin['SubLoginControl:cookieMailbox'].value = 'mailbox'
    signin['SubLoginControl:cookieCallbackNumber'].value = 'callbackNumber'
    signin['SubLoginControl:serverDomain'].value = ''

    browser.submit_form(signin)
    return browser

Inicie sesión en el sitio y muestre la URL para verificar que estamos en:

In [20]: from liboncall import *
In [21]: m = auth(oc_mailbox, oc_password_hashed)

In [22]: m.url
Out[22]: u'http://example.com/OptionsSummary.aspx'

Abra "/FindMe.aspx":

In [24]: m.open(find_uri)

In [25]: m.url
Out[25]: u'http://example.com/FindMe.aspx'

Inicialmente "/FindMe.aspx" cargará un formulario y un botón "Listas de teléfonos", (FindMeControl:btnPhoneLists)

In [26]: m.select('title')
Out[26]: [<title>Find Me</title>]

In [27]: form_find_a = m.get_form(action="FindMe.aspx")

In [28]: for i in form_find_a.keys():
    print(i)
    ....:
    __VIEWSTATE
    __EVENTVALIDATION
    FindMeControl:enableFindMe
    FindMeControl:MasterDataControl:focusElement
    FindMeControl:MasterDataControl:masterList:_ctl0:enabled
    FindMeControl:MasterDataControl:masterList:_ctl0:itemGuid
    FindMeControl:MasterDataControl:btnAdd
    FindMeControl:MasterDataControl:btnDelete
    FindMeControl:MasterDataControl:btnRename
    FindMeControl:MasterDataControl:btnCancel
    FindMeControl:MasterDataControl:btnEnter
    FindMeControl:MasterDataControl:btnUpdate
    FindMeControl:MasterDataControl:hidSelectedScheduleName
    FindMeControl:MasterDataControl:hidbtnStatus
    FindMeControl:MasterDataControl:hidScheduleXML
    FindMeControl:MasterDataControl:tempScheduleXML
    FindMeControl:MasterDataControl:hidSelectedScheduleGUID
    FindMeControl:MasterDataControl:hidChangedScheduleList
    FindMeControl:btnApply
    FindMeControl:btnSchedules
    FindMeControl:btnPhoneLists
    FindMeControl:enableFindMeHidden
    FindMeControl:applySet

Elimine los campos de formulario innecesarios, complete el formulario y envíe:

In [29]: find_remove = (
'FindMeControl:MasterDataControl:btnAdd',
'FindMeControl:MasterDataControl:btnDelete',
'FindMeControl:MasterDataControl:btnRename',
'FindMeControl:MasterDataControl:btnCancel',
'FindMeControl:MasterDataControl:btnEnter',
'FindMeControl:MasterDataControl:btnUpdate',
'FindMeControl:btnApply',
'FindMeControl:btnSchedules')

In [30]: for i in find_remove:
        form_find_a.fields.pop(i)

In [31]: form_find_a['FindMeControl:enableFindMe'].value = 'on'
form_find_a['FindMeControl:MasterDataControl:focusElement'].value = ''
form_find_a['FindMeControl:MasterDataControl:masterList:_ctl0:enabled'].value = 'on'
form_find_a['FindMeControl:MasterDataControl:masterList:_ctl0:itemGuid'].value = ''
form_find_a['FindMeControl:MasterDataControl:hidSelectedScheduleName'].value = ''
form_find_a['FindMeControl:MasterDataControl:hidbtnStatus'].value = ''
form_find_a['FindMeControl:MasterDataControl:hidScheduleXML'].value = ''
form_find_a['FindMeControl:MasterDataControl:tempScheduleXML'].value = ''
form_find_a['FindMeControl:MasterDataControl:hidSelectedScheduleGUID'].value = ''
form_find_a['FindMeControl:MasterDataControl:hidChangedScheduleList'].value = ''
form_find_a['FindMeControl:btnPhoneLists'].value = 'Phone Lists'
form_find_a['FindMeControl:enableFindMeHidden'].value = ''
form_find_a['FindMeControl:applySet'].value = 'false'
Out [31]: ...

In [32]: m.submit_form(form_find_a)

Verificando que la página se ha actualizado y tiene el elemento de la lista "Trabajo":

In [33]: m.parsed.find('title')
Out[33]: <title>Phone Lists</title>

In [34]: m.parsed.find('a', id='PhoneListsControl_MasterDataControl_masterList__ctl0_SelectButton')
Out[34]: <a class="linkButtonItem" href="javascript:__doPostBack('PhoneListsControl$MasterDataControl$masterList$_ctl0$SelectButton','')" id="PhoneListsControl_MasterDataControl_masterList__ctl0_SelectButton" onclick="javascript:onClick();">Work</a>

Obtenga el formulario "PhoneLists.aspx", elimine los campos innecesarios, complete y envíe.

In [35]: form_find_b = m.get_form(action='PhoneLists.aspx')

In [36]: phne_remove = (
    'PhoneListsControl:MasterDataControl:btnAdd',
    'PhoneListsControl:MasterDataControl:btnDelete',
    'PhoneListsControl:MasterDataControl:bt,nRename',
    'PhoneListsControl:MasterDataControl:btnCancel',
    'PhoneListsControl:MasterDataControl:btnEnter',
    'PhoneListsControl:MasterDataControl:btnUpdate',
    'PhoneListsControl:btnApply',
    'PhoneListsControl:btnBack')

In [37]: for i in phne_remove:
            form_find_b.fields.pop(i)

In [38]: form_find_b['PhoneListsControl:MasterDataControl:focusElement'].value = ''             
form_find_b['PhoneListsControl:MasterDataControl:hidChangedScheduleList'].value = ''
form_find_b['PhoneListsControl:MasterDataControl:hidScheduleXML'].value = ''
form_find_b['PhoneListsControl:MasterDataControl:hidSelectedScheduleGUID'].value = ''
form_find_b['PhoneListsControl:MasterDataControl:hidSelectedScheduleName'].value = ''
form_find_b['PhoneListsControl:MasterDataControl:hidbtnStatus'].value = ''
form_find_b['PhoneListsControl:MasterDataControl:masterList:_ctl0:itemGuid'].value = ''
form_find_b['PhoneListsControl:MasterDataControl:tempScheduleXML'].value = ''
form_find_b['PhoneListsControl:applySet'].value = 'false'

In [39]: m.submit_form(form_find_b)

Revise la publicación para ver si la lista de usuarios está cargada. En este caso, no cargó la lista de usuarios.

In [40]: m.parsed.findAll('div', id='PhoneListsControl_phoneListMembersText')
Out[41]: [<div class="displayText" id="PhoneListsControl_phoneListMembersText"></div>]

Si fue exitoso lo anterior volvería:

<div id="PhoneListsControl_phoneListMembersText" class="displayText" style="top: 315px; left: 281px;">&nbsp;&nbsp;Work&nbsp;&nbsp;</div>

Junto con los siguientes elementos en una tabla, (PhoneListsControl_phoneListDetail):

<input name="PhoneListsControl:phoneListDetail:_ctl2:number" type="text" value="95551234567" maxlength="50" id="PhoneListsControl_phoneListDetail__ctl2_number" onkeyup="enableApplyButton('PhoneListsControl_')" style="width:140px;">
...
<input name="PhoneListsControl:phoneListDetail:_ctl3:number" type="text" value="95551236789" maxlength="50" id="PhoneListsControl_phoneListDetail__ctl2_number" onkeyup="enableApplyButton('PhoneListsControl_')" style="width:140px;">
...

En esta empresa descubrí que Robobrowser no incluye todos los datos de formulario necesarios para que la publicación en "PhoneLists.aspx" funcione como se esperaba, ('__EVENTTARGET':'PhoneListsControl$MasterDataControl$masterList$_ctl0$SelectButton' y__EVENTARGUMENT) Establecer los parámetros y luego hacersubmit_form(form_find_b) tampoco logra los resultados deseados. Me pregunto si eladd_field() derobobrowser.forms.form funcionaría, pero no entiendo cómo utilizarlo correctamente (si se va a utilizar como quisiera, por ejemplo, agregue el__EVENTTARGET y__EVENTARGUMENT campos de entrada ocultos al formulario).

¿Me falta algo más o RoboBrowser / Requests no admite este tipo de publicación? ¿Es que el formulario requiere JavaScript para ejecutarse como se menciona?aquí con mecanizar?

Respuestas a la pregunta(1)

Su respuesta a la pregunta