Jak wykonać prostą automatyzację w Selenium i zintegrować ją z elektroniką?
Tym razem Dominik Bednarski z IntHou przedstawi, w jaki sposób wykonać prostą automatyzację, gdzie przy pomocy Selenium WebDrivera, Pythona, Raspberry Pi oraz kilku gotowych układów elektronicznych można zrealizować monitorowanie na stronie stanu magazynowego produktu i na podstawie otrzymanych danych zrealizować jakąś akcję.
Więcej artykułów o projektach na blogu: InThou
Ogólny zarys projektu
Założenia projektowe:
- pobieranie danych ze strony internetowej odnośnie stanu magazynowego produktu
- przesłanie danych do Raspberry Pi z wykorzystaniem protokołu UDP
- przetworzenie danych i wysterowanie dowolnego układu elektronicznego, którego działenie będzie uzależnione od otrzymanych danych
Pobranie danych ze strony internetowej przy pomocy Selenium WebDriver
Projekt rozpoczniemy od pobrania danych ze strony internetowej. Jako cel obrałem monitorowanie stanu konwertera poziomów logicznych 3,3V / 5V 4-kanałowy, który znajduje się pod następującym linkiem https://sklep.msalamon.pl/produkt/konwerter-poziomow-logicznych-33v-5v-4-kanalowy/ [1]. Zaznaczę, że między innymi tego konwertera użyjemy w późniejszym etapie projektu.
Dane ze strony internetowej pobierzemy przy pomocy Selenium WebDriver, o którym wspominałem już wcześniej na blogu. Jeżeli chcesz dowiedzieć się podstawach informacji o Selenium, zapraszam Cię pod ten link [2], a jeżeli chcesz zainstalować odpowiednie oprogramowanie, to proponuję przeczytać ten wpis [3].
Znając nasz cel, przechodzimy pod nasz adres URL i otwieramy narzędzia developerskie przyciskiem F12 w przypadku przeglądarki Firefox czy Chrome. Z narzędzi developerskich możemy użyć opcji “Inspector”, gdzie zobaczymy kod strony a następnie narzędzia “inspect”, przy pomocy którego odszukujemy linijkę kodu, która będzie nas interesowała. Poniżaj, zamieszczam zrzut ekranu z danymi, które wykorzystam w moim kodzie.
Po kodzie, który znaleźliśmy, możemy z dużym prawdopodobieństwem stwierdzić, że do szukania naszych danych wystarczy wykorzystać klasę css o nazwie “in-stock“.
W chwili obecnej mamy już wszystkie dane, które nas interesują i możemy przejść do pisania kodu.
W pierwszym kroku z modułu selenium musimy zaimportować klasę webdriver oraz z modułu by klasę By. Następnie należy utworzyć instancję klasy webdriver.Firefox(), która pozwoli nam na przeprowadzenie interakcji z przeglądarką. Warto następnie ustawić czas oczekiwania na elementy, ponieważ może zdarzyć się, że mogą być ładowane z opóźnieniem.
W kolejnym kroku możemy zmaksymalizować okno przeglądarki, a następnie przejść pod nasz docelowy adres URL. Gdy już będziemy na stronie, tworzymy tak zwany lokalizator elementu, który będzie typu tuple i w niej umieszczamy dwa argumenty. Pierwszy argument informować będzie metodę, że chcemy szukać elementu po nazwie klasy, a drugi argument zawierać będzie, konkretną nazwę, którą chcemy znaleźć. W kolejnym kroku wykorzystujemy metodę find_element, w której rozpakowujemy krotkę i wykonujemy na niej właściwość text odpowiedzialną za pobranie tekstu z odnalezionego elementu na stronie.
Gdy już pobraliśmy nasz tekst, możemy zauważyć, że zawiera on więcej danych, niż potrzebujemy, dlatego dodatkowo przy pomocy wyrażeń regularnych możemy wydobyć z naszego stringu jedynie dane, które będą nas interesować. W celu weryfikacji, czy wszystko działa poprawnie dane, które wydobyliśmy, możemy wyświetlić w terminalu. Na koniec jeszcze należy po sobie posprzątać i zamknąć przeglądarkę metodą quite().
Kod takiego programu prezentuje się następująco:
Przesłanie danych do Raspberry Pi
Gdy już mamy przygotowane dane, które chcemy wysłać, musimy napisać program a właściwie dwa programu, które obsłużą nam komunikację. Pierwszy program będzie odbierał dane “receiver.py” i należy umieścić go na Raspberry Pi, drugi natomiast, będzie wysyłał dane “sender.py“, dlatego umieszczamy go na komputerze.
W celu obsłużenia komunikacji po UDP, należy zaimportować moduł socket. Z modułu socket następnie należy utworzyć instancję klasy, o tej samej nazwie, czyli socket i jako argumenty podać AF_INET odpowiedzialną za poinformowanie, że komunikacja będzie odbywać się po protokołach internetowych oraz jako drugi argument należy podać SOCK_DGRAM informujący, że zostanie użyty protokół UDP. Obie stałe dostępne są pod modułem socket. Gdy już utworzymy instancję, należy przypisać do niej adres IP oraz PORT, po którym będzie odbywała się komunikacja. Port i IP podajemy naszego Raspberry Pi, ponieważ to RPi będzie serwerem. W kolejnej części należy w pętli nasłuchiwać, czy nie pojawiły się dane w buforze w tym celu, należy użyć metody recvfrom, która przyjmuje jako argument rozmiar bufora w bajtach. Metoda ta zwraca dwie wartości, gdzie jedna to dane a druga to adres, z którego przyszły dane w postaci IP i Portu. Tak otrzymane dane są gotowe to ich obrabiania.
Kod programu prezentuję poniżej:
Drugi program, który będzie wysyłał dane, umieszczamy na komputerze. Podobnie jak wcześniej powtarzamy kroki z zaimportowaniem modułu socket stworzeniem instancji dla klasy socket z tymi samymi argumentami, a jedyna zmiana to użycie metody sendto, która przyjmuje argument w postaci wiadomości typu byte oraz drugi argument typle, która stanowi adres IP i Port serwera, gdzie mają być dostarczone dane.
Kod programu prezentuję poniżej:
Wysterowanie pinu na Raspberry Pi
Jednym z ostatnich kroków jest stworzenie tak zwanej logiki biznesowej, gdzie otrzymane dane będę odpowiednio obrabiane. W moim przypadku stworzyłem prosty program, który ma za zadanie jedynie ustawiać pin na stan wysoki, a następnie niski po jedno sekundowym opóźnieniu.
Podzielmy jednak to zadanie na dwa kroku, gdzie w pierwszym napiszemy program, który wysteruje pin a dopiero w drugim kroku połączymy go z daną, którą otrzymaliśmy. W celu wysterowania pinu należy zaimportować moduł RPi.GPIO, następnie należy ustawić tryb opisu pinów gpio. Ja ustawiłem go na gpio.BCM. W następnym kroku konfigurujemy pin na przykład o numerze 21, aby pełnił funkcję wyjścia i dopiero wówczas możemy przy pomocy metody output ustawić pin 21 na stan wysoki. Na koniec należy po sobie posprzątać korzystając z metody cleanup() tak, aby zwolnić zasoby sprzętowe. Przed posprzątaniem możemy jeszcze dać opóźnienie abyśmy mogli zaobserwować stan wysoki.
Taki kod programu prezentuje się następująco:
Gdy przetestujemy powyższy kod możemy napisać prostą funkcję do ustawiania pinu w stan wysoki i niski po sekundowym opóźnieniu.
W ten oto sposób możemy przejść do etapu drugiego i połączyć obydwa programy.
Do połączenia obsługi nasłuchującego serwera oraz wysterowania diody możemy użyć na przykład wątków. W jednym wątku będziemy nasłuchiwać, a w drugim będziemy obsługiwać piny. Abyśmy mogli korzystać z wątków należy je zimportować moduł threading, a następnie musimy utworzyć dwa wątki.
Dalsza część artykułu Dominika dostępna pod linkiem: IntHou