Python - Solicitações / RoboBrowser - ASPX POST JavaScript

Estou portando um script bash que usa curl e POSTs as cargas úteis no código para os URLs e funciona. A questão básica é que, com o robobrowser, estou tendo problemas para postar usando os formulários da página.

Percorrendo o site:

Entre no /SubLogin.aspxO login bem-sucedido redireciona /OptionsSummary.aspxGET /FindMe.aspx com parâmetrosBotão POST /FindMe.aspx "Listas de telefones" (a página deve carregar a tabela "Listas de telefones" com o item "Trabalho")Selecionar o item "Trabalho" executa um POST para /PhoneLists.aspx (isso deve carregar uma tabela "Trabalho" com a lista de usuários.

Consegui me autenticar com sucesso no site e executar GETs com RoboBrowser e Requests + bs4, no entanto, estou confuso ao postar novamente nas próprias páginas.

Usando o 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

Entre no site e mostre o URL para verificar se estamos:

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" carregará um formulário e um botão "Listas de telefones", (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

Remova os campos não necessários, preencha o formulário e envie:

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)

Verifique se a página foi atualizada e se o item da lista "Trabalho":

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>

Obtenha o formulário "PhoneLists.aspx", remova os campos desnecessários, preencha e envie.

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 a postagem para ver se a lista de usuários foi carregada. Nesse caso, ele não carregou a lista de usuários.

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

E se foi bem sucedido o acima retornaria:

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

Juntamente com os seguintes itens em uma tabela (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;">
...

Nesse empreendimento, descobri que o Robobrowser não está incluindo todos os dados de formulário necessários para que a postagem em "PhoneLists.aspx" funcione conforme o esperado ('__EVENTTARGET':'PhoneListsControl$MasterDataControl$masterList$_ctl0$SelectButton' e__EVENTARGUMENT) Definir os parâmetros e depois fazersubmit_form(form_find_b) também não alcança os resultados desejados. Eu me pergunto se oadd_field() derobobrowser.forms.form funcionaria, mas não estou entendendo como utilizá-lo adequadamente (se for para ser usado como eu queria. por exemplo, adicione o__EVENTTARGET e__EVENTARGUMENT campos de entrada ocultos no formulário).

Estou faltando algo mais ou o RoboBrowser / Requests não é compatível com esse tipo de postagem? É que o formulário requer javascript para executar como mencionadoaqui com mecanizar?

questionAnswers(1)

yourAnswerToTheQuestion