Lab 1.5: Desenvolvendo automações Web com DOM
Automações Web são limitadas ao escopo do navegador. Com isso, apesar de não ser possível interagir com elementos fora desse contexto, podemos interagir com o navegador em maior profundidade.
Podemos manipular mouse e teclado como na automação Desktop, além disso, podemos também executar código em JavaScript e interagir com elementos da DOM.
Automações Web também podem ser executadas em modo Headless (plano de fundo) e em paralelo com outras atividades sem interromper ou bloquear recursos de outras tarefas.
BotCity Web Inspector
Para esse treinamento, 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 + 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 que foram selecionados e que serão utilizados para gerar o código. Também é possível selecionar os diferentes elementos selecionados para visualizar as informações ou 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, se deve gerar código para configurar o navegador ou iniciar o navegador.
-
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. Abrindo o navegador e pressionando a tecla F12
.
Coletando informações de canais de YouTube
Para esse Lab, vamos desenvolver uma automação web que acessa canais de YouTube e coleta informações sobre cada um deles, ao final mostra na tela as informações de nome do canal, número de inscritos e quantidade de vídeos.
Criando um projeto usando o template BotCity
A BotCity oferece templates de projeto que podem ser criados e customizados através do cookiecutter.
Para instalarmos o pacote do cookiecutter
, vamos executar o seguinte comando:
python -m pip install --upgrade cookiecutter
Para criarmos um projeto usando o modelo, vamos invocar o cookiecutter
e fornecer como argumento a URL do repositório onde os templates da BotCity estão localizados:
python -m cookiecutter https://github.com/botcity-dev/bot-python-template/archive/v2.zip
O sistema solicitará algumas respostas para criar seu projeto:
- project_type:
2
| Tipo de projeto Web. - bot_id:
BotYoutube
| Nome do projeto.
Após o término do processo acima, uma nova pasta chamada BotYoutube
estará disponível.
Sucesso
Parabéns, você agora tem um projeto com o framework Python da BotCity. 🏆
Entenda o que são os arquivos no projeto de exemplo
Ao obter o projeto, uma pasta com o nome BotYoutube é criada. Ao abrir a pasta, há os seguintes arquivos:
BotYoutube
├── bot.py <- Arquivo onde iremos trabalhar e desenvolver nosso robô.
├── resources <- Pasta contendo os arquivos auxiliares para o robô.
├── build.bat <- Script em Batch para gerar o pacote.
├── build.ps1 <- Script em PowerShell para gerar o pacote.
├── build.sh <- Shell script para gerar o pacote.
├── requirements.txt <- Arquivo descrevendo todas as dependências externas para seu robô.
└── BotYoutube.botproj <- Arquivo utilizado para carregar o projeto no BotStudio.
Finalmente, temos um modelo de projeto Web criado. Nos próximos passos vamos desenvolver o projeto através de inspeção de elementos de páginas web.
Baixando o WebDriver
Para trabalhar com automações web, precisamos usar o WebDriver correspondente ao navegador que está sendo utilizado na automação.
Utilizaremos o navegador Firefox para essa automação, portanto precisamos baixar o Geckodriver
disponível deste link.
Você pode utilizar outros navegadores, como:
Configurando o caminho do WebDriver
No arquivo principal bot.py
do template, vamos fazer a configuração do Geckodriver
para esse projeto alterando as seguintes linhas:
bot.browser
: Seleciona o navegador Chromebot.driver_path
: Informa o caminho do Webdriver (para facilitar coloque dentro da pasta resources)
...
def main():
bot = WebBot()
# Configurando para rodar no modo headless
bot.headless = False
# Setando navegador padrão para o Chrome
bot.browser = Browser.FIREFOX
# Setando o caminho do WebDriver do Chrome
bot.driver_path = r"resources\geckodriver.exe"
...
Sucesso
Toda essa informação é bem legal, mas é hora de vermos alguma ação.
Vamos testar nosso robô localmente. 🦾🤖
Criando ambiente isolado
Como boa prática, criaremos um ambiente virtual isolado para essa automação, evitando problema como diferentes versões de dependências. Para isso abra o terminal na pasta do projeto e use os seguintes comandos:
Cria o ambiente:
python -m venv venv
Ativa o ambiente:
venv\Scripts\activate
Cria o ambiente:
python -m venv venv
Ativa o ambiente:
source venv/bin/activate
Instalando as dependências no projeto
Vamos fazer a instalação das dependencias listadas no arquivo requirements.txt
dentro do ambiente isolado com o seguinte comando:
python -m pip install -r requirements.txt
Navegando na página com Inspector
Vamos abrir o inspector para começar a navegar e capturar os elementos necessários, precisamos das seguintes informações:
- Nome do canal
- Número de inscritos
- Quantidade de vídeos
Coletando as informações da página
Para abrir o Inspector, clique no ícone da extensão BotCity no VSCode, e em seguida, clique no botão Launch Web Inspector.
Com a janela aberta, insira a URL que deseja inspecionar e clique em Start para iniciar o navegador.
- url:
https://www.youtube.com/@botcity_br
Ficará semelhante à imagem abaixo:
Nesse momento, procure com o mouse os elementos necessários, eles ficarão marcados com uma borda vermelha. Ao encontrá-los, clique diretamente no elemento ou pressione Alt + C
com o mouse em cima do elemento para mapea-lo. Ele aparecerá no painel Mapped Elements.
Dica
Para esse caso específico, o elemento com o número de inscritos retorna todas as informações que precisamos, vamos usar esse elemento.
Após selecionar todos os elementos necessários, verifique as configurações:
- Generate code with browser setup: Desmarcado
- Generate code to start the browser: Marcado
Como já configuramos o navegador, não é necessário selecionar essa opção.
Volte no VSCode e clique na linha onde quer que o código seja gerado, logo após as configurações iniciais que fizemos anteriormente, em seguida clique em Generate Code.
O código ficará semelhante ao abaixo:
# Starting browser
bot.browse("https://www.youtube.com/@botcity_br")
element = bot.find_element(selector='//span[@class="yt-core-attributed-string yt-content-metadata-view-model-wiz__metadata-text yt-core-attributed-string--white-space-pre-wrap yt-core-attributed-string--link-inherit-color" and @role="text"]', by=By.XPATH)
## Getting text property, you can access other properties through the WebElement object
# print(element.text)
# Stopping the browser
bot.wait(3000)
bot.stop_browser()
Refatorando o código
Ao selecionar o elemento com o número de inscritos, podemos refatorar o código gerado para capturar as informações da seguinte maneira:
- método:
find_element() -> find_elements()
- variável:
adiciona -> nome_canal = element[0].text
- variável:
adiciona -> numero_inscritos = element[1].text
- variável:
adiciona -> quantidade_videos = element[2].text
Dica
O método find_element()
retorna somente um elemento com o seletor indicado, já o find_elements()
retorna uma lista de elementos com o mesmo seletor e podemos acessar cada um deles através do índice da lista.
# Retorna lista de elementos
element = bot.find_elements(selector='//span[@class="yt-core-attributed-string yt-content-metadata-view-model-wiz__metadata-text yt-core-attributed-string--white-space-pre-wrap yt-core-attributed-string--link-inherit-color" and @role="text"]', by=By.XPATH)
# Captura o texto de cada elemento
nome_canal = element[0].text
numero_inscritos = element[1].text
quantidade_videos = element[2].text
Pesquisando outros canais
Vamos criar uma lista com o nome de outros canais para pesquisar e coletar as essas informações.
- canais:
canais = ['botcity_br', 'botcity-dev', 'youtube', 'github']
Agora criaremos um laço de repetição para iterar sobre a lista e repetir o processo criado acima. Também vamos alterar a URL para pesquisar o canal atual, adicionando uma string formatada. No final, vamos imprimir as informações coletadas de cada canal.
O código ficará semelhante ao abaixo:
for canal in canais:
# Inicia o navegador
bot.browse(f"https://www.youtube.com/@{canal}")
# Retorna lista de elementos
element = bot.find_elements(selector='//span[@class="yt-core-attributed-string yt-content-metadata-view-model-wiz__metadata-text yt-core-attributed-string--white-space-pre-wrap yt-core-attributed-string--link-inherit-color" and @role="text"]', by=By.XPATH)
# Captura o texto de cada elemento
nome_canal = element[0].text
numero_inscritos = element[1].text
quantidade_videos = element[2].text
print(f"Nome do canal: {nome_canal} | Número de inscritos: {numero_inscritos} | Quantidade de vídeos: {quantidade_videos}")
# Finaliza o navegador
bot.wait(3000)
bot.stop_browser()
Código completo do projeto
# Import de Web Bot
from botcity.web import WebBot, Browser, By
# Import de integração com BotCity Maestro SDK
from botcity.maestro import *
# Desativa mensagem de erros por não estar conectado ao Maestro
BotMaestroSDK.RAISE_NOT_CONNECTED = False
def main():
# Instancia do BotMaestroSDK
maestro = BotMaestroSDK.from_sys_args()
# Objeto com 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ção do modo headless
bot.headless = False
# Configuração do navegador
bot.browser = Browser.FIREFOX
# Caminho para o webdriver
bot.driver_path = r"resources\geckodriver.exe"
# Lista de canais para pesquisar
canais = ['botcity_br', 'botcity-dev', 'youtube', 'github']
for canal in canais:
# Inicia o navegador
bot.browse(f"https://www.youtube.com/@{canal}")
# Retorna lista de elementos
element = bot.find_elements(selector='//span[@class="yt-core-attributed-string yt-content-metadata-view-model-wiz__metadata-text yt-core-attributed-string--white-space-pre-wrap yt-core-attributed-string--link-inherit-color" and @role="text"]', by=By.XPATH)
# Captura o texto de cada elemento
nome_canal = element[0].text
numero_inscritos = element[1].text
quantidade_videos = element[2].text
print(f"Nome do canal: {nome_canal} | Número de inscritos: {numero_inscritos} | Quantidade de vídeos: {quantidade_videos}")
# Finaliza o navegador
bot.wait(3000)
bot.stop_browser()
if __name__ == '__main__':
main()
Nome do canal: @botcity_br | Número de inscritos: 1,11 mil inscritos | Quantidade de vídeos: 45 vídeos
Nome do canal: @botcity-dev | Número de inscritos: 1,54 mil inscritos | Quantidade de vídeos: 22 vídeos
Nome do canal: @YouTube | Número de inscritos: 42,8 mi de inscritos | Quantidade de vídeos: 928 vídeos
Nome do canal: @GitHub | Número de inscritos: 456 mil inscritos | Quantidade de vídeos: 2,1 mil vídeos
Desafio
Desenvolvemos uma automação web que acessa canais de YouTube e coleta informações sobre cada um deles, ao final mostra na tela as informações de nome do canal, número de inscritos e quantidade de vídeos.
Como desafio, faça melhorias no código, como:
- Navegar na página com BotCity Web Inspector e coletar informações diferentes;
- Separar responsabilidades em funções;
- Adicionar tratamento de exceções;
- Adicionar canais dinamicamente;
- Estruturar a saida das informações em um arquivo CSV: