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.
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 + Cpara 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.
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.

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.
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.
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.
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.
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
importda funçãoelement_as_selectno 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.
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()






