Estou usando o CasperJS para automatizar uma série de cliques, formulários preenchidos, análise de dados, etc. através de um site.
Casper parece ser organizado em uma lista de etapas predefinidas na forma de then
instruções (veja o exemplo deles aqui: http://casperjs.org/quickstart.html ), mas não está claro o que aciona a próxima instrução para realmente ser executada.
Por exemplo, then
aguarda a conclusão de todas as solicitações pendentes? Conta injectJS
como um pedido pendente? O que acontece se eu tiver uma then
instrução aninhada - encadeada ao final de uma open
instrução?
casper.thenOpen('http://example.com/list', function(){
casper.page.injectJs('/libs/jquery.js');
casper.evaluate(function(){
var id = jQuery("span:contains('"+itemName+"')").closest("tr").find("input:first").val();
casper.open("http://example.com/show/"+id); //what if 'then' was added here?
});
});
casper.then(function(){
//parse the 'show' page
});
Estou procurando uma explicação técnica de como funciona o fluxo no CasperJS. Meu problema específico é que minha última then
declaração (acima) é executada antes da minha casper.open
declaração e não sei por quê.
fonte
flow
sobre casperjs, mas descobri que basicamente você não pode fazer referência a casper em umaevaluate
chamada. (ou seja, você não pode abrir um novo url, log, echo, etc). Portanto, no meu caso, a avaliação estava sendo chamada, mas não havia como interagir com o mundo externo.evaluate()
é para código que roda no "navegador", no DOM da página que o phantomjs está navegando. Portanto, não hácasper.open
lá, mas pode haver jQuery. Portanto, seu exemplo não faz sentido, mas ainda me pergunto o quethen()
realmente faz.Respostas:
then()
basicamente adiciona uma nova etapa de navegação em uma pilha. Uma etapa é uma função javascript que pode fazer duas coisas diferentes:Vejamos um cenário de navegação simples:
Você pode imprimir todas as etapas criadas dentro da pilha assim:
Isso dá:
Observe a
_step()
função que foi adicionada automaticamente pelo CasperJS para carregar a url para nós; quando o url é carregado, a próxima etapa disponível na pilha - que éstep3()
- é chamada.Depois de definir suas etapas de navegação,
run()
execute-as uma a uma sequencialmente:Nota de rodapé: o material de callback / listener é uma implementação do padrão Promise .
fonte
then()
simplesmente registra uma série de etapas.run()
e sua família de funções de execução, retornos de chamada e ouvintes são os que realmente fazem o trabalho de execução de cada etapa.Sempre que uma etapa é concluída, CasperJS irá verificar contra 3 bandeiras:
pendingWait
,loadInProgress
, enavigationRequested
. Se algum desses sinalizadores for verdadeiro, não faça nada, fique ocioso até um momento posterior (setInterval
estilo). Se nenhum desses sinalizadores for verdadeiro, a próxima etapa será executada.A partir do CasperJS 1.0.0-RC4, existe uma falha, onde, sob certas circunstâncias baseadas no tempo, o método "tentar fazer a próxima etapa" será acionado antes que o CasperJS tenha tempo para levantar uma das bandeiras
loadInProgress
ounavigationRequested
. A solução é levantar uma dessas bandeiras antes de sair de qualquer etapa em que se espera que essas bandeiras sejam levantadas (ex: levante uma bandeira antes ou depois de pedir umcasper.click()
), talvez assim:(Nota: Isto é apenas ilustrativo, mais como psuedocode do que a forma CasperJS adequada ...)
Para resumir essa solução em uma única linha de código, eu apresentei
blockStep()
neste github pull request , estendendoclick()
eclickLabel()
como um meio de ajudar a garantir que obteremos o comportamento esperado ao usarthen()
. Verifique a solicitação para obter mais informações, padrões de uso e arquivos de teste mínimos.fonte
blockStep
, IMHODe acordo com a documentação do CasperJS :
then()
Assinatura:
then(Function then)
Nos bastidores, o código-fonte do
Casper.prototype.then
é mostrado abaixo:Explicação:
Em outras palavras,
then()
programa a próxima etapa do processo de navegação.Quando
then()
é chamado, é passada uma função como parâmetro que deve ser chamada como uma etapa.Ele verifica se uma instância foi iniciada e, se não foi, exibe o seguinte erro:
Em seguida, ele verifica se o
page
objeto énull
.Se a condição for verdadeira, Casper cria um novo
page
objeto.Após isso,
then()
valida ostep
parâmetro para verificar se não é uma função.Se o parâmetro não for uma função, ele exibe o seguinte erro:
Então, a função verifica se o Casper está rodando.
Se Casper não estiver funcionando,
then()
anexa a etapa ao final da fila.Caso contrário, se Casper estiver em execução, ele insere uma subetapa um nível mais profundo do que a etapa anterior.
Finalmente, a
then()
função conclui emitindo umstep.added
evento e retorna o objeto Casper.fonte