Ir para o conteúdo

4: Desenvolvendo automação Web DOM

Cadastro de vagas de emprego no sistema

Nesse workshop você construirá uma automação que cadastra as vagas disponíveis em um sistema web de RH.

O processo consiste em:

  • Acessar o sistema web de RH (https://rpaexercise.aisingapore.org/login);
  • Fazer o login no sistema;
  • Clicar no botão de cadastro de vagas New Job Posting;
  • Preencher os campos do formulário de cadastro de vagas;
  • Salvar o cadastro da vaga Submit;
  • Repetir o processo para cada vaga disponível.

BotCity Web Inspector

Para esse workshop, vamos usar a ferramenta BotCity Web Inspector.

Com essa ferramenta conseguimos navegar, inspecionar elementos de páginas web e gerar a base do código Python, conforme as configurações desejadas.

Inspector Web

Uso básico

A ferramenta tem algumas funcionalidades e configurações, os principais são:

  • Page URL:

    Nesse campo passamos a URL da página que será acessada para inspeção.

  • Botão Start:

    Pressionando o botão Start, a ferramenta entra em modo de inspeção, abrindo o navegador na página definida, o cursor do mouse pode ser utilizado para selecionar os elementos da aplicação, veja que uma borda vermelha é exibida ao redor do elemento para identificação.

    Nesse momento clique no elemento ou pressione o atalho Alt + C para que o elemento seja inspecionado, mapeando ele.

    Você pode navegar e mapear todos os elementos antes de finalizar.

  • Botão Stop:

    Pressionando o botão Stop será finalizado o mapeamento de elementos e o navegador encerrado.

  • Botão Reset:

    Pressionando o botão reset, a ferramenta volta ao estado inicial, limpa os elementos e URL.

  • Janela Mapped Elements:

    Exibe os elementos mapeados, ou seja, os elementos selecionados na página web que serão utilizados para gerar o código. Ao clicar em cada um deles, será exibido suas respectivas informações. Também poderá excluí-los no ícone de lixeira.

  • Janela Property/Value:

    Exibe as propriedades e valores do elemento selecionado, como HTML Element, Tag Name, Id, etc. Esses valores podem servir para refatorar o código gerado, deixando-o mais resiliente.

  • Janela Code:

    Nessa janela podemos selecionar algumas propriedades para gerar o código, como: Seleção de navegador e duas checkbox para gerar código de configuração do navegador selecionado e iniciar o navegador na página definida em Page URL.

  • Botão Generate Code:

    Pressionando o botão Generate Code, o código será gerado com base nos elementos e configurações selecionadas.

Alternativa

Como alternativa, pode ser utilizada a inspeção de elementos manualmente no navegador, pressionando a tecla F12 ou clicando em inspecionar com o botão esquerdo do mouse na página.

Inspector

Lista de vagas

Para facilitar o preenchimento dos campos, utilize uma lista de vagas disponibilizada pela plataforma. Nesse momento, inserira essa lista no código do arquivo bot.py, logo após as configurações do navegador:

# Lista de informações das vagas
dados = [
    {
        "id":1,
        "jobTitle": "Training and Development Specialist",
        "jobDescription": "The responsibility of this role is to come up with structured programmes to meet the learning needs of employees.",
        "hiringDepartment": "Human Resource",
        "educationLevel": "Diploma",
        "postingStartDate": "12/10/2021",
        "postingEndDate": "30/11/2021",
        "remote": "No",
        "jobType": "Full-time"
    },
    {
        "id":2,
        "jobTitle": "Senior Software Engineer",
        "jobDescription": "This role participates in the full software development life cycle of internal enterprise applications.",
        "hiringDepartment": "Engineering",
        "educationLevel": "Degree",
        "postingStartDate": "15/10/2021",
        "postingEndDate": "14/11/2021",
        "remote": "Yes",
        "jobType": "Full-time/Permanent"
    },
    {
        "id":3,
        "jobTitle": "Accountant",
        "jobDescription": "The responsibility of this role is to provide the full spectrum of accounting support to the Head of Finance.",
        "hiringDepartment": "Finance",
        "educationLevel": "Degree",
        "postingStartDate": "24/11/2021",
        "postingEndDate": "23/12/2021",
        "remote": "No",
        "jobType": "Part-time/Temp"
    }
]

Nota

O formulário será validado se todas as informações estiverem iguais aos dados disponibilizados, caso algum dado esteja errado, aparecerá a seguinte informação ao final do formulário. erro de cadastro

Acessar o sistema

Como começar a automação, vamos acessar o sistema web de RH e fazer o login, utilizando o BotCity Web Inspector.

Abra o BotCity Web Inspector e preencha o campo Page URL com a URL do sistema de RH: https://rpaexercise.aisingapore.org/login. Em seguida, pressione o botão Start para iniciar a inspeção.

BotCity Web Inspector

Com o Inspector iniciado, identifique e clique nos campos necessários para o login, para mapeá-los: username e password.

Logo, coloque o mouse em cima do botão Login e pressione o atalho Alt + C para mapeá-lo também, sem clicar nele.

Esse processo deve gerar três elementos mapeados na janela Mapped Elements, como mostrado acima.

Gerar o código - login

Após mapear os elementos, vamos ter atenção para as configurações do código que será gerado. Na janela Code, marque apenas a opção Generate Code to start the browser, pois as configurações de navegador já foram feitas anteriormente no template do projeto.

Em seguida, no arquivo bot.py vá até uma linha vazia abaixo dos dados. Volte ao Inspector e pressione o botão Generate Code para gerar o código na linha selecionada.

O código gerado será semelhante a este:

# Starting browser
bot.browse("https://rpaexercise.aisingapore.org/login")

element = bot.find_element(selector='outlined-search', by=By.ID)
## Insert text content in the element
element.send_keys("")

element = bot.find_element(selector='password', by=By.ID)
## Insert text content in the element
element.send_keys("")

element = bot.find_element(selector='login', by=By.ID)
## Perform a default click action on the element
element.click()

# Stopping the browser
bot.wait(3000)
bot.stop_browser()

Refatorar o código

Tenha atenção às linhas destacadas. Nelas vamos fazer algumas alterações.

Coloque os valores no método send_keys():

  • No primeiro elemento retornado, username: jane007
  • No segundo elemento retornado, password: TheBestHR123

O último trecho de código temos o encerramento do navegador, porém ainda não finalizamos o processo, então ele pode ser apagado.

O código refatorado ficará assim:

# Starting browser
bot.browse("https://rpaexercise.aisingapore.org/login")

element = bot.find_element(selector='outlined-search', by=By.ID)
## Insert text content in the element
element.send_keys("jane007")

element = bot.find_element(selector='password', by=By.ID)
## Insert text content in the element
element.send_keys("TheBestHR123")

element = bot.find_element(selector='login', by=By.ID)
## Perform a default click action on the element
element.click()

Agora faça um teste executando o código no terminal com o comando python bot.py e verifique se o login é realizado corretamente.

Cadastrar vagas

Agora que o login foi realizado com sucesso, vamos cadastrar as vagas disponíveis no sistema.

Com o Inspector ainda aberto, faça o login manualmente para ir até a página de cadastro de vagas. Lembre-se de limpar os elementos do Inspector clicando no ícone de lixeira.

Agora, mapeie o botão New Job Posting , com o mouse em cima do elemento, pressionando o atalho Alt + C.

BotCity Web Inspector

Gerar o código - abrir o form

Dessa vez, desmarque todas as checkboxes na janela Code para gerar apenas o código do elemento mapeado.

No arquivo bot.py vá até uma linha vazia abaixo dos elementos de login. Volte ao Inspector e pressione o botão Generate Code para gerar o código na linha selecionada.

O código gerado será semelhante a este:

element = bot.find_element(selector='newJobPosting', by=By.ID)
## Perform a default click action on the element
element.click()

Criar repetição

A partir de agora, precisamos criar uma repetição, pois vamos cadastrar várias vagas, uma para cada item da lista de vagas que criamos anteriormente. Utilize a estrutura for para clicar em abrir o formulário e percorrer a lista de vagas e preencher os campos do formulário.

O acesso às informações de cada vaga será feito através da variável vaga, que representa o item atual da lista dados. Veja o exemplo de acesso ao título da vaga:

for vaga in dados:
    # Identifica e clica no botão "New Job Posting"
    element = bot.find_element(selector='newJobPosting', by=By.ID)
    element.click()

    # Acesso às informações da vaga atual
    print(vaga["jobTitle"])
    ...

Gerar o código - preencher o form

Nessa etapa, o formulário de cadastro está aberto, vamos mapear os campos que precisam ser preenchidos.

Para isso, posicione o mouse em cima de cada elemento e clique para carregá-lo no Inspector.

BotCity Web Inspector

Nota

Atenção ao mapeamento dos campos, eles devem ser do tipo input, textarea, select, radio ou checkbox, pois são os tipos de campos que podem ser preenchidos.

Mapeie todos os campos do tipo radio e checkbox.

BotCity Web Inspector

O código gerado será semelhante a este:

element = bot.find_element(selector='jobTitle', by=By.ID)
## Insert text content in the element
element.send_keys("")

element = bot.find_element(selector='jobDescription', by=By.ID)
## Insert text content in the element
element.send_keys("")

element = bot.find_element(selector='hiringDepartment', by=By.ID)
## Converting the element to a select element
from botcity.web.util import element_as_select
select_element = element_as_select(element)

## Select the option by index or value
select_element.select_by_index(index=0)
select_element.select_by_value(value="")

element = bot.find_element(selector='educationLevel', by=By.ID)
## Converting the element to a select element
from botcity.web.util import element_as_select
select_element = element_as_select(element)

## Select the option by index or value
select_element.select_by_index(index=0)
select_element.select_by_value(value="")

element = bot.find_element(selector='postingStartDate', by=By.ID)
## Insert text content in the element
element.send_keys("")

element = bot.find_element(selector='postingEndDate', by=By.ID)
## Insert text content in the element
element.send_keys("")

element = bot.find_element(selector='//input[@class="jss17" and @name="remote" and @type="radio"]', by=By.XPATH)
## Perform a default click action on the element
element.click()

element = bot.find_element(selector='//input[@class="jss17" and @name="remote" and @type="radio"]', by=By.XPATH)
## Perform a default click action on the element
element.click()

element = bot.find_element(selector='jobTypeFullTime', by=By.ID)
## Perform a default click action on the element
element.click()

element = bot.find_element(selector='jobTypePartTime', by=By.ID)
## Perform a default click action on the element
element.click()

element = bot.find_element(selector='jobTypeTemp', by=By.ID)
## Perform a default click action on the element
element.click()

element = bot.find_element(selector='jobTypePermanent', by=By.ID)
## Perform a default click action on the element
element.click()

Refatorar o código

Com os elementos mapeados, vamos fazer o preenchimento dos campos com as informações da vaga atual. Além disso, vamos colocar alguns tratamentos no código para seleção correta dos campos Remote e Job Type.

send_keys nos campos de texto

Substitua os valores dos campos send_keys() pelos valores correspondentes da vaga atual, utilizando a variável vaga['campo'], como por exemplo:

element = bot.find_element(selector='jobTitle', by=By.ID)
## Insert text content in the element
element.send_keys(vaga['jobTitle'])

select nos campos de seleção

Note que nos campos do tipo select, automaticamente o BotCity Web Inspector já importou a função element_as_select para converter o elemento em um elemento do tipo select, então você pode utilizar os métodos select_by_index() ou select_by_value() para selecionar a opção desejada.

Vamos fazer as seguintes ações:

  • Colocar o import da função element_as_select no início do código.
  • Deletar a linha com o método select_by_index().
  • Utilizar o método select_by_value(vaga["campo"]).

Exemplo:

element = bot.find_element(selector='hiringDepartment', by=By.ID)
## Converting the element to a select element
select_element = element_as_select(element)

## Select the option by index or value
select_element.select_by_value(value=vaga['hiringDepartment'])

Atenção

Não esqueça de remover todos os import no meio do código, eles devem ficar todos no início do arquivo.

Campos do tipo radio

No caso dos campos do tipo radio, vamos utilizar o método click() para selecionar a opção desejada. Para isso, precisamos verificar se o valor da vaga é remota ou não, para selecionar a opção correta.

Note que ao mapear o campo Remote, o BotCity Web Inspector gerou dois elementos com seletores iguais, então vamos modificar o seletor, adicionando and @value="No" e and @value="Yes" para diferenciá-los.

Outro ponto importante é notar que o seletor @class="jss17" é dinâmico, ou seja, pode mudar a cada execução. Por isso, vamos removê-lo.

O código ficará assim:

if vaga["remote"] == "No":
    element = bot.find_element(selector='//input[@name="remote" and @type="radio" and @value="No"]', by=By.XPATH)
    ## Perform a default click action on the element
    element.click()
elif vaga["remote"] == "Yes":
    element = bot.find_element(selector='//input[@name="remote" and @type="radio" and @value="Yes"]', by=By.XPATH)
    ## Perform a default click action on the element
    element.click()

Campos do tipo checkbox

Nesses campos também precisamos verificar quais os tipos de trabalho disponíveis para a vaga atual e selecionar as opções corretas. Lembrando que uma vaga pode ter mais de uma opção selecionada.

if 'Full-time' in vaga["jobType"]:
    element = bot.find_element(selector='jobTypeFullTime', by=By.ID)
    ## Perform a default click action on the element
    element.click()
if 'Part-time' in vaga["jobType"]:
    element = bot.find_element(selector='jobTypePartTime', by=By.ID)
    ## Perform a default click action on the element
    element.click()
if 'Temp' in vaga["jobType"]:
    element = bot.find_element(selector='jobTypeTemp', by=By.ID)
    ## Perform a default click action on the element
    element.click()
if 'Permanent' in vaga["jobType"]:
    element = bot.find_element(selector='jobTypePermanent', by=By.ID)
    ## Perform a default click action on the element
    element.click()

Gerar o código - salvar o form

Após preencher todos os campos, vamos salvar o formulário. Para isso, mapeie o botão Submit ao final do formulário.

BotCity Web Inspector

Com o elemento mapeado, clique no botão Generate Code para gerar o código abaixo do último campo preenchido, ainda dentro do laço de repetição.

O código gerado será semelhante a este:

element = bot.find_element(selector='submit', by=By.ID)
## Perform a default click action on the element
element.click()

Finalizar o processo

Agora que o formulário foi preenchido e salvo, vamos finalizar o processo de cadastro de vagas. Para isso o tempo de espera e, em seguida, encerramento o navegador que estava ao final do template será mantido.

# Wait 3 seconds before closing
bot.wait(3000)

# Finish and clean up the Web Browser
# You MUST invoke the stop_browser to avoid
# leaving instances of the webdriver open
bot.stop_browser()

Código final

Para finalizar, podemos limpar alguns comentários repetidos e adicionar comentários para melhor entendimento.

O código final do arquivo bot.py ficará semelhante a este:

# Import do WebBot
from botcity.web import WebBot, Browser, By

# Import da integração com Orquestrador BotCity
from botcity.maestro import *

# Flag para executar localmente sem erro de autenticação
BotMaestroSDK.RAISE_NOT_CONNECTED = False

# Import do WebDriver Manager para Firefox
from webdriver_manager.firefox import GeckoDriverManager

# Import da função para converter elemento em select
from botcity.web.util import element_as_select


def main():
    # Conecta ao Orquestrador BotCity quando executado via Runner
    maestro = BotMaestroSDK.from_sys_args()
    # Retorna informações da execução
    execution = maestro.get_execution()

    print(f"Task ID is: {execution.task_id}")
    print(f"Task Parameters are: {execution.parameters}")

    bot = WebBot()

    # Configura modo headless do navegador
    bot.headless = False

    # Seleciona o navegador a ser utilizado
    bot.browser = Browser.FIREFOX

    # Instala o GeckoDriver para o Firefox
    bot.driver_path = GeckoDriverManager().install()


    # Lista de informações das vagas
    dados = [
        {
            "id":1,
            "jobTitle": "Training and Development Specialist",
            "jobDescription": "The responsibility of this role is to come up with structured programmes to meet the learning needs of employees.",
            "hiringDepartment": "Human Resource",
            "educationLevel": "Diploma",
            "postingStartDate": "12/10/2021",
            "postingEndDate": "30/11/2021",
            "remote": "No",
            "jobType": "Full-time"
        },
        {
            "id":2,
            "jobTitle": "Senior Software Engineer",
            "jobDescription": "This role participates in the full software development life cycle of internal enterprise applications.",
            "hiringDepartment": "Engineering",
            "educationLevel": "Degree",
            "postingStartDate": "15/10/2021",
            "postingEndDate": "14/11/2021",
            "remote": "Yes",
            "jobType": "Full-time/Permanent"
        },
        {
            "id":3,
            "jobTitle": "Accountant",
            "jobDescription": "The responsibility of this role is to provide the full spectrum of accounting support to the Head of Finance.",
            "hiringDepartment": "Finance",
            "educationLevel": "Degree",
            "postingStartDate": "24/11/2021",
            "postingEndDate": "23/12/2021",
            "remote": "No",
            "jobType": "Part-time/Temp"
        }
    ]


    # Inicia o navegador e acessa a página de login
    bot.browse("https://rpaexercise.aisingapore.org/login")

    # Realiza o login no sistema
    element = bot.find_element(selector='outlined-search', by=By.ID)
    element.send_keys("jane007")

    element = bot.find_element(selector='password', by=By.ID)
    element.send_keys("TheBestHR123")

    element = bot.find_element(selector='login', by=By.ID)
    element.click()

    # Faz um laço de repetição para cada vaga na lista de dados
    for vaga in dados:
        # Clica no botão que abre o formulário
        element = bot.find_element(selector='newJobPosting', by=By.ID)
        element.click()

        # Preenche o formulário com as informações da vaga
        element = bot.find_element(selector='jobTitle', by=By.ID)
        element.send_keys(vaga['jobTitle'])

        element = bot.find_element(selector='jobDescription', by=By.ID)
        element.send_keys(vaga['jobDescription'])

        element = bot.find_element(selector='hiringDepartment', by=By.ID)
        select_element = element_as_select(element)
        select_element.select_by_value(value=vaga['hiringDepartment'])

        element = bot.find_element(selector='educationLevel', by=By.ID)
        select_element = element_as_select(element)
        select_element.select_by_value(value=vaga['educationLevel'])

        element = bot.find_element(selector='postingStartDate', by=By.ID)
        element.send_keys(vaga['postingStartDate'])

        element = bot.find_element(selector='postingEndDate', by=By.ID)
        element.send_keys(vaga['postingEndDate'])

        # Verifica o campo Remote e clica no radio button correspondente
        if vaga["remote"] == "No":
            element = bot.find_element(selector='//input[@name="remote" and @type="radio" and @value="No"]', by=By.XPATH)
            ## Perform a default click action on the element
            element.click()
        elif vaga["remote"] == "Yes":
            element = bot.find_element(selector='//input[@name="remote" and @type="radio" and @value="Yes"]', by=By.XPATH)
            ## Perform a default click action on the element
            element.click()

        # Verifica o tipo de trabalho e clica nos checkboxes correspondentes
        if 'Full-time' in vaga["jobType"]:
            element = bot.find_element(selector='jobTypeFullTime', by=By.ID)
            element.click()
        if 'Part-time' in vaga["jobType"]:
            element = bot.find_element(selector='jobTypePartTime', by=By.ID)
            element.click()
        if 'Temp' in vaga["jobType"]:
            element = bot.find_element(selector='jobTypeTemp', by=By.ID)
            element.click()
        if 'Permanent' in vaga["jobType"]:
            element = bot.find_element(selector='jobTypePermanent', by=By.ID)
            element.click()

        # Clica em "Submit" para salvar o formulário
        element = bot.find_element(selector='submit', by=By.ID)
        element.click()

    # Aguarda 3 segundos antes de fechar o navegador
    bot.wait(3000)

    # Finaliza e encerra o navegador
    bot.stop_browser()

    # Método de finalização da tarefa no Orquestrador BotCity
    # maestro.finish_task(
    #     task_id=execution.task_id,
    #     status=AutomationTaskFinishStatus.SUCCESS,
    #     message="Task Finished OK.",
    #     total_items=0,
    #     processed_items=0,
    #     failed_items=0
    # )


if __name__ == '__main__':
    main()