Robotlarınızı Selenium-Grid ile Docker Üzerinde Paralel Çalıştırma

Robotik Süreç Otomasyonu tekrarlı ve adımları belirli olan süreçlerin otomatize edilmesi için kullanılan bir teknolojidir. Bu teknoloji sayesinde kullanıcılar daha değerli ve insan dokunuşu gereken işlere ve müşterilere daha fazla vakit ayırabilmektedir. Diğer bir deyişle, Robotik Süreç Otomasyon’u size daha değerli işler işe uğraşmak için vakit oluşturur.

Docker uygulamaların paketlenerek üretim ortamına tüm gereksinimleri ile birlikte aktarılmasını sağlayan ve kolaylaştıran bir teknolojidir. Docker ile ilgili detaylı bilgiye bu siteden erişebilirsiniz.

Selenium fiyat analizi, rapor oluşturma ve müşterilere farklı ürün tanımlamaları yapmak gibi web süreçlerini otomatikleştirmek için kullanılır. Aslında Selenium’un çıkış amacı GUI testlerini gerçekleştirmek olsa bile, Selenium web süreçlerini otomatikleştirmek için oldukça uygun bir araçtır. Burada bulunan bir örnek uygulama ile Selenium hakkında detaylı bilgiye erişebilirsiniz. Selenium-Grid ise yazılım testlerinin Selenium-Hub adı verilen bir yönetici tarafında dağıtık olarak farklı makinalarda çalıştırılmasını sağlayan bir araçtır. Selenium-Grid temel olarak iki unsurdan meydana gelmektedir:

  • Hub: Kod ve web tarayıcıları arasında bulunan bir köprü niteliğindedir ve kodun hangi ortamda ve sunucuda çalıştırılacağının kararını verir. Her Selenium-Grid ağında yalnızca bir adet Hub bulunmalıdır.
  • Node: Hub tarafından iletilen kodun işletildiği ortamdır. Her bir Node farklı işletim sistemler ve tarayıcılar ihtiva edebilir. Node’lar ağ üzerinde birden fazla bulunabilirler.

Bu yazımızda, sizlerle birlikte, yazılım robotlarını Selenium tarafından sağlanan Docker konteynırları (İng. containers) üzerinde çalıştıracağız. Gereksinimler aşağıda belirtildiği gibidir:

  • Docker 19.03.12
  • Docker Compose 1.126
  • Python 3.6.9
  • VNC Viewer

Ağ Oluşturma

Hub ve Node’ların iletişim kurabilmeleri için Docker üzerinde bir ağ oluşturmamız gerekmektedir. Docker yüklendiğinde varsayılan olarak aşağıda görülen ağlar oluşturulmaktadır. Bu ağları listelemek için komut satırından docker network ls komutunu vermeniz yeterlidir.

docker network

docker network create grid komut ile birilikte grid adında bir ağ oluşturabilirsiniz. Ağın oluşturulduğunu görmek için docker network ls ağları yeniden listeleyebilirsiniz.

docker network create grid

docker network inspect grid komutu ile oluşturduğunuz grid ağının içeriğini ve özelliklerini görebilirsiniz. Şu ana kadar herhangi bir konteynır oluşturmadığımız için ağ üzerinde bir konteynır tanımlı değildir.

docker network inspect grid

Hub ve Node’ların Çalıştırılması

Bu yazımızda robotlarımızı çalıştırmak için bir adet Hub ve Chrome tarayıcı içeren iki adet Node kullanacağız.

Aşağıda görülen kod ile selenium/hub imajının son versiyonundan selenium-hub adında bir konteynır çalıştırır. İmaj eğer sistem yok ise öncelikle Docker-Hub’tan indirilir. Konsol kapatıldıktan sonra bile konteynırın çalışması için -d komutu verilmelidir. Hub oluşturulduktan sonra tarayıcı üzerinden erişebilmek için 4444 numaralı port ile yerel makinanın 4444 numaralı portu eşleştirilir.

docker run -d -p 4444:4444 --net grid --name selenium-hub selenium/hub

Aşağıda bulunan komutlar ile VNC bağlantı özelliği sağlayan iki adet Node konteynırı çalıştırılır. VNC bağlantısı kurabilmek için Node’ların 5900 numaralı VNC portları yerel makinanın 5900 ve 5901 portları ile eşleştirilir.

docker run -d -p 5900:5900 --net grid --name chrome-debug -e HUB_HOST=selenium-hub selenium/node-chrome-debug 
docker run -d -p 5901:5900 --net grid --name chrome-debug2 -e HUB_HOST=selenium-hub selenium/node-chrome-debug

Buraya kadar herşey yolunda gittiği takdirde, docker network inspect grid komutu ile aşağıdaki görsele benzer bir sonuç elde etmeniz gerekmektedir.

selenium hub

Ayrıca tarayıcıdan localhost:4444/grid/console adresini ziyaret ederek çalışan Node’ları görebilirsiniz.

grid console sonuç

Buraya kadar yapılanları kod dosyaları içerisinde bulunan create_grid.sh betiğinin chmod +x komutu ile çalıştırılabilir hale getirilerek çalıştırılması ile kolayca yapabilirsiniz.

Otomasyon Robotu

scraper.py isimli yazılım robotumuz aşağıda bulunan kod satırlarında verilmiştir. Robot basitçe verilen terimi Google üzerinde arar ve çıkan sonuç sayfasında ilk sıradaki sayfanın bağlantısını alır. Ardından terim ve bağlantı ikilisini ismi IP adresi olan bir dosyaya yazar. Eğer dosya halihazırda mevcut ise öncelikle dosyadaki bilgileri alır ve bulduğu sonucu bu dosyaya aktarır.

Robot’un ihtiyaç duyduğu modülleri pip3 install -r requirements.txt komutunu çalıştırarak kolayca yükleyebilirsiniz.

					

import os
import random
import sys
from time import sleep


import pandas as pd
import requests
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.common.keys import Keys


def scrapper(search_term):
    host = "http://localhost:4444"
    driver = webdriver.Remote(
        command_executor=host + "/wd/hub",
        desired_capabilities=DesiredCapabilities.CHROME
    )


    node_socket = requests.get(host + "/grid/api/testsession?session=" + driver.session_id)
    robot_ip = node_socket.json()["proxyId"].replace(".", "-").split("//")[1].split(":")[0]


    df = pd.read_csv(robot_ip + ".csv") if os.path.exists(robot_ip + ".csv") else pd.DataFrame()


    driver.get("https://google.com")
    search_box = driver.find_element_by_name("q")
    search_box.send_keys(search_term)
    search_box.send_keys(Keys.ENTER)


    sleep_duration = random.randint(1, 10)
    print(robot_ip + " sleeps " + str(sleep_duration) + " second(s).")
    sleep(sleep_duration)  # simulate long running automation


    results = driver.find_elements_by_css_selector("div.g")
    link = results[0].find_element_by_tag_name("a")
    href = link.get_attribute("href")
    print("Search term: " + search_term + "\nURL: " + href)
    df = df.append({"Search Term": search_term, "URL":href}, ignore_index=True)
    df.to_csv(robot_ip + ".csv", index=False)
    driver.quit()


if __name__ == "__main__":
    scrapper(sys.argv[1])

Robotları Paralel Olarak Çalıştırmak

Gereksinimleri ve ağımızı kurduktan sonra, robotumuzu paralel olarak çalıştırmamız gerekmektedir. Bunu yapabilmek için subprocess modulünün sağlamış olduğu Popen komutunu kullanıyor. Aşağıda bulunan run.py kodu input.txt içerisinde bulunan satırları okur ve her bir satır için scraper.py kodunu çağırır. Oluşturulan her bir alt işlem bir diziye atılarak daha sonra bu işlemlerin sonlanması bir döngü yardımıyla beklenir.

  1. 					
    from subprocess import Popen
    
    processes = []
    f = open("input.txt", "r")
    lines = f.readlines()
    for line in lines:
    cmd = "python3 scraper.py '"+line.strip()+"'"
    processes.append(Popen(cmd, shell=True))
    
    for i in range(len(lines)):
    processes[i].wait()

scraper.py kodunu çalıştıran konteynırların çalışmasını görmek için, VNC Viewer üzerinden 0.0.0.0:5900 ve 0.0.0.0:5901 adreslerine secret şifresi ile bağlanabilirsiniz. python3 run.py ile kodu çalıştırdıktan sonra aşağıdaki videoya benzer bir çalışma görmeniz gerekmektedir.

Robotlar çalışmasını bitirdikten sonra run.py kodunun çağırıldığı dizin altında iki adet .csv dosyası olması gerekmektedir.

selenium automation

.csv dosyalarının içeriğini aşağıdaki gibi cat komutu ile kontrol edebilirsiniz.

cat komutu

Docker Compose Kullanmak

Docker üzerinde ağ oluşturmak ve konteynırları çalıştırmak tüm yükümlüğü üstlendiğiniz bir iş olduğu için bir miktar zorlayıcı bir iştir. Bu işleri kolaylaştırmak için Docker Compose kullanılabilir. Docker Compose birden fazla konteynırın çalıştırılması ve yönetilebilmesi için kullanılan bir araçtır. Docker Compose kullanabilmek için aşağıdakine benzer bir docker-compose.yml dosyası oluşturmanız gerekmektedir. Böylece tüm servisleri tek bir komut yardımıyla çalıştırabilir, ölçeklendirebilir ve sonlandırabilirsiniz.

Bizim örneğimizdehub ve chrome adında iki adet servis tanımlıyoruz. hub selenium/hubimajının son versiyonunu kullanır ve daha önce olduğu gibi 4444 numaralı portları eşleştirir. chrome  selenium/node-chrome-debug imajının son versiyonunu çalıştırır ancak depens_on parametresi sayesinde hubkonteynırının çalıştırılması beklenir. VNC bağlantısı sağlamak için 5900 ve 5904 arasında bulunan portlar ayrılmıştır.

					

version: "3"

services:

  hub:

    image: selenium/hub

    ports:

      - 4444:4444

  chrome:

    image: selenium/node-chrome-debug

    depends_on:

      - hub

    ports:

      - 5900-5904:5900

    environment:

      - HUB_HOST=hub

docker-compose up –scale chrome=5 -d komutu ile 1 adet hub ve 5 adet chrome konteynırı çalıştırılabilir.

selenium konteynır
Konteynırları çalıştırdıktan sonra run.py kodu çalıştırılarak yukarıdaki senaryoya benzer bir çıktı elde edilir. Ancak dikkat edilmelidir ki bu senaryoda 5 adet Node çalıştırılmıştır. Çalışma bittikten sonra docker-compose down ile tüm konteynırlar sonlandırılabilir.

Sonuç

Bu yazımızda, Selenium-Grid ve Docker kullanarak yazılım robotumuzu birden fazla makinada çalıştırdık. Bu sayede özellikle tarayıcı işlemlerinin yoğun olduğu süreçlerde çalışma zamanı açısından fayda sağlanabileceğini göstermiş olduk. Bu yazıda kullanılan tüm kodları bu Github sayfasında bulabilirsiniz. Bir sonraki yazımızda bu yapıyı AWS gibi bir bulut servisine Docker Swarm kullanarak kurmayı deneyeceğiz.