Selenium is a portable framework for testing
web applications. Jim from JimShapedCoding teaches this Selenium course. He has created many
popular courses both on the freeCodeCamp channel and his own channel. Hi, everyone, and
welcome to the Python Selenium series, where we will learn how to create user interface
automation for websites. So Selenium is widely used. And it is very popular for a great reason.
Because it can help you to create tests for your web applications. And it can also help you
to create online bots, which is very nice. So in this series, we are going to learn how to
use Selenium from the basics. And later on, we will learn how to create an online bot that will
report the cheapest deals from a booking website. And this series is really going to include some
great episodes, so be sure to hit the subscribe button and as well as click the bell notification.
So you will never miss an episode from this entire series. So grab a cup of coffee, and let's get
started. Great. So before we really get started, we need to understand that there are going to
be some prerequisites. So in this series, I'm going to assume that you have Python installed.
And as well as you got an id like Python that is configured properly with Python. Now you can
also use a random text editor like Sublime Text, but just make sure that it is connected
properly to your system interpreter. And if you don't have any of those, then you can
visit my five our beginners course and catch up with the installations. Alright, so like a lot
of libraries in the Python programming language, we need to somehow use the library of scillonian.
So that's why we need to somehow install it on our computer. And we can do that with the PIP
command. Now, if you got Python installed, then you should also have the PIP package manager
installed together with it. So now I'm going to open our terminal here. And I'm going to say pip
install Selenium like that. Now I'm doing this in the system interpreter, because I'm not going to
use virtual environments throughout the series. So that's why I could allow myself to do that
from the terminal. Okay, so if you see no arrows, then it means that everything is great. And we can
go back to a pie chart and basically import this library and see how we can use it. Alright,
so here, I'm going to import from Selenium import WebDriver. So I'm importing something very
specifically inside the Selenium library. And there's a great reason for doing that. Now, when
it comes to performing user interface automation in web browsers, then we need to somehow open up
that web browser. So that's why we need to import a dedicated library that is going to automate
us the action of opening up a web browser. Now when we talk about performing automations on a web
browser, we need to understand that for each web browser out there, there is going to be a version
that is going to be dedicated for performing those automated tasks. So for example, if we want to
perform those automation tasks on Chrome browser, then we need to instantiate the chrome driver
class to perform those automated actions in it. So that's why we need to import that library.
Alright, so now that we have imported this, then we have to instantiate the library that
is going to be responsible to pop up the Chrome browser to us. So that's why I'm going
to go down. And I'm going to say, for example, driver is equal to WebDriver dot Chrome, like
that. And as you can see here, there is actually more options rather than Chrome. So if I delete
that, and I press on control space, then you can see that we also got Firefox. And I believe that
there is edge as expected. So as you can see, you can perform those automated actions in different
browsers. But actually, throughout this series, I'm going to use Chrome browser. So that's why I
will say Chrome, and we'll instantiate the class like that. Now, we could go ahead and try to
execute this. But we will receive some arrows and the arrows are going to talk about something that
is called chromedriver. That does not exist on my computer. And as well as it is not in the tat.
So let's break down this error into two important steps that we need to do. So first of them, we
need to download the chrome driver. And actually chrome driver is a separated executable file that
Selenium WebDriver uses to perform those automated actions in a Chrome browser. So that means that we
need to download this chrome driver dot e xe file to our computer. So that's why I'm going to bring
here this website. And I will put the link of that in the description for sure. And as you can see,
here is the page that we can download the chrome driver, and if we scroll down, then you can see
that there are a lot of versions of Chrome driver that you can download. Now, you might ask yourself
how I'm going to decide which version should be installed on my computer? Well, this depends
on what Chrome browser version you have right now installed on your computer. So if you
use the Chrome browser by default, like me, then what we can do is basically go to a separate
tab, and we can right here, Chrome, colon, two forward slashes, and then say, version.
And right after that, we will see an output like the following. And as you can see from
here, here is the google chrome version that I use. And as you can see, we have the major version
as 89. So for yourself, it could be 9091 92, or even 84. But you need to make sure that
this measure version is going to be matched to the version that you are going to download from
the chromedriver page. So in my case, I am going to go back now to that page. And I'm going to
search up for a version that is starting with 89. And that's why I'm going to click here. And right
after that, I'm going to search for the specific archive that I need. And for sure it is going to
be windows because that is the operating system of my machine. And I'm going to click here and
it should start downloading and right after we have this downloaded, then we need to extract it
because it is actually a zip archive. Alright, so as you probably know, in Windows, by default, the
download files are going to be downloaded in the download library. And you want to move this to a
location that you want to have your chromedriver. So for myself, it is going to be under the C
drive. And inside the folder that I named salonu drivers, as you can see in the left side of my
screen. So I'm going to cut this from here and move this to the folder that I'd like to have it.
So I'm going to do that. And right after that, let's go ahead and work with this follow now.
So as you can see, the location of that will be C Selenium drivers like that. And you can again,
put it in whatever location you would like to invite up to that I'm going to extract the
files in here. And as soon as I have done this, then you can see that we got the executable file
located in this directory. So it is a great start to solving our problems that we have when we try
to execute this fight on file. Perfect. So back to Python. Now, if we will try to execute this file
again, then we will end up with the same error. And this is because we did not perform the second
step that I talked about when we saw this error. And we need to now put the location of our
chromedriver in an environment variable that is called a path. Now the PATH environment
variable is going to be responsible for the files that your system should look up for when
you want to execute them immediately from the terminal. So that's why it should be inside the
PATH environment variable. Now we could have done this in the system level. But that is actually
a not great idea. If one day you would like to perform the Selenium project on another server. So
that's why configuring this environment variable in the code level and not in the system level is
considered as a best practice. So that's why I'm going to say up top here, something like import
OAS. And I'm going to now upload one more value to the already existing PATH environment variable. So
I'm going to say Oh, s dot n, v wrong like that. And then I'm going to look up for the key of
cat and make sure that you should do it all in capitalized like I did. And now we'd like to use
plus equals because we are adding a pet value to already existing pad, we could have multiple
values for this environment variable. And right here, we want to specify the location of
our chrome driver. So I can start typing here C, colon and Ford slash. So I'm pointing to the C
drive of my computer. And I'm going to say here, selenium drivers like that, because this is
the folder name where I have the chromedriver. Alright, so right after we have done this, then we
should add here the our letter before the double quotes. And this is actually a convention for a
prefix that is going to mark it as a role string and it is going to be helpful when you specify
paths to different locations. So now if we were to try to execute this program, then we should see
now the chrome popped up and that is exactly what is happening. So it means that now we are ready to
work and start trying to perform some automations on a random website. Alright, so now that we
understood how to set up a Selenium environment, let's try to perform some automation on a random
website. Now in this episode, specifically, I will start by a testing Selenium website which will
allow us to to basically take basic actions to get started with it. So I'm going to use this
Selenium ez.com website. And I'm going to go to this URL in here, which I will put the link of
that in the description. And I'm going to try to click on that start download, performing it with
the Selenium only. And right after we click on that, then we should somehow identify that the
progress has been completed. So actually, those kinds of actions are good candidates for actions
that you want to perform with Selenium without really being involved in clicking manually on
those buttons. So let's go ahead and get started. So first of First, we should understand how we
are going to identify the element that we want to click on. And in order to do something like
that, we can go to the element that we want. And we can click on Inspect like the following. Now
actually, when it comes to pages, then each page is going to have its unique HTML architecture.
And each HTML element is going to be described by each type. And as well as with some additional
attributes. So let's see what I said in action. So I'm going to say inspect. And as you can see, we
have this line in blue background. And as I said, the kind of this element is button because we
see that it is right after the tags. So that's why it is called a button HTML element. And as you
can see, it has different attributes like class, Id like that. So what we can do from here is
to try to identify the element that has the ID of download button, like it says in here. So
let's try to do and see how we can identify this specific element, and try to click on that.
Alright, so let's go back to pi charm. Now before I do that, let me copy the link of the website,
because we are going to use it just in a minute. All right, so now if I open pi charm, and go down,
and here we are ready to write some additional code. Now before everything, we need to specify
selenium, what is the website that we are going to use in our automation, so it should be done with
the get method that the driver is going to have. So I will say driver dot get. And as you can see,
it expects for a URL, so I can straight forward, put the link of the URL that we actually look to
perform some automatic actions. So as you can see, this is the way that the driver dot get should be
executed. Alright, so now that we have done this, then we should somehow tell the Selenium
that we like to click on an element that eats ID is download button. So I'm going
to say here, driver dot find underscore element, underscore by ID. And as you can see, we have
multiple methods of find element by so we have class name, CSS selector, and even more like name.
And those are methods that we are going to see in the future throughout the series. But let's
start with the ID. And I'm going to say here, download button, like the following. Now since
this entire statement is going to return us an object that we can actually do some additional
actions with it, then I should assign this to a variable. So I can say my element, something like
that. And then down below, I can say my element that click like that. And we should see Selenium
driver trying to click on that element. So let's test this out. So I'm going to execute that right
now. And I'm not going to touch anything. So let's see that in action. Alright, so it takes us
to here. And as you can see it immediately just click on that element, because we see
that progress box that says us now that the download has been completed. But there
is actually a big problem with doing this approach. Because sometimes, in most of the cases,
loading an entire website could take some time. So that's why we can go between those two lines, and
actually try to wait before we try to perform an action on an element. So that's why going between
those lines and saying something like driver that implicitly wait. And here, we should specify
the amount of seconds that we'd like to wait to this website, it's all being loaded successfully.
So we can say that we'd like to wait for example, three seconds, so it's considered as a better
thing to do, because now we are totally safe from our browser being a little bit slow sometimes.
Or maybe we can have some cases that our server could be very slow. So that's why waiting a
little bit here and there could be a better idea. So now if we run our program one more time,
then let's see the results. So at first again, the page is being loaded. Then as you can see it
immediately try to download this file. Now again, this is just a simulation, this really doesn't
download anything to your computer. Okay, so let's identify what happened in here. So first
off first, we can understand that it really did not wait three seconds. So what that means it
means that the implicitly wait does something special to our driver object, because we did
not really wait three seconds, right. So let's try to test this with 30 seconds now. So I'm going
to execute this one more time. And as you can see, just in a second, it sounds to download it
once again. So this really does not wait in the amount of time that is specified in this
line. So what is going on here and why we saw the actions being taken immediately. Well,
we could have use here something like time dot sleep, and specify the amount of seconds to
wait. But this is something that we don't like to do here. Because sometimes we don't like
to wait for the complete duration of time, in case the element is going to be found before
the duration specified, it needs to move on to the next line of code execution. And so using here,
the implicitly wait is actually very, very useful. Because again, we don't feel the need to wait 30
seconds if the element is already there in that web page. Now, to be fair, there are more things
that I'd like to talk about this implicitly Wait, because it has some more functionalities
that I will talk in the future. And if you have any questions about the behavior of this
tricky method, then let me know this in the comment section down below. Alright, so before
we go ahead and compare those kinds of weights, then let's clear some important points about
the implicitly wait. Now till that point, we know that this is much more efficient,
rather than typing in the time dot sleep, because not always we'd like to wait 30 seconds,
before we find an element by ID, for example. But there is one piece of information that we
should know about implicitly Wait, it is going to be set up as a timeout across all your scillonian
project. So what that means it means that you only need to call this implicitly await method
one time, and then it will go ahead and set an implicit wait amount for all the elements that
you're going to try to find it in the future. So for example, I might go down here and say
something like my second element, and I can make that to be equal to driver dot find element by ID.
And I'm going to put here some element that is not even existing in the page in the left side. So I
can say something like, let's just write something randomly. And then I can basically try to execute
our program. And just for testing reasons, let me decrease this to eight seconds. So we won't really
wait 30 seconds before we see this program being crashed. Okay, so if we run this one more time,
then let's see the results. So as you can see, we have no problem with the first element. But in
about a second or two, we should receive an error that the Selenium was not able to identify
an element with this ID in here. So that's actually an important point to remember. Because
once we said the implicitly Wait, it is going to be basically applied across all the elements that
we are going to try to find them somehow in the future. All right, so now that we completely
understood the behavior of implicitly Wait, let's go forward with our automation. So now as
a next step, it would have been nice to identify if the download has been completed successfully.
And we understood that that to indicate something like this, we need to understand when this
text in here is going to be exactly equal to complete with an exclamation mark. So let's try
to write an automation like that. So I'm going to select everything in here and try to click on
Inspect. And let me do this one more time because it did not really point to it. Okay, so we can
see that this complete with an exclamation mark is coming from this HTML element, which says us
that its type is Dave, and it has the class of progress label. Now till this point, we did
not really identify a specific HTML element by its class name. And there is actually a
great way that we can do that by again using a method with the prefix of find element. So
let's see how we can do that. So let me delete this line actually, and I will stick with
that one. So I can say something like progress element is equal to driver dot find element,
and then I can select a method that is called by class name. So we cannot identify an element
by its class name. So it is a great idea to select that. And I only need to now
pass in the class value. So it will be progress dash label as we saw earlier. Now, for
those that are confusing What are classes in the web world, it is basically a reference to a filing
method, unlike with Python, which is referring to classes where we use it for object oriented
programming. So I just wanted to make sure that we don't confuse between the meanings of
class in the web. And now that I have this, then I can go to a new line. And I can say here,
something like print, and I can use the formatted string. And I can try to basically print the text
of these elements. So it will be by both text, and it showed that display as the text in here.
So if we do that, and run this one more time, let's test the result of that. Okay, so we have
a new page being appealed. And as you can see, it immediately showed the text of this element,
which was starting down now showing up the text immediately is actually not a great idea,
because we probably like to wait some time until we see the complete. But there is actually
not a nice way to do this with the approaches that we have learned till this point. So we need to use
another utility. And for that there is something that exists in selenium, which is called explicit
wait. Now with this, we can actually allow our program to wait for unexpected condition. And then
we can basically wait until this condition returns through. So what that means it means that we
look to this through expression in here. So I can say here, completed with the exclamation mark. And
in our case, if we don't wait in a smart way, then we will always receive false with that. So we need
to figure out how we can wait till this condition is through. And let's go ahead and see how we can
do that. Alright, so in order to use the explicit Wait, we need to import some several secondary
libraries that is inside the Selenium. So we are going to say up top here something like from
Selenium dot web driver, that common.by import by like that. And we are also going to import two
more things in here. So it will be from Selenium dot web driver.support.ui. Like that, we need
to import the built in class inside the Selenium that is called a web driver wait. And we'd also
like to import one final thing, which is going to be Selenium dot WebDriver dot support. Import
expected conditions as EC, both capitalized like that. Now I know that it was a lot of info
that we have used as input. But there is actually a great reason for that. And we will see why
just in a minute. So now I will go down here and I will start writing the condition that we'd
like to wait for. Now in order to start with that then First I will instantiate the WebDriver
weight class. So I will say web driver weight and I will instantiate that without assigning it to
a variable. And at first we need to pass in the driver object. So we will just say here, driver.
And now we like to specify the amount of seconds that we should wait until the expected condition
is true or not. So I'm going to say here something like 30 seconds again, and the actual be enough.
And then I'm going to automatically launch the method of until in here. Now by convention, the
info that is written inside this until method is usually in a separate line. So I'm going to
press enter in here. And then we need to write the condition that we want it to be through
at some time. And in our case it is after 30 seconds approximately. So we can say here e c,
which stands for expected condition that we have used as import in here. And we can now use a
method that says text to be present in element. So as we can understand this method is designed to
basically to wait until the text has the expected text. And I'm going to launch up this method in
here and again, press enter. So again, I'm just writing the arguments just in a separate line. Now
this method expects for two important arguments as the first one being the element that we'd
like to check the condition on. And the second one being the text that we expect to have after
30 seconds. So I will just comment here, those downs So I will say here, element filtration. And
as the second one, we will say the expected text like that. Alright, so the way that we are going
to identify the element that we'd like to check is by using the by class. Now, this is just
another approach finding elements in a web page. So it is not going to look complex. So it is as
easy as saying here something like so I will just create a tupple in here, and then I will start
my filtration. So we'd like to find this again, by class name. And as you can see, we have
auto completion for that. So I can just use class name like that. And the second piece of
information right near of it should be the class name value, so it will be progress dash label
exactly like before. So this entire expression is just another way to find an element in a web
page, unlike using the find element by class name, meddled, and I just realized that I did not delete
those two lines that we don't need. So let's go ahead and do that. And then in the second line,
right after we say, comma, we are going to write the expected text. So it is going to be complete
with an exclamation mark. So now, if we run our program, then we should not receive any errors,
because this condition is probably going to return us through in less than 30 seconds. So if we run
our automation now, and wait for the results, so again, we click on this download button. And let's
see, just in a second, what will happen. Alright, so we got the text of complete. And if we go back
to our program, then you can see that the program finished successfully. So what that means it means
that we were able to write a nice automation, until we have waited, that's really verifies
that the download of some file has been completed successfully. So it is very nice to play around
between those wait methods, we can use implicitly wait to find elements in our entire page. And
we can also use the explicit Wait, which is the more custom waiting, so it means that we need to
use it if we want the execution to wait for some time until some condition is achieved. Now for
everyone that are interested to know what are the expected conditions that you can use, you can do
that by basically seeing all the options in here. So if we delete everything from here, and use
that again, and you can see that we have a lot of options that we can use expected condition for. So
you can see that we have element to be clickable elements to be selected and basically wait for
new window is opened. So as you can see, there are tons of options that you can use if you'd like
to wait until some expected condition is achieved. So it is very nice feature by Selenium that we can
always use to write more dynamic bots and as well as writing more efficient test cases. Alright, so
the reason you want to learn about ascending keys or clicking on different buttons right after it is
for performing actions like login and registering accounts. And this is something very useful
when you want to overcome authorization in some websites to basically performing some UI testing
or creating a bot for whatever reason. So to practice this, I am going to pull up this website
again from Selenium easy.com. So that's actually the page that we are going to try to send the keys
to. So as you can see, in here, we have some HTML forms. And actually, when we want to send the
keys, usually we'd like to do it in HTML forms where we actually need to write in some data, and
then we need to click on some button to submit our data. So as you can see, here, we have some form
in here which asks for two values. And then if we were to click on Get total, then you can see that
it shows us 30 and if I change this to actually some other number, there you can see that it is
being updated. So that is what we are going to try to automate now with Selenium. So first, let
me grab the website of this section in here and go back to Python and actually say here rival dot get
and the link will be available in the description for sure. So you can directly copy and paste from
there, alright. So now I will paste this in. And right after we have done this, then we should
somehow again try to identify the element in some method by ID class name or whatever method it
will be. So I will go back to our website in here and as usual I will say inspect, and you can see
that we have here something that is called class which we can again, find the element by class. And
as well as ID. Now, I always like to filter by ID because I think that this is the strongest field
that is always unique. So I'm going to use this ID some one. And I believe that the second box in
here should be some tools. So if I check that with inspect, then you can see that it is just as
expected. So we need to pull those elements and basically try to send it some keys to it. So I'm
going to go back to Python. And I will say here, some one is equal to driver dot find element by
ID. And I can use someone in here. And I can do the exact same thing by basically copying this
in here, and paste this in and change the values to number two, like that. And then I can try
to send some keys. So it will be just as easy as pulling the element. Because now we have full
access to it, and basically launched the method of send keys like that. Now, you can put here,
whatever you would like to, as you can see, it expects for a value. So this could be any
value that you would like to pass in here, it could be a string, or it could be directly a
number like that. So let's go with numbers and say 15, like we have done manually. And I will do the
same thing with some tools. So I will send the 15 as well. And now we can actually test this
out and see if it works. But not before we go ahead and say here's something like rival
that implicitly wait. And it is enough to wait five seconds in here for each element. And now
we can test this out. So if I run our program, then let's see the results. Okay, so the
page has been loaded. And you can see that we received this message. And we will handle it
in a minute. But you can see in the background, that we got the values. So I know
that it is a bit transparent in here, but you can actually see this in the background.
Okay, so I think we got a new challenge in here as we see this output. And we need to somehow
perform an operation to click on no things to continue our automation. So this is actually a
good candidate to handle things along the way. So now I can go to inspect in here and see what needs
to be done to basically identify this button in here and click on that before we go ahead with
our automation. Okay, so you can see that we got this element with multiple classes. And if I
take a look in here, then you can see that we have some classes in here that are separated by spaces.
Now, if you see classes separated by whitespace, as I said, then it means that it is referring to
a different class. So I can actually try to filter this element by class name at dash c m dash, no
dash button, as it will probably the most unique class name that I can try to filter this
element by. So I can go here and actually use let me copy this down and manipulate this in
Python. So before we go with everything in here, let me please go down here and paste this text
in here. And as you can see, this is the class name that we'd like to filter by. So I will delete
everything. And I will cut this string from here. And I will say no button is equal to driver dot
find element by class name. And I will paste back the class name that we'd like to filter by. And
now that I have done this, then I can basically apply the click method. So it will be no button
dot click like that. Now one final thing that it is a great idea to do here is to wrap this with
try except block because not always we are going to find an element by this class name because
maybe in the next time this popup won't appear. So it is a great idea to use here, try and basically
locate those two lines under a try block. And then if the Selenium is not going to find any element
with that class name, then it will not crash our program. Because in the except block, we can
only say something like print no element with this class name. So I can say just skipping like that.
All right, and down below, I can continue with our automation exactly like that. Okay, so if we run
our program here, then let's see what will happen this time. So the page has been opened. And as you
can see, now we don't see the popup, and we don't see any message from the except walk. So what
that means it means that the Selenium identified the element with this class name and it emits
Click on that button that we wanted to click on from the first stage. And then it went ahead and
basically executed the rest of the lines of code. And you can see that the values are right there.
So we are pretty close to complete the automation that we wanted to complete. Now there is one
final thing that I like to show you before we go ahead with the get total element. And I'm talking
about the fact that we can send the keys directly, not only specifying the text that we'd like to
send. So what that means it means that we can send the keys like Shift Alt, enter control and stuff
like that. And the way that it is going to work is by importing the keys class from the Selenium.
And that is something useful here and there that you will want to basically automate some actions
that are required to maybe copy some text. So you need to automate Ctrl C. And again, that's useful
because sometimes you'll want to automate pressing on some key directly rather than sending some
random text. So I'm going to import here from Selenium dot WebDriver, dot common dot keys,
import keys like that. And inside this class, you have all the options that are basically the
keyboard keys that are existing in each keyword. So to show you that, then I'm going to
now change this to something like keys, dot. And as you can see, in the drop down, we
have all the options. So we even have F 1234. And we even have the nums that are existing in
the right side of our cable, which is in numpad. So if we want, we can send the keys from the
numpad, I know that it is not quite useful for that case. But again, sending keys directly
could be very, very useful in some cases when you need them. So as you can see, you have
all the options in here. And if one day, you want to take a look to all the options, then
you can always go here and basically use Ctrl B in Python or F 12 in visual code, and you can
inspect to that class. And you can see that all the options are here available. And this is very,
very useful. Now to prove you that it will work, then let me try this with the numpad. So in the
someone, I will send numpad. One, and I will also send pay attention that I can separate the values
by comma. And I can say here keys that numpad five, and then it will basically send the 15.
So it is going to be quite equivalent to what we have done. And to show you that it works, then
I can basically launch our program again. And you can see down below that the results are quite the
same. So that is just another approach of sending keys. And the beauty behind the fate eight is
the fact that you can send all the keyboard keys that exists out there. Alright, so now we only
have the gate total a button to filter. Now, not always we'd like to filter the HTML elements
by their ID or class name, we might have in some more attribute key value pairs that we can try to
filter the elements by. So now I'm going to go to inspect in here. And we do this again. And as you
can see, we have here an attribute that we did not see before, which is on click. Now say that I'd
like to filter this element by onClick equals to that value in here. And this is something that we
did not learn how to do till that point. And this is possible with something that is called a CSS
selector. And the CSS selector is a pattern to filter an element by its styling. Now, unlike with
the methods of find element by ID or class name. with CSS selectors, we don't always need to filter
an element that matches an exact string. So for example, with CSS selectors, it is an option to
identify an element by only searching a substring that it contains. Now that is extremely useful
because not always we'd like to filter element by exact key value match, because we could want
to perform something with elements that are having the same prefix or suffix. So let's see how CSS
selectors works in action. Alright, so we are back at pi charm. And let's go down and see how we can
use the CSS selector. So I'm going to say here, button is equal to driver dot find element by CSS
selector like that. And in here, we need to pass our CSS selector expression. And the way
that we're going to do that is by using some special pattern that exists out there.
Now to select an element by CSS selector. You have multiple options but we are going to use
the pattern of a HTML element type, followed by a matching key value. Now as an example, we can
actually go back to our button and see how we are going to filter that. And you can see that it's
a type of button. And we can see that from here, and it has the key value of on click return
total. So that means that we can try to filter all the buttons out there that are having
the attribute of onClick with the value of return total like that. So to achieve this, we will go
back here and we will say button, and then we will need to open a square brackets. And we will need
to say here something like on click equals and then we will use double quotes in here. Now the
reason I use double quotes is because I use single quotes here from the beginning. And we do not want
to miss match those. And now in here, I can say return total like that. And as you can see, this
is a one way that a CSS selector could work, you can basically specify the HTML element
followed by the key value match, and make sure that it is inside the square brackets right after
it. Now I'm going to show later on all the CSS cert or options, because there are tons of options
that you can filter in element by CSS selector. Okay, so I expect this button to basically have
the HTML element of this button. And then I can basically use button dot click as expected.
So now we can test if this works. So if we run our automation, once again, let's see
what will happen. Alright, so down below, you can see that we received the text of total A
plus B is 30. And that is exactly the result that we expected for. So what that means it means that
we were able to select an element by CSS selectors successfully. And that is perfect. Alright, so I
said earlier that I will show you the page where I took this CSS selector expression pattern. And you
can see that now, I mean, a page that has multiple examples of how you can filter elements by using
CSS selector. So you can see that we have a table with all the selector options. And as well as some
additional examples for all the patterns. So you can see that if we scroll down, then I actually
used those patterns. So this is a pattern that is containing the element type. And in this example,
the type is a and that stands for anchor. And you can see that within the square brackets in here,
it looks for a matching key value. But in that case, as I said earlier, you can not only search
for an element that includes an exact string, you can also search for an element that contains some
string. So you can see that in the description it says selects every eight tag elements whose href
attribute value begins with HTTP s. And same goes when you want to select some elements that ends
with some text. So you can see that we have a lot of options in here. And that is very useful.
And I can totally confirm that the CSS selector is the method that I use the most, because it
gives you much much control rather than the other elements. So it helps you really to find the
elements that you will look up for when you want to perform some automation on them. Alright, so
the first thing that we want to do is to dedicate a file for the project. Now before I started
recording this, then I already have created this board folder. So this is going to include the code
for our project. And you can go ahead and create the folder wherever you want, just make sure
that you connect this to Python. So I will click OK. And we will start from here. Now you can pay
attention that by default Python created for us the main.py file, so we can just basically
delete everything from here and continue working. So if the auto generated file is not
happen to you, then just go ahead and create a new file by yourself and name it main like that. Okay,
so now, I am going to basically start designing the structure of the project. And the way that
I'm going to structure this project is going to be as I described in my project structural video
on my channel. Now if you don't know what I mean, then I have a video that describes how a Python
project should be structured, whether it's a beginner project or an advanced project. So if
you want to take a look then you can click in the suggested link. So now I'm going to go ahead and
create a sub directory that is named Woking like that. And I'm doing this because I want to include
all the relevant code to the booking bot inside this directory. And then this main.py file is
going to go ahead and basically call the necessary Python files from this directory. And let me go
ahead and change this to run actually is just more comfortable to win. So I will go ahead and do
that. Alright, so inside this booking directory, we will start by creating three files. So let's
go ahead and create the first of them. So the first one is going to be named booking like that.
And here, I'm going to have a class that is going to have some instance methods that we're going to
call them in order to make our board to perform some actions. And the second one is going to be
constants. So we are going to have a lot of values that we really want to change it through how the
execution of our project. So that's why separating those variables in another file that we can name
it constant is a great idea. So I'm going to go ahead and do that. And the other file that I'm
going to create for now is going to be called by the following way. So it will be underscore twice
in it underscore twice once again. And there is actually a great reason that I naming this file
the way it is, it is because this is a convention when you want to create a Python package. Now
the reason you want to create a Python package it is because we want to call the package from
this run.pi file. Now notice how the run.pi file is outside of the working directory. And that is
one more reason that I have created this double underscore, you need double underscore file, it
is just a convention to mark this directory as a Python package. Now I will use a few more seconds
to explain something very special about the double underscore init file as well. So say that we go to
run.py file, and we look to import something from the constants file in order to execute something
successfully. So we could say something like from booking dot constants, import a for example, now
I know that this variable doesn't really exist, so we can create it like that. And notice that now
I'm inside the constants. And if I go back to run, then we are totally fine. Now before I do this,
let me go to the double underscore init file and say, I will print first. Now what I'm meaning
in here, it is the fact that no matter which sub module you're importing from the booking
directory, at first, the double underscore init file is always going to be executed. So to prove
that, then I'm going to execute the run.py file, which basically imports just a variable from
the constants file. So if I go ahead and run it, then you can see that we received this message. So
that is one more important behavior that we should be aware of when it comes to Python packages.
And we are going to use this advantage in our project as well. But I just want to make sure that
you understand the behavior of Python packages. And now we are totally ready to go ahead and
start building our bot. Now kind of a disclaimer, before we start, I will not recommend running
this bot around wild through or running it every few seconds, because it might lead the server side
to automatically disable your public IP address. And it is always not nice because then you have
to contact to that website and explain that you did not mean to do any harm. So that's why Be
sure to give enough room when you test your bot on those larger websites like the one that
we're going to use which is booking.com. Alright, so I have deleted everything that I have showed
you previously as example. Now we are ready to go and write our class. Now I say that we are
going to make this project object oriented. So this file that I named booking.py file is going to
be responsible to describe the methods that later on we are going to call them and those methods are
going to take the actions that we want our bots to take. So let's get started. Now first, we want to
import the WebDriver from the Selenium library. So we can create a class that will inherit from some
utilities inside this Selenium library. So we will start by saying from Selenium import web driver,
and then we will go down to lines. And we will say class booking so this is actually a good name for
our class. And now this class is going to inherit from WebDriver dot Chrome. And the reason we want
to do this, it is because I want the sale object to have the option of both using the WebDriver
dot chrome methods and also the methods that I will design for the class booking itself. So now
I can go inside our class and excuse me for these backslash and design the double underscore init
method. Now this is the constructor of our class, so This method is going to be called immediately
once we instantiate an instance of this class. So we will say def double underscore in it like that.
And we will receive one parameter that I can name that driver, Pat like that. And if Remember, this
is going to store information about the location of our drivers. Now, just to save us a little bit
of time, then I'm going to receive a default value for this parameter, which is going to be exactly
the value that I have used throughout the first three episodes of this synonym series. So it
will be all for rostering in I will open here, double quotes, and I will say C column backslash,
say lynnium. Drivers like that, because this is the location that I have the chrome driver. Okay,
so now I can go down and say self dot rival pad is equal to rival path. And further than that, I will
say, super. And the reason I use a super in here it is because I want to instantiate the WebDriver
dot chrome class along the way. And the reason I want to do this, it is because the constructor is
going to complain about how the inherited class is not instantiated yet. So this is why I can't allow
myself to use the super method to do so. Now, if you never saw me using the super method, then
I actually have a video from a series that I have created a year ago that you can watch a video that
is dedicated for class inheritance. So I will put the link in the suggested video up top. Alright,
so this super is going to receive the name of the current class as an argument, and as well as the
self object. And now I'm going to call the double underscore init method of the webdriver.com class
as well. So this line is going to be successfully instantiate an instance of the WebDriver
dot chrome class as well. And to do that, let's go down and design a random metal. So let's
say here, something like this land first page, and receive self as a parameter for
sure, because this is an instance method. And now if I was to say self dot get, then you
can see that I have full access to the methods of the WebDriver dot chrome class. And you can
see that I can also make use of find element by something. And as well as using the get method.
So those methods are familiar to us, because we saw them in the beginning of the series. So this
is perfect. Now I have a class that I can use the Selenium methods to play around with the action
that we want to take with our online bar. Alright, so I'm actually going to make use of this
method. And I'm going to point our board to the first location that we want to do so. And I'm
going to use here the get method. And as the URL, I'm going to pass in the URL of the website that
we are trying to make an online board on. So it will be HTTPS, that will double w booking.com.
Now actually, here is the exact reason that I have created the constants dot p y, what we can do
in that case, this value in here is probably a value that is not going to change. So commonly,
because this is the website that we are going to always use. So that's why moving this value to
a file that I already created, like constants.py is a perfect idea. So we can make use of this file
by storing some constants. And by convention in programming, when we have constants, then we
should use all obligates. So I'm going to say base underscore URL is equal to the exact URL in
here. And now I can go back to our booking.py. And I can use import booking dot constants like
that as const, just to make it shorter and easier to read. And I can go now and say const, dot
base URL. And now we are ready to continue from here. Now actually, before we test this out, if
you remember, before we instantiated the WebDriver chrome class in the first three episodes, then
we had to do something that is quite mandatory, because otherwise the Selenium is going to
complain that it does not have the driver Pat in the system level of PATH variable. So that's
why we used something that was looking like always thought envy wrong, if you remember. So
let's do this before we use this super metal, because again, otherwise the cylinder is going to
complain for that error. So I'm going to go up top here, and I'm going to say import always, and I'm
going to go down and I'm going to use here always dot envy Ron, and I'm going to access to the cat
variable. And I'm going to use plus equals. And then I will add the self dot driver path like
that. Now, if you don't remember what this does, definitely consider watching the first
episode maybe for a minute or two. But let me bring the code from the first episode.
So I am inside my repository on GitHub that I have published recently, when I launched the series.
And if we take a look, then you'll see that I used in the very beginning, this line that adds
this path to the PATH variable. So that's why I have basically use the same expression pretty
much inside our class. All right, so let's go back to five gentlemen continue. And now what
we can basically do is go to our run.py file, and import this class and create an instance
of it. So we can really use its methods like land the first page. So if we go to run.py
file, and zoom in a bit, and say, from booking, actually, it should be from booking dot booking,
because we want to refer to the file name as well, we only want to import the booking class, which I
named like that. And now I can say inst is equal to a booking instance. And I'm not going to pass
anything because I want to make use of the default value of this driver pad. And now I can really
try to use the first metal that we have launched. So it will be inst dot land first page. So this
line is going to be responsible to take our bot to the booking.com homepage. So now I can execute
the run.py file and test if everything works. So if I run that, then let's see what will happen.
Okay, so you can see that we are inside the page that we were interested to be at from the very
beginning. And now we can continue on basically designing our bot from here. Now there are
going to be tons of actions that we want to take to basically fill in the form of where we are
going, or the date that we'd like to check in Plus check out and as well as adding more people to
our vacation. So the combination of all of those are going to be divided into instance, medals. And
the fact that we do that is going to make our code a lot more readable and maintainable. So that's
why using here, object oriented is a perfect idea, because it gives you the option to extend your
application, if you want to do that later on. Alright, so there's going to be one more very
interesting thing that we want to design at this stage. Now you could pay attention that although
we only wanted to launch the Index page, then we still got the driver instance being opened. So
what that means it means that on our next testing, the Chrome browser is still going to be opened.
And this can lead us to have like 10 or even 20 browsers open on our computer. Now sometimes when
we test something, then we immediately want to force our browser being closed once the
board has finished doing its job. So that's why sometimes we want to have control whether
if we like to quit the application of Chrome, or leave it open. So this is a good candidate
for why we like to use context managers, because using context managers could give us a
lot more control when we want to start something and when we want to tear down things up. So that's
why I'm going to make use of context managers throughout this project. So in order to implement
this, then let me show you what needs to be done in the class level. And if you did not hear about
context managers yet, then I'm going to give here a short explanation about it. But basically,
if you want to learn about it more deeply, then I have a video that is dedicated for context
managers in Python. So if you want, definitely consider taking a look in the suggested link. But
let's go and cover this up. So I'm going to go to booking.pi file. And I'm going to use two more
magic methods that will allow us to basically make use of context managers. Now the way that
context managers are being used on the instance level is by instantiating, an instance of a class
with the width, keyword and tools similar to that. Then I'm going to split the panes now,
horizontally, I believe, no, we should do this, excuse me. I'd like to do that vertically.
Alright, so on the left pane, I'm going to have our booking.py file and on the right pane, I will
have the rumbaut py file. So on the right side, I'm going to now delete everything and I'm going
to say Wait, booking like that as board and then I will go here and I will Se bought that land first
page. Now the beauty of using something like that, it is the fact that once Python reaches the line
outside of the indentation, then it is going to execute some teardown actions. And the location
that we'd like to define those teardown actions are by convention used under the magic metal that
is called level underscore exit. So to implement that, then I'm going to go here, and I'm going to
say there, double underscore exit. And I'm just going to use this suggestion of Python, because
by default, it receives some more parameters. And I don't want to screw things up. So I'm going
to just press Enter on the suggestion of Python. So now I can say self dot quit. So quit is going
to be the method that is going to be responsible to shut down the Chrome browser, once we have
finished everything. Now to prove that, then I'm going to run this. And I'm going to say inside
the indentation, exiting, like that. And now let's try to run the run.py file one more time, and
see what will happen. So I'm going to run that. And once we received the page, then you can
see that we have exiting, and right after it, the Chrome browser has shut down. So what that
means it means that once Python gets out of the indentation of weight expression, then it executes
automatically the double underscore exit middle, this is how complex managers are working. And
to have something like this, when we want to test multiple things throughout the development
of this project is perfect. Now to extend the option of when we want to tear it down. Or when we
don't want to tear it down, then we can basically receive here one more parameter. So I am now
inside the booking file, then I can say tear down is equal to false by default. And I can
say under the exit model, something like if teardown. So this basically refers sorry, this
will be self dot teardown. And we should go here and say self dot teardown equals to teardown and
then I can basically use here an if statement and say self dot teardown. So if this is true, then
run the self dot exit. But if this is false, then just don't do anything and leave the browser
open. And now when I want to basically tear down, then I can pass in here till now I'm equals to
true, or I cannot pass it. And if I don't pass it, then the browser will remain open. So again,
this is a good way to have a control whether if you want to close up your browser or you want
to leave it open, go maybe sometimes you want to test something else, rather than just testing the
Selenium code. Now, let me also remove the exiting line now that we understood this. And I think that
will be it about the context manager. So I hope that you understood the concepts of how context
managers are working. Alright, so at that stage, we have left the previous tutorial, and
we understood in the previous episode, how we use this booking class in order to have
more control in our WebDriver chrome class. And we also designed some methods that could be helpful,
like the double underscore exit. So we could have the option of using context managers when we
instantiate an instance of this booking class. And we also have designed this metal in here,
which is looking like laying the first page. And it basically lends the board on these cons thought
base URL, which is booking.com, that is located in the constants.py file. Okay, so now before we
go ahead and understand what are the next steps, let me do two more actions that are going to be
quite useful for us to have more control. So the first one is going to be to adding the implicitly
weight method. And just a quick reminder, implicitly weight is the metal that will allow us
to wait for some amount of time until the element is ready on the website. So if we were to say
self dot implicitly Wait, and for example, a pass in here 15 seconds, then no matter which method
is going to be executed with the prefix of find element, then it is going to wait approximately
15 seconds. But he could also proceed to the next find element method by less time because not
always, we'd like to wait 15 seconds, and this method is going to take responsibility for that.
And the second line of code that I'd like to add in here is going to be self dot maximize window.
And the reason I want to do this it is because I just want to have a cleaner look when I test the
board. So now let me go and run out run.py file. And now you can see that the web browser has been
opened in maximized window so it is more nicer. And you can also see that we are inside
booking.com as expected. All right. So now that we have done this, then the
next step in here is probably going to automate clicking on Choose your currency. Now
you might have think that we should automatically automate the Where are you going, and as well as
checking checkout dates, and selecting how many people we are, but actually, at first, it might
be a great idea to change the currency. So we will have like a more common look to all the deals that
are going to be resulted after we search for them. So now, let's basically understand what we need to
automate. So we need to automate clicking on that. And right after it, we need to automate clicking
on USD or euro or whatever currency we look for. Now, for the purposes of this tutorial, I am
going to try to automate clicking on USD, because basically, this is one of the popular currencies
out there. So this is what we should do, we should basically click on this one. And right after that,
we should somehow try to click on that one. And then you can see that right after we have clicked
on that, then the currency has been changed. And then we are ready to try to send some text in
Where are you going textbox. So now let's try to understand how we are going to automate clicking
on that. So I'm going to click right click and click on Inspect. So we can understand which
element is responsible to display this button. Now, I not sure why I have to do it twice, always.
But I really did not figure this out yet. But if this is happening to you, as well, then maybe try
to do it once again. And it will basically color the element in the blue background as expected.
So I will do that one more time. And you can see that this button is actually what responsible
to display this currency element. So now, when we try to identify an element with selenium,
then we should always try to be smart enough to identify this element in the most unique
expression as we can. Now the attribute of ID is actually the most unique attribute
that an HTML element that could have, but not always, we are going to have ID for HTML
elements. So that's why we need to figure out other approaches to find that element. And
in our case, maybe you would have taught to find this element with the class is equal to
be UI button. But actually, this might not be the most smart way to do that. Because there
might be some other buttons with that class, as classes in HTML are for styling elements. So
multiple buttons could have the same styling. So that's why maybe feel during this button with the
data tooltip text is equal to choose your currency is a more unique expression that we can use. So
now, I'm going to copy this expression from here. And I am going to basically identify it with
CSS selector method that we have learned in the third episode. So I'm going to go back to pi
charm. And down below, I'm going to say their change currency. And I will also receive currency
as a parameter in here so that maybe we could have the option to change to different currency
rather than United States dollars. So I'm going to say currency. And down below, I'm going
to say self dot find element by CSS selector. And I will open up and close and I will press
enter, because I don't want to make the lines of code at all much long, so that it is a great
idea to separate them in the following way. And I'm going to now open up a single code, and I'm
going to use button and open and close square brackets. Now if you remember, this is how we use
to work with CSS selectors, we first wrote the type of HTML element. And then inside we wrote the
expression that we should filter this button by, and this is going to be data tooltip text is
equal to choose your currency. And then it is a great idea to assign this whole expression
to a variable. So I'm going to say currency, underscore element is equal to that one. And
down below, I can say currency underscore element dot click, so it will automate clicking on that.
Now let me change this parameter to have a default value. So we will not really have to pass the
value all the time. So now I'm going to open up the run dot p y on the right side. So let me split
that vertically. And let me open this in here like that, and then let me call these buttons. So
it will be bought that change currency like that. And then let me run this run.py file and
the test the results. So as expected, we are on the homepage, and you can see that we have
automated clicking only change currency element. So that is nice. That is a great first step to
achieve our goal. Now the next thing that we look to automate is probably to clicking on one of the
currencies. And for the purposes of this tutorial, let me first show how we could identify the
USD. Now in the future, we have a parameter that receives the currency type. So maybe we could
choose from the rounded p y, a different currency that we can automate to click on. So let me use
inspect again. So we could identify this element. And now if I click on this element
to expand its innerHTML elements, then you can see that in here, we have this
text and this text as well. But actually, the whole button is coming from this anchor
tag, because if I take my mouse to here, and I hover it, then you can see that we have
a green background surrounded our currency. So that's why maybe we should try to find these
a element. And we should use something that will help us to identify these a tag. Now I have
expanded the view of the inspect in here so we can have a cleaner look. And you can see that
we have here some key value attributes again, now I can try to find the data model header
async URL params, something like that, that is containing the text that looks like
selected underscore currency is equal to USD. Now I know that we did not learn how to
find elements that contains some substrings. But this is actually very easy with the CSS
selector method as well. So let's say in pie chart on how we can do that, alright, so down
below, I'm going to use a new variable that we can name it selected the currency element, and
that is going to be self dot find element by CSS selector. And here we are going to write the
expression again. So it will be single quotes a, and then we will use square brackets. And
now we will use these long expression that will help us to identify this element. So
it will be data dash, modal dash, Heather, dash, async dash again, URL dash Param, like that.
So I know that this is a long expression. But this is actually a great approach to identify this
element. And that is going to include a substring. So besides doing equals two, then we should use
asterisk equals. Now I know that again, this is not something that I have covered in the first
three episodes. But now we know how we can try to find an expression that contains substring. And
it is as easy as using the asterisk sign near the equal sign. And then I'm going to use here
double quotes. And I'm going to say selected currency is equal to USD like that. Now, if you
remember, then this is actually the value that this long the key had in this element that we
looked to automate. So now we could say selected currency dot click. And this should be enough to
basically automate clicking on the USD currency. Now, you may think to yourself, why did you hard
code this USD in here, besides you did not use the currency parameter. So that is a wonderful
point. And I'm going to just change it now. So I'm going to add here a formatted string. And
I'm going to refer to the value of the currency like that. And then what I'm going to do now is
going to run.pi by again, splitting the panes and working on run.py and I'm going to pass in
currency is equal to USD like the following. And then this line will be responsible to basically
replace this expression with the USD string, and this should be enough. So let's test
this out. So I'm going to run our program. Alright, so you can see that the
currency has been changed to USD. Now we could also test this one more time by
trying to click on a totally different currency. So let's go with G BP. Alright, so let's try to
do that. So let's open the PI charm again. And besides sending USD let's send GB P and run our
program again. And let's see now what will happen. All right, alright. So again, perfect. So
as you can understand, we have identified the perfect key value expression to identify the
element for changing the currency and from here, we We are ready to go forward with the next
step that our board should do in order to search for the best deals. Alright, so now that
we have completed the changing currency method, then let's design the next method that we shall
do now. So if you remember, we should now try to identify an element for sending some text to
the search text form element. So if we run our automation, again, just to have the browser being
open in booking.com, and wait for this automation being completed, then now we should automate
sending some text to this area. So I'm going to inspect again. And I'm going to try to find the
most smart expression as I can to send the text to this form field. Now, I said earlier in this
tutorial, that if our elements are including the ID attribute, then this is actually the strongest
attribute that the element could have to basically identify each uniqueness. So that's why I'm going
to identify an element by the ID with the value of s twice. So now I can go and say in a new method
in Python, something like this select place to go something like that. And I can basically
receive a parameter that will say place to go. And now I can go down and say search field is
equal to let me make the font bigger. So excuse me if you did not see the text quite well. So
I'm going to say here self dot find element by IE. And I'm going to find this by s, twice like
that. And at first, I'm going to do something that we really did not see before, which is
looking like search field dot clear. So clear stands for cleaning the existing text. So
if one day, we'd like to search something twice, then maybe we will have some leftovers. So that's
why cleaning the entire text ad first place is a great idea before we write some new fresh text. So
that's why I launched the clear method. And then I'm going to use search field dot send underscore
keys. And I'm going to basically saying the place to go that is arriving from this parameter. And
then I'm going to go to run the spy. And I'm going to say bot dot select place to go. And let's
use here New York as a first place to go. And now let's see what will happen. So I'm going to
run our automation again, and test the results. Now, by the way, we could comment out the
changing currency code, just because we don't want to probably execute it every time we
test a new area in our board. So I'm going to do that just in a minute. All right, so you can
see that the minute that I have wrote some text, then we received a drop down. So what
that means it means that we need to go now and identify the first result of our of
our drop down. And we need to automate clicking on that. So this is exactly what I'm going to do.
Now I'm going to click inspect on the drop down. And going to do that one more time. And
you can see that this is the value that we should automate clicking on that. So this
is actually an attribute with the tag of API. Now Li is actually standing for a list HTML
field that is basically commonly used if we want to display a list of elements. So that's
why we see this tag with the name of Li. Now we should again try to find how we
are going to click on these Li. So this is this element, I believe Yeah. And then if we
expand this a little bit more, then we will have a cleaner look. Now you can see that inside
each Li we have an attribute that says data dash i is equal to some string. Now I know that it is
hard to see. But if you will look in the bottom left, then you can see that once I point on that
element, then the first result of our drop down is being shown with green background. And if I
was to move my mouse to that element, then you can see that it now points to the second result
of the drop down. So what that means it means that the data I value is actually like an index of
all the results because the first result is having the value of zero and the second one is having
the value of one and the third result is having the value too, and so on. So that's why we call
the identifying element with the expression of data dash i is equal to zero. So I'm going to open
our pie chart, and I'm going to say right under select place to go something like first result is
equal to self dot find element by CSS selector. And our expression is going to look like l II and
square brackets again, and it will be data dash i is equal to zero like that. And then after
we have done this, then we are going to say first resolved dot click like that. And
then I'm going to leave everything as it is, because those lines are going to be responsible
to basically click on the first result. And this is exactly what we want to do. So I'm going to
run run up UI, and test the results once again. And I forgot to uncomment this section, so excuse
me for that. And now you can see that we got a perfect result, we automated clicking on the first
result of the drop down, and hence we have done that, then booking.com automatically took us
to the check in check out area. So here's the exact place that we can already try to automate
selecting check in dates in as well as check out there. So this is great. And this means that
we have done a wonderful job identifying how we call the click on that specific element. All
right, so this was the stage that we have left the previous tutorial. Now as you remember, when
we selected the location that we'd like to go, then booking.com, by default, popped up the check
in or check out the date that the user can select. So it means that we can automatically try
to select the check in date, and as well as the check out date. Now the time that I record,
this video will be may 2021. So if for yourself, you are seeing a totally different result, then
it probably means that you are watching this in some another date. So the results are going to be
different for you. But I'm going to write a method that will be generic enough to support any kind
of date. So let's go ahead and get started. So we need to somehow click on two dates, as the first
one will represent the check in and the second one will represent the checkout. So I will just click
on that right click and say inspect in do that one more time. And then I will go to the inspect
window. And let's see how we are going to automate clicking on those buttons. So you can see that it
is actually this one. And it is a child element of this TD element. Now te D stands for table data.
And what that probably means it means that this element is part of a bigger HTML tag that is
called table, which is designed for creating HTML tables. And this is also how this page represents
the calendar. As you can see the table in here and when I hover my mouse, you can see that it totally
gets colored with blue background. So now this means that we need to somehow automate clicking on
this one. And we can actually use a circle again, by selecting an element with data date equals
to some date. As you can see, in this case, it is 2021 05 16. So I'm going to copy this
statement, and I'm going to go back to pi charm. And let's try to automate that. So down here in
booking.pi, right where our booking class is, I'm going to type in one more method that
we can call it something like select, shake. Or we can just call it select date, something like
that. And then we will receive two parameters like check in date in the as well as a check out date.
And we can go down and we can say check in element is equal to self dot find element by CSS selector.
And this is going to have as a an argument, the following statement. So I will open single
quotes, and I will use TD because this is the element we'll look to automate. And then we will
open up and close the square brackets. And we will paste in the statement that we'd like to identify
the element by. So now you can see that this date is hard coded in here. And I'm just going to use
formatted string and replace the value from being hard coded to have the value of check in date,
which we receive as parameter and then it totally makes sense to go down and say check in element
dot click and then we are going to do this exactly same thing for the check out date because this
is how we are going to select a range of dates for deciding the dates of our vacation. So I'm
going to go Now I'm going to say check elevate, element, excuse me. And it will be equal to self
dot find element by CSS selector one more time. And I'm just going to use the same statement like
we did with check in. And I'm going to replace the check in date with check out date. So down below,
we can again, use the checkout element that click initially enough to basically decide the check
in and checkout date. And the only thing that we have to do now is go back to our run.pi and
execute this method by passing in two arguments. So it will be bought that select date, and we are
going to pass in check in date is equal to let's say 2021 dash 05. For May, and then they have the
month will be 16. And then we are going to do the same for checkout date. And we will pass in 2021
05 23, for example. Alright, so let's go ahead and test our program. Now we understand that we don't
have to really test the change currency anymore, because this works. So I can allow myself to
comment this just for now. Alright, so let's run this out and see what happens. Okay, so this works
very well. And you can see that we have the check in and check out dates. Now, let me tell something
very important in here. Actually, let's say that you would like to automate for selecting dates
that are two months or three months from today. So this is something that I'm not going to show
in this tutorial, but you have all the utilities to basically achieve this by yourself.
So say that you want to select some date, that is going to be four months from today. So
this means that you have to automate clicking on this next button three times. And then you will
have the option to select range of dates, that is four months from today, which in my case will be
September 2021. So I just wanted to mention that I know that this program is not going to support
selecting vacations in dates, like five months or six months from today. But again, you have all the
tools that you can try to automate this action by yourself. Alright, so the next thing that I'm
going to straightforward show in here is how we can select the adults to decide our vacation. And
to do that, we need to first simulate clicking on this area. And then we are basically looking
for automating it clicking on this minus sign, or this plus sign to basically decide the adults.
Now again, we will try to write a method that will basically receive a parameter with adults count
something like that. And then we will try to simulate deciding the adults for our vacation.
Now, I'm not going to show for children or rooms, because this is going to be probably the same
logic that we need to repeat. But again, you have the option to extend your robot in whatever way
you'd like to. Alright, so now, first of First, let's start identifying this entire area in
here. So inspect, and loaded again. Alright, so we look for the element that will basically
color the entire area of this selection button. So I think this will be this label with the
ID of XP, guests toggle. So I know that the font is a little bit small in here. But this is
basically what it says here. It says to us HP guests toggle. So I'm going to just copy
this value. And I'm going to go to our board. And I'm going to go down and write one more method
that we can again, name it something like this, select adults like that. And then we will receive
count as a parameter. And we will see how we are going to control the count of our adults in this
method. So down below, I'm going to say selection element, something like that. And I'm
going to use self dot find element by ID, and I will paste the value that I have copied
previously. So you can see that it is XP double underscore guests double underscore toggle, and
I'm going to just selection element dot click like the following. And now let me pass in some default
value in here like one. So we will not receive arrows when we call this from run dot p y and
then I will go here and I will say Bob dot select adults, something like that. And now let's see
what will happen if we will run our program. So until now, we should expect to see only
this page being popped up. I mean this area, not the page and it looks okay. It looks
like It works. So we can continue on to see how we are going to control the adults for
our vacation. Alright, so now we have to somehow control how we are going to select the adults
count. Now this might be a tricky action to take, because let's say that you want to go with
three adults, then it means that in that case, you only need to automate clicking on the
plus sign once because the default value is two. But what if one day the default value
is not going to be two adults in booking.com, say that the default value is going to be changed
to something like four or five, three or any other count. So we can actually be more smarter. Rather
than trying to automate clicking on the plus sign, depending on whatever adults count we are going
to pass in, in our method. So we can first try to decrease the adults count to the minimum value.
And then we can have more control how many times we really need to click on the increasing button.
So at first, we can write some logic to decrease the count of adults until the value reaches one
adult, because this is the lowest value of adults that we can have. And then we can try to click on
the plus sign, depending on the adults count that is passed in. So this is a more generic
way to complete this kind of task. And it is going to be very interesting to implement
that. So I'm going to go to our PI Chairman, you know what Before that, we need to understand
how we're going to click on the quiz button. So let's do inspect and see how we are going
to identify the element of decreasing. So let's expand this and see what is going on here. So
you can see that when I hover my mouse in here, then this button of decreasing is being colored
with the green background. So this is the button that we looked automate clicking on, and
you can see that it has a unique value of area label with the value of decreased number of
adults. And I believe that we are going to say the same thing for increased number of adults weight
area label as its key. So I think it should be this one. So if we open this element, and
see its attributes, so I'm just going to move here. And Alright, there it is. So you can
see that it has area label increased number of adults. So this is the approach that we're going
to identify those buttons. And let me basically copy the statement and try to find
this element by CSS selector. Okay, so right under the Select adults method, we
are going to use something like decrease. Adults element is equal to self dot find element
by CSS selector. And we are going to pass in button and open up and close square brackets and
basically paste the key value statement that we have copied previously. And you can see that it is
area label is equal to decrease number of adults. Now we need to somehow simulate clicking on that
button until the adults count reaches one because as we said, it will allow us to have more control
to basically decide the adults count. So for that I'm going to use while true, and then inside this
wild rule, we will write an if statement that will look up for the value of adults count. And once it
reaches the value of one, then we will go outside of our while loop. So I'm going to say here while
through. And I'm going to go here and basically fix the indentations. And then I'm going
to go down and I'm going to say decrease adults element thought click. Now if I leave the
code as it is, then it is always going to try to click on the crease button, which is obviously not
what we want. But we want some logic to basically identify if the value reached the number of one.
And if so we'd like to get out of the wild true. So it is going to be something like if the value
of adults reaches one, then we should get out of the while loop. So let's see how we're going
to identify this. So I'm going to go back to our browser, and I'm going to search for the
element that displays the value. So it should be this one in here where my mouse is pointing
me zoom in a bit so you can see more clean. And you can see that I'm pointing exactly to here. So
let's go inspect and you can see that it actually depends on this span element. And you can see
that it has the text of one. So what that means, it means that we can try to basically Find this
element and see what its value. Now, if I add here plus, then you can see that it got updated. So
it means that this is the exact element that we need. Now I can actually see in this inspect page
that we have more elements that are being updated with the adults count. And you can see up top in
input in here that we let me zoom in. So you can see that this element is actually getting updated
continuously as well. And the reason I want to select this element is actually because it has
ID. And if we remember I said that the ID is the strongest attribute that the HTML element could
have to identify its uniqueness. So if I click on plus hearing, and then you can see that it gets
updated. So I'm going to just find this element by the ID of group adults. And I'm going to go
back to Python and see what we can do with this element. So I'm going to go here and say, adults
value element is equal to self dot find element by ID, and it should be the value of group adults.
Alright, so now that we have control in the element that displays the value of adults count,
then we should somehow receive the challenge of the adults. Now this is something that we did not
learn how we can do, because we only learned about actions like clicking or sending keys. But we did
not learn how we can receive a value of some key in HTML elements. So it is going to be by using
the adults value element which we have identified in here. And then it is going to be basically by
launching a method that is called get attribute. Now get attribute is basically a method that
receives a key name, and then it tries to give you back the value of whatever attribute it is. So
if we go back to our browser, you can see that we need to work with this key that is called value,
because this is what displays the adults count, right? So we need this key. So I'm going to go
here and go back to a pie chart and basically pass in here value. And this entire statement should
give back the adults count should give back the adults count. So I'm just commenting this up
because the code is starting to be more complex, so we can remember what each line is responsible
for. So down below, I'm going to type in a conditional and it is going to be much better if
we will assign this entire statement that to a separated variable. So I can say something like
adults value is equal to that entire statement. And let me just write here some split lines
because we want to have more organized code. Okay, so down below, I can say something like if adults'
value is equal to one like that, now, I already know that this statement is going to give us back
an error, because by default, the get attribute returns the value as strings. And we cannot
write if conditionals with comparing strings to integers. So we are going to convert these adults
value to integer exactly in here. And then we are going to check if it is equal to one. Now once it
equals to one, then we can break the while true. So let's see if this logic works. So we should
go ahead and test the run.py file by executing it. And we should see the adults count being set
up to one adult. So now I'm going to test this up. And Alright, so we can see that it works perfect,
the adults has been changed to one. And the only thing that we have to do now is identifying this
plus button and basically say that we'd like to go away to 10 adults, then we'd like to launch
a for loop that is going to click on that button nine times. So let's go back to pi charm and
implement that now to really test if it works properly, then really we are going to assume
that we are having 10 adults in our vacation. So I'm just going to pass in this argument when
we call this method. So now let's go to our method and minimize this wild rule because we have
finished working with it. And we can say increase button element is going to be equal to self dot
find element by CSS selector one more time. And if you remember it was a button with the key
value pair of area labeled is equal to and I'm going to open those double quotes and say increase
with capital. I Number of adults with capital A, and then I'm going to go down. And I'm going to
launch a for loop, applying the range building function, so we can really have control in the
amount of times that this for loop is going to execute. So I'm going to say for i in range, and
we are going to use range of count, minus one, because if you remember, I said that we should
decrease this by one to really achieve the exact count that is passed in in here. So we are going
to say increase button element dot click. And that's it. Now I'm not sure if you know or not.
But basically, if you're not going to refer to the variable that is used in here, then by convention,
you don't really need to pass in a variable name like I or a or something like that, you can just
use underscore like that and leave it as it is. And this is just a convention in Python that says
that we are not going to make use of the variable value. So now we are ready to test the entire
program. So I'm going to launch our run.pi file, and we show the C, the adults count being set to
10. So if we run our board, and wait a minute, all right, so you can see that it really works
perfect At first, we use this safety logic to basically set the adults to one and then we have
full control of the adults count that we'd like to set. Now this is really generic and working
perfect, because even if we are going to pass in count equals to one from our method, then what
is going to end up happening, it is going to go to here, and it is going to try to
apply a for loop in range of zero, and it is never going to run because if you are
having a for loop with range over zero, then you are basically not iterating over anything.
So the adults count is going to remain one. And that is perfect. So this logic
really works. And we are basically ready to go ahead and click on the search button to
really test if we are going to receive any results. So it is going to be very easy, because
by convention, each search button in whatever site it is, is mostly having a key value pair that
says type equals to submit something in that time. So we are going to click on Inspect and see
if this is the same for this website. So if we expand this, and go here and look up for this
button, and you can see that it has type equals to submit. So again, we can automatically try to
basically identify an element with CSS selector with HTML type of button that has this key
value pair. So if we go back to Python, we can easily just create one more method that
we can call it click Search. And we can basically receive nothing in this method because there is
not going to be any argument we'd like to pass in. And we are going to say straightforward itself dot
find element by CSS selector. And we should find a button with this key value pair, and basically
assign these to a variable like search button. And then later on, we like to click on that.
Alright, so here, I'm just going to call this board dot click search, and see if everything
works properly. Now to really test the entire logic, let me uncomment the change currency and
change this to USD to really see if everything works. And let me challenge this program a bit and
pass in another date. So we can maybe say here 19, and pass in here 25. And really test if everything
just works and functions properly, even though I have customized the value that a little bit. So
if we run our program, and basically do nothing, so I'm not going to touch my mouse at all, and
see if everything works. Okay, so currency date, adults search, perfect, just perfect. Everything
really works well. And we see some results about different hotels from these booking.com
website. And this is just exciting because we really have some results going in here. And
in the next episodes, we are going to dive into more complex stuff because we need to only
identify the best deals and by saying best deals, we need to somehow automate applying
the filtration to that result. Alright, so here you can see that we have
some results about what we can really book. But as we can understand from this page,
we really have multiple options for what we can filter to basically improve the results that we
received. So for the purposes of applying some filtrations then we're going to need to write some
methods that will be responsible to apply those filtrations. But to those in that booking class
might lead us to a situation where we are going to have too much methods in one class. So that's why
we will basically come up with a new Python file that will include some methods about filtrations,
once our bot has reached the page of the results, so if we go back to our Python now, then we can
actually design our project in the following way. So let me open up booking.pi. And we can go
down here, and we can say something like, apply filtrations. And this filtration is should be
filtrations. And this one will actually go ahead and instantiate an instance of another class that
could be named something like booking filtration, something like that. And then in this class, we
could basically include some methods that will be responsible to really go ahead and apply those
filtrations with the scillonian. Driver. So let's go ahead and start working on such a design.
So I can go here, and I can say, new file, and I can name this booking underscore filtration.
And then inside that, I can write a comment, what is the purpose of these pages. So it will be this
file will include a class with instance methods that will be responsible to interact with
our website. After we have some results, to apply filtrations, so we could really
understand what this page is about. And right after that, we can basically go down and we
can say class booking filtration. And this class is not going to inherit from anything. So we can
go directly inside the constructor. And actually, the constructor needs to receive one parameter.
And this parameter is going to be actually the driver that we are going to pass in his argument
because we also need this class to work with the WebDriver. So if I go to booking.pi, then we
can actually see that through how the process of writing methods, we do it on the self object.
So we need to somehow pass the self object to the instantiated instance of this booking filtration.
So this is going to look like something like rival equals to self in the future. So that's
why we should go to our booking dot filtration, and basically receive here driver as a parameter.
So before we continue working on this one, let me quickly fix the arrows in the other file. So I
will right here and pass to ignore the arrows. And I will go to booking.pi. And I will basically go
up top of this file. And I will say from booking, dot booking filtration, import
looking filtration like that. And I will jump here, one more line.
And I will go down here. And I will say, filtration, something like that. And I will
basically instantiate the booking filtration class. And I see that I missed the tea here as
well. So sorry about that. And then later on, we can basically decide what kind of filtrations
we want to apply within this method. So that's actually a good way to design our program. Because
once we have too much methods in our class, then we might have a tough time to maintain our
code in the long run. So that's why designing the filtrations in the following way could be a
great idea. Alright, so now that we understood how we could structure the booking filtrations, then
let's see some good candidates for what we can filter by the results. And you can see that we can
basically apply some star rating for the results. So that's going to be the first method that we're
going to write within the booking filtration file. Now we can see that we have this entire box
in here that is responsible to give us back all those check boxes. So I'd like to first work with
that element, because you can see that we have some more check boxes in that page. And I don't
want to confuse these five stars, for example with that one, because this same check box is appearing
also in the popular filters. So that's why it is a better idea to first take our board and identify
the element that is responsible to display this whole area. So I'm going to try to click on
Inspect in here. And we're going to do that twice. And you can see that we have this filter
category title. So the parent element of this is probably what is responsible to display all
those checkboxes. And if we take our mouse to the parent element in here, then you can see that this
is exactly the box because it also says filter box in its class name and it also has an ID that says
filter on this coral class. So that is perfect, because we can try to use our board to basically
select this element with that ID. And then we are going to do something very special that will be
responsible to display all the Child Elements of this div element. So let's go ahead and work on
that. So I'm going to copy this statement in here. And I'm going to go back to our PI charm. And you
can see that I am inside the booking filteration file. So at first, we should assign the driver to
the self object of this booking filtration class. So it is going to be self dot driver is equal to
driver. And if you remember, this is always going to receive the original driver from the booking
class itself. So that's why I do this little trick in here. And I can basically launch a method like
a fly star rating in here. And this will receive self as a parameter. And now I can use something
like self dot driver, dot find element by ID. And the ID should be filter underscore class,
because this is the ID of the element that would like to filter by now notice how we did not
have auto completion. And this is very annoying, because in libraries that are very large, like
selenium, we probably always like to have auto completion for the different methods to basically
make our lives more easier. And the reason that the auto completion doesn't work, it is because
this parameter doesn't have a specific type. Now there is actually something in Python that
is called typing. So we can really decide the parameters type to work with auto completions.
Now to show you an example of how type things are working, then I will use I mean to explain this
with a more familiar, a type of variable that we commonly use that is called a list. So say that
this class is actually going to receive one more list like my list, and we always like to pass
in here a list. But if we go here, and say my list, then we will not have auto completion
for methods like append, remove, and stuff that is very related to lists. And again, it is
because this parameter doesn't know it's typing. So we could actually do something like from typing
import list. And we could go here, and we could say that this one is going to be list. And now
if I was to say, dot, then you can see that I have auto completion for the list methods. In
the same approach goes for the driver instances of selenium, we could basically import a library
to decide this drivers type. And it is going to be as easy as going here and saying from Selenium
dot WebDriver dot remote dot web driver import web driver like that. And let me remove the
examples because we really not going to receive list as a parameter. This was just an example.
And then I'm going to say here, call on web driver. And once we have set the type
of this driver parameter, then we are always going to have self dot rival dot and you can see
that we have those auto completions as expected, because now the self dot driver object knows its
type. So that's why this is very useful. And now we can go ahead and basically assign this to a
variable so we can name it something like Star filtration box. And then we could use that. And
now the next step should be how to identify the Child Elements of some element that we have
selected. And this is something that we can achieve by using CSS selectors. So let me show you
how this could be done. So star child elements, this is our I'm going to name my variable. And I'm
going to now use self dot driver. And I'm going to use find elements and not elements. So I know that
this is the first time that we use more than one element as a method. But actually there is also
the option to finding more than one elements in a website. So I'm going to use find elements by CSS
selector. And actually there is a convention to find all the Child Elements of a given element and
that will be by basically using the asterisk sign inside a string. Now I want you to take a look
and think about what is wrong with this statement. So we go ahead and say self that rival and we
launch. On top of that these find the limits of ICS cert or method. So this will end up giving us
all the elements of this entire webpage. And this is wrong because we only want the The elements
of star filtration box element, I mean all the Child Elements of it. So what we can actually do
is we can remove this self dot driver, and we can replace this with Star filtration box. And then
this line will be responsible to give us all the elements that belongs to that star filtration
box element. So now, we could go ahead and use something like print when star child elements
to really see that we have some elements stored in this variable. And we can go to booking dot p y.
And we can also use here something like filtration dot apply star rating. And if you remember, we did
not use this method in our main file, which was run.pi. So I'm going to go here, and I'm going
to always execute what dot apply filtrations. And we want to leave here, this method always being
executed. And then we will customize what methods we want to execute in this apply filtrations
method inside the booking.py file. So now let's execute our entire project. So I will run run that
pie and see what happens. And in a minute, I will also show you the results in our console, because
we are printing something. So let's wait for that. Alright, so if we go back to here, then you can
see that we receive as a result for the end. Now inside those for the elements, we look for the
five checkboxes that we need. Now if we go back to the Chrome browser, again, I actually have set
up what are the exact elements that we need. So we can see that I have expanded here, this filter
class element. And if we take a look a little bit more down, so if we go to like this area, then in
here, you can see that it is more focused on the checkboxes. And inside of that, we have all those
eight tags. And those eight tags are what really, we should click on them. And you can see that each
of those eight tags are having some more child classes, I know that it has a very long structure.
And you can see that at the end, the innerHTML of one of the Child Elements is one star. So what we
can actually do, we can try to iterate over those for the elements in we can look up for those that
are having the substring of one, two, or three, or four or five. And this is the same structure
for all other stars. So if we go and expand the two stars element, we can actually see that it has
at the end innerHTML with the value of two stars. So those are the elements that we look to click
on them. So that's why we can go to here. And we can basically open up the looking filtration.
And we can work on those star child elements by iterating over each one of them. So we can say
four star elements in star child elements. And we could use something that will look like if star
underscore element dot get underscore attribute. And we should receive the attribute that is
really responsible to display the inner text. So it should be inner HTML like that. So this
is a convention to find the values of what is inside those HTML tags. So for example, if we
were to have a tag that is looking like that, and we have some value like gym, then if we want
to receive the gym value, only, then you show the launch obligate attribute medal. And so that's
why we use this expression in here. And we want to look if this entire expression here is equal to
something like one stars, right, so this is what we look up for. And of course, I'm not going to
hard code this in. And besides we are going to receive use something like Star value. And we want
to turn this to a formatted string. And we want to change this tool store value like that. And if
this entire expression is true, then we want to do something. Now before I go ahead inside of this
if statement. Let me write in here fast. At first, we want to convert this entire expression to a
string just to be more safe. So I'm going to just do that and wrap all this expression with the str
method. And I'm also going to launch a method that you may be seen before that is called strip. Now
this strip is a method that will be responsible to clean all the white spaces, because we might
have some white spaces when we want to see the values of the inner HTML files. And this is
basically going to be responsible to clean all of those. Alright, so now I can go inside of
our if conditional and I can basically say star element, dot click. And the reason I can do this
right now, it is because we are going to iterate over for the elements. And if we have one element
that eats innerHTML is actually star value stars, then we probably want to click on that. So let's
test this in action. So I'm going to basically now run our run bot p y. But before we do that,
we should go to booking dot p y, because this is where we use the applying star rating. And we
should pass in some star value. So let's go ahead and try to click on five stars. So I'm going to
pass in in here, and let's do these keywords so we can really understand what this is about.
And now we can launch our bot again. So let's go ahead and do that. And let's see what will
happen. So we search for some results as usual. And then it should go ahead and try to click
on five stars. And if we actually go down, then you can see that it click on here. So that
is perfect. And you can see that this one got also activated. And this is great because we were
able to really achieve our goal. Alright, so now that we understood this, then there is going to
be one more in the future that we'd like to add to this method. Because this is just realistic
sometimes to search for results that are kind of like four stars or above, or three stars or above
or something in that kind. So that's why we should somehow receive as a parameter, not just one
store value, but maybe receive more than one store value. And the way that we can achieve this is by
turning the store value being arbitrary argument. And that is a way that we can pass in many
arguments to one argument, basically by doing it with adding an asterisk sign before the parameter
name. Now if you don't know what this does in here deeply, then I have a video that explains what
is the difference adding one asterisk sign near a parameter to adding a double asterisk sign. And
this is commonly seen with orgs. Or maybe you have seen previously double asterisk key w arms. And if
you don't know what are those, then I have a video that explains the differences between those in the
suggested video. So definitely consider taking a look on that one. All right. So now that I have
changed this to being an arbitrary argument, then let me change this to store values because
it will be just more friendly name for that kind of variable. And I can go down and basically
use a statement like for store value in store values. And I can take my entire code in this
area and basically insert this into a new for loop. So it will be something like that. And
now that we have done this, then let's test this out with passing in multiple style values.
And the way that we're going to do that is as easy as going to booking.py. And besides passing
in one single value, let's try to pass in three, four, and also five. So we should see the results
that their star rating is three stars or above. So if we run our program now and wait a few
seconds, then let's see what will happen. So as usual, we see the regular
behaviors in the searching results. Alright, so if we take a look in here, then you
can see that we have activated those star ratings. And if we actually take a look in your filters
box, there, you can also see that it has been activated successfully. So we have done a really
great job implementing the star rating to this booking.com website. And we can continue from
here. Alright, so you can definitely understand that there is no limit for the filtrations that
you can apply right after you are inside the results page. So I'm going to add one more
method for the purposes of this tutorial, that I personally think that is very useful. And
I think if we could have the option to take our board to click on the sorting option from lowest
price to higher, then it is going to be very, very useful. So if we take a look in the results
page, then you can actually see that up top we have some more filtration or basically just some
more utilities that can help us to customize our results whether you can see that we have the
option of clicking price lowest first. So we would like to automate clicking on that. And I'm going
to click on Inspect. And you can see that this is just a button with only this attribute in here
which we have to find to probably click on that. And that is going to be this data ID is equal to
price. So we can grab this key value attribute and find This way, the CSS selector and basically
try to click on that one. So we can go back to our pie charm, and basically to our booking
filtration file. And we can design here one more method, and we could name this sold price lowers
first. And this is just going to try to find an element. So we can name it just element. And that
will be equal to self dot driver, dot find element by CSS selector, and this will be that one. And
this will just receive Li because this was the element pipe. And we will open up our
square brackets. And we will say data ID is equal to actually I copied this statement.
So excuse me about that. And I can just paste in data ID is equal to price, make sure to use double
quotes in price. And then down below, I can say element thought click in that will be it. Now if
you remember, this is only the page that we write our methods, but we don't actually call them in
the place that we call them is inside the spoking dot p y file inside the apply filtrations. So
right after we apply some storage thing, we could also sold our results. So we could say filtration,
but sold price lowest first and this is not going to receive anything as parameters. So we are
not going to pass any arguments. And now let's test this entire program now inaction. And let me
actually test our program and wait and only use four to five stars. All right, so if we run this,
then and wait a bit, let's see what will happen. Alright, so you can see that we have also
activated the price lowest first button, as you can really see that we have some more
cheaper results now in the first page. And if we take a look in our filtration, then you
can see that we got four stars and five stars. So I think this will be pretty much enough
about the filtrations that you can apply. If you want to basically see useful results. Of
course, there are more things that you can apply to receive better results. And as you can see the
technique of that it is pretty much going to be similar to finding the elements with the
different methods that you can use within the Selenium library. Alright, so one of the first
things that we're going to do in this episode is to support running this project, not always
from an ID, because in some cases, you only want to execute the bot to do its actions and to
receive some results. And for doing such action, you may not always want to open it in a specific
IV. further than that, sometimes executing bots from the command line is just more
comfortable rather than going to pi charm and basically pointing to your project. And then using
the shortcut of shift fn to execute your project, sometimes the only one to do it from a terminal
executing Python, and then referring to the file, in our case it is run.pi. Now I'm not gonna
lie to you, but our project currently does not support such a behavior. Because we have
this tricky line inside the booking.py file, that is going to add the location of our
driver path to the PATH environment variable. Now executing such a line from Python will work
because the Python knows how to take this line and attach it to a Python process and really
add this location to the path system variable. But when it comes to other processes that
we want to execute the project from them, for example, a common line interface in Windows,
then we are going to have some troubles because we need to add the location of our Selenium drivers
before we execute the project. So it is going to be tricky to handle that from the terminal level.
And I'm actually going to prove you that our project won't execute successfully if we will try
to run the run.py file from a terminal. So if you remember, in this directory, we have this file,
which we look to execute. And if I was to say Python, run dot p y, then you can see that it
complains about how the chromedriver executable needs to be in path. So I'm going to fix that. So
you will have the ability to execute this project from your terminal. It doesn't matter if you
work with a Linux environment or if you work with a Windows around. Alright, so the way that
we're going to fix that is by using try and accept blocks. And we can actually try to execute those
lines of code. And if we will have some errors, then we could always bring to our users that the
user needs to basically execute some line from a command line that will add this C Selenium
rivals folder to the path system variable. So let's go ahead and try to design that. So I'm
going to Grab all those lines of code in here, and I'm going to indent all of those ones. And
I'm going to wrap it up with the try block. Now, right after this, we can go down here,
and we could say, accept any exception. And we could grab the exception inside a variable,
something like E, maybe. And as a starter, we could say something like print, there is a
problem or running this program from command line interface. So that is just a great start handling
things inside the except block, of course, there is going to be some more additions in the
future. So I'm going to go back to our terminal, and I'm just going to run the same command. So it
is going to be python run.pi. And you can see that now we automatically see this, there is a problem
running this program from command line interface, because we were able to hit the except block,
because we really have some exceptions. But in some other cases, we might also
have some problems directly in our bot. Now, not all the exceptions in the world are about
how the chrome driver is not inside the path. So that's why it is quite dangerous to
output something like that for all the exceptions that are going to occur in
our program. So that is why we need to verify that we really hit this message that says
chromedriver executable needs to be in path. So that's why we could go back to Python. And
we could verify that the message is really about how there is not a folder inside the system
path. So we could say if str E. So that is a way to cache the exception message. And we could go
back to terminal and check the substrings of this specific exception. So if we were to check if this
in path is a substring in the exception message, then it really means that the problem is about how
the chrome driver executable needs to be impaired. So I'm going to go back to pi charm. And I'm going
to say if impaired inside a string like that, in the exception message, then we could go down
and we could print this message. But if we have some other problems say that we have a problem
with selenium, say that we have a syntax problem, then we would like to raise the
original problem. And that is achievable by easily saying else. And basically using the
keyword or phrase like that. Now the minute that you are doing something like this, then once we
don't hit that specific problem, then we really raise the original exceptions. So that is a great
way to handle the exceptions. So now we could verify that this works. So we could go back to
our terminal. And we could clean the screen for a minute. And we could say again, python run.pi. And
you can see that we again received this message. So that means that our if conditional works
great. Now To be honest, I am going to change this message to be more friendly. So the user could
understand what command needs to be executed to add the location of our chrome drivers to the
path system environment variable. So I'm going to grab a code snippet that I prepared as a print
message. And I'm just going to paste the same in here. And obviously, you can grab this from
my website in the eighth episode of our entire series. So you can see that here I have a nice
error message that says you are trying to run the bot from command line. And the backslash n is
just an escaping characters to just jump to the next line. So in the next line, we say please add
the towpath your Selenium drivers and for Windows use this command. Now I know that this looks
a little bit complex. But that is actually a built in Windows command that we can execute to
add some more locations to our already existing pad system around variable. Now as I said in the
first episode, our path environment variable has already around 50 or even 100 locations that we
have as a value. So that's why we use set path and we add the original paths. And in
addition, that's why we have semicolon, we add our path, which is going to be C Selenium
drivers or whatever folder you have set up the chromedriver window and if you use Linux, then you
should execute this line which is looking pretty much similar. Only the windows includes the set
command. Alright, so now we could basically go to our terminal. And again, run this command and now
you can see that we have a very friendly message. So the only thing that I have to do now is grab
this and paste this in and now really customize the path that we should have. Add here. So it
will be Selenium rivals, once again. And I'm not always sure if it needs to be added with a
backslash at the end or not. So I'm going to try both. And I recommend for you to try both
as well. So let's try that and then try to run Python run.pi. And you can see that I again,
received this message. So let me clean the screen and run the same command with a backslash at the
end. And again, executing python run.pi. And now you can see that our bot works. And you can see
that everything is pretty much functioning as expected, you'll see that we were able to search
the results, you can see that we were able to filter out and also applying the sorting. So this
means that it works perfect. And if we take a look to our terminal, then you can see that we actually
received some warnings that we are really going to fix soon. But at all in the big picture, our
board functions perfect if we even execute it from a terminal. Alright, so now you might notice some
weird warnings about their withdrawals, listening to our localhost with some port, etc. So that is
actually something that we did not see before. But actually, when we work with browsers like
Chrome, which is in our case, Chrome driver, then chrome now comes built in with some
dev tools. That is a set of web developer tools built in directly into Google Chrome
browser. And I think when it recognizes that we execute some automated Chrome browser to run some
test cases, or basically automating websites, then it already executes that utility. Now, in this
tutorial, I'm not going to cover too much about their tools. So that is why we can allow ourselves
to ignore those kinds of errors. And to ignore those kinds of errors in that stage, we
need to go back to our booking.py file, and basically add some additional configurations
to our WebDriver instance. So it is going to be as easy as going back to pi charm and add some
lines in this file in here. And if you remember, we have some line that says super, that is
really responsible to instantiate an instance of the inherited class and as well as the class
that we are writing just in that moment. So that is why we need to customize this line, because
we need to pass in some additional options to this class that we inherit. So it is going to
be something like that. So we are going to say options is equal to web driver dot chrome
options. And you can see that it is just a built in class that I instantiate. And then
I can say something like options, dot add experimental option. And I'm just going to write
in here some strings that will be responsible to ignore those kinds of errors. And I'm not gonna
lie, I searched a lot about this dev tools. And why do we see those warnings. So I ended up by
grabbing this code from a Stack Overflow poll, which I will add in the description. So you can
take a deeper look in the discussion that is going on there. Alright, so it will be exclude switches
like that, pay attention that the switches is with a capital S. And then there is going to be one
additional value that I will pass in here, which is going to be accepted inside the list with one
element and it is going to be enable dash logging, like that. And once I have done this, then we need
to grab the options, which is equal to an instance of Chrome options. And we need to pass this in
in the initialization line. So it is going to be options is equal to options like that. And then
once I have done this, then let's test out if we still see those logs. So I'm going to open back
our terminal. And I'm going to say again, python run.pi. And I'm just going to let our bot running
in the background. Let's see what is going on with the terminal. And you can see that now since
we ignore those kinds of logs, then we really don't see anything. And you can see that our bot
finished its job. And that is perfect, as we can see the results in this Chrome browser page. So
that is one way that we can ignore those kinds of errors. And we can continue from here. All right,
so now that we were able to figure this out, then there is going to be one more thing that we'd
like to test in this stage. Now we like to test if we will really see the original exception, even
if we are having an exception that is not about the chrome driver being in the path. So that's
why let's do something wrong in our project by purpose. So I'm going to go to our PI charm and
I'm going to say hear a is equal to two divided by zero like that. And we should receive basically
zero division error before even our board starts. So that is why we should now go back to
our table again. And let's clean the screen and try to execute our bot one more time and see the
results. All right, so we can see that we see now the original exception, which says to us zero
division error, because we really try to divide a number by zero. So we will have some arrows
and you can see how our award did not even start executing the lines of code, because we had some
early exception. So that is perfect. And this is a great preparation for the future of this board
project. And we can now continue to extend our application as much as we want, and even test this
with a terminal. Now the main reason that I really wanted the ability to execute this project from a
terminal, that is because if you remember from the preview of the board, then we like to visualize
the results of the deals in a nice way. So the user can really have engravable look on what are
the results for the best deals. And we probably want to avoid doing that with the PI charm. And we
probably want to visualize it nice with terminal. So that is why I want the ability to execute this
board from any terminal, even if it's a Windows environment, or even if it is a Linux environment.
Alright, so let's look into the next element that we should identify in order to start reporting
the results to the user that uses this bot. So as expected, I'm going to run this project
now from the terminal. And I'm going to make use of this recommendation that we have generated
in the print line. So we can really have the drivers folder under the patch system environment
variable. So I'm going to execute those lines. And as you can notice, I replaced this path with my
original path. So I'm going to run that. And right after that, I'm going to say Python run.pi exactly
like the previous episode. Now, just a reminder, if you remember, I showed some exception
by purpose in the end of the last tutorial, and I deleted that, and it was a zero division
error. So make sure that you have deleted this. And then I can go back to our browser. And you
can see that we have the results as expected and the filtrations and the sorting are pretty much
fine. Alright, so now we should look into that large element that is responsible to display all
the results. Now I'm going to be honest with you, I'm not going to show how you can see all the
170 results. But we are going to just seek for the first page for the purposes of this tutorial.
So that means that we should identify an element that has 25 child elements that are responsible
to display all those boxes that are displaying the deals price, hotels name and star rating and
stuff like that. Alright, so let's get started. Now again, our goal is going to be first to find
that parent element that is responsible to display all those 25 boxes, that each one of the boxes are
responsible, as you'll see to display the hotel's name and star rating and stuff like that. So at
first, let me try to find the element that is pretty much covering the entire box. So I scrolled
up to the first result. And let's click here on Inspect. And I will do that twice. Excuse me about
that. And as you can see, this is for example, the title of the first box. And if I
scroll up a bit, and here, for example, we only see the part that is without the
image, which is again, not what we want, we want the entire box. And as you can see, this
one is responsible to display the entire box. And if I minimize this element, and you can see
that now if I take my mouse to the second one, then you can see that the second box has been
covered with blue background. So this means that those div tags that are having maybe the data
score, or data or tail ID are what responsible to display each one of the boxes. And you can
also see that the parent element of all of those is a div tag with the ID of alternate list Enter.
Now before we go ahead and start writing this in the Python side, let me show you some tricks that
you could have done in the JavaScript side of the web pages. Now don't be afraid of JavaScript,
I know that this is a programming language, that there is a great chance that you did not
practice it. But I'm just going to make a short walk through how I identified when I developed
this project, all of those 25 boxes. So let's go to console Alright, so the council is actually
an area that you can execute pure JavaScript code that is going to be responsible to identify
each one of the elements that we look for. So if we go to console and Way, ignore what
is going on here. And let me zoom in a bit. So you can see everything. And I am first going
to clean everything in here. So it is going to be clear. And then this is a metal that we should
execute. So, like that, and then you have a clean console. Now to grab all the elements that are
responsible to display this page, then we can use the built in document statement. Now this is again
from JavaScript. So don't confuse it with Python. But I just want to make a short walk through how
I identified the elements that I need. So you can execute a method that is pretty much similar like
in selenium, and now it is called get element by ID. Now pay attention that E, B and the AI are
capitalized. And then I'm going to say here, or fail list underscore inner. And if you remember,
this was the ID that is responsible to display all the results. And I'm going to assign this whole
expression to a variable, we can name it like hotel list, and this is going to be equal to that
expression. And you can see that once I click on Enter, then you can see that it returns me the
element that is responsible to display all those boxes. Now I'm again going to clear the screen
and work with the hotel list library. And I mean the variable. And then on top of that I'm going to
execute get elements by class name. So II, B, C, and n are capitalized. And I'm going to find here
the class name that is pretty much unique for each box. So I actually found this ASR underscore
property, walk string as unique per each box. Now, you can see that even before I executed this,
it is going to be responsible to give me back 25 elements. So what that means it means that now
we have the control of all those 25 elements that we can work with. So if I press on Enter,
then you can see that we have a result with 25 elements. So again, this is what
we need to do on the Selenium side, we should first find that parent element with the
alternate list, inner ID. And then on top of that, we should go ahead and execute, find elements
by class name, and we should pass in this value. So let's translate what we have done here to
Python. And I think that the fact that I showed you this on the JavaScript side is just one more
utility that could be useful for you. Alright, so we are inside pi charm inside the booking.pi
file. And I'm just going to go down here and type in one more method that we can call it report
results. And then inside this method, we are going to say self dot find element by ID, and it
is going to receive hotel list on the score, Enter. And then on top of that, we are going to
execute dot find elements by class name. And let's actually split the line so we can have a cleaner
look. So I'm going to do that in here. And this by class name is going to receive as argument
ASR underscore property underscore block. And I need to assign this entire expression to some
variables. So we can name it artell underscore boxes, this is going to be equal to that one.
And actually, let's test first that this works. So I'm just going to say return ortel boxes, and
I'm going to go to our run.pi. And I'm going to say print the length of bot dot report results.
Because if you remember, this is returning a list. And we only like to see the length of this list.
And of course, this should return us 25. And if it is then it means that we are ready to continue
on the further actions. So I'm just going to go to our terminal. And I'm again going to execute
Python run dot p y. And let's wait for the results of that. Alright, so the filtrations have been
applied. Now if I go to terminal, there, you can see that we receive 25 back. So this means that
we have done a great job receiving all those boxes that are responsible to display data about the
deals. Alright, so now that we have the control on each of the boxes, then we should somehow try to
pull the specific data that we need. And obviously we'd like to start with the details name. So we
should find a pattern to get the title of all the 25 deals. So let's try to find these up. So
I'm going to open our latest browser and see what is going on here. So let's go to our first box
and try to click on Inspect And if you remember, this is under the elements that we have found.
So this means that we can iterate over each one of the 25 boxes. And we can try to find an element
by a class name that is equal to ASR dash hotel, underscore underscore name. So I'm going to
remember that and start working on that one. Now, I want to start working on a new file now, because
we want to have the reporting in a separator, the Python file to basically have more organized
project. So I'm going to go to the booking directory. And I'm going to create a file that we
can name this booking underscore report. And let's document first what this file is about. So this
file is going to in clewd, methods that will parse the specific data that we need from each one of
the veal boxes. So this explanation is pretty much making sense. All right. So down here, we
are going to have a class that is going to be responsible to have some methods that will start
to display the data that we need in a nice table. So I'm going to start by saying class booking
report. And then this will not inherit from anything. So we are ready to straightforward
to receive something inside our constructor. Now what is making sense the most is probably
to receive as a parameter, the parent element that is responsible to display all those deal
boxes. So I'm going to receive as a parameter something like boxes section element. And then
I'm going to say here, self dot voxels section element is equal to that one. And then we are
going to instantiate an instance of this one, and we're going to pass in the element with
the ID of a pill list, enter. So let's work on that. So I'm going to go here, and I am going
to basically go up top, and I'm going to use from booking dot booking report, import booking
report. And I'm going to go down, and I'm going to say report is equal to booking report and I'm
going to pass in the hotel boxes. So excuse me for instantiating this before that one it
is wrong. So I'm going to just fix that. And I'm going to just move it and actually replace
this with the return because we really don't want this to return anything for now. So I'm just going
to instantiate it in here. And then I'm going to pass in hotel boxes like that. Now I'd actually
like to execute these find elements by class name on the booking report side. So I'm just going to
cut this from here, and only pass in the element with that specific ID. And now let me basically
remove this empty line from here. And I think that will be it. So later on, we can basically execute
some methods from the booking report class, like I don't know, display table, stuff like
that, I know that this metal doesn't exist, but I'm just assuming the future of our project.
So let me delete that. And actually, there should be one more area that we should remove everything.
And this should be this one. So let's also remove the execution from here and continue designing
this. Alright, so now I'm inside the booking.py file. And I'm going to just leave everything here
as it is. And I'm just going to continue working on working report. Okay, so now that we have an
HTML elements inside this box section element, then we should go and execute find elements
by class name on top of it. So we will have all those 25 elements back. So I'm going to just
type in a metal that will say pull deal boxes, and this will receive self as a parameter. And I'm
going to say self, excuse me, this should be self dot boxes, section element, dot find element
by class name, and this will have the argument as ASR property block. And again, this is just going
to pull all those 25 elements. And what I want to do now is actually instantiate one more list
inside our init method. And I'm just going to say here, return to all the expression in
here, and I'm going to say in the init method, self dot deal boxes is equal to pull self dot pull
the boxes and then we will have control for all the elements under this name, which is in Making
much more sense. And I'm sorry that I missed the s right after find the elements. So, obviously,
they should be find elements by class name, because we would like to pull all the elements
that are matching this class name. Alright. So now that we have done this, then again, you might have
noticed that we did not have any auto completion about the find elements by class name. And
that is because we did not have typing for the box section element. And we are already familiar
with these from the seventh episode. So now that is going to be a very similar action to what
we have seen previously through how the series and it is just going to be importing
the typing for the web element class, and then basically use this specific
typing. So I'm going to say here, from Selenium dot WebDriver dot remote, that
web element, import web element like that. And then I'm going to say that these boxes
section element is going to be in kind of web element like that. And then we will start having
auto completions as expected. Alright, so now that we have done this, then let's start pulling in
the data that we really need from each one of the boxes. And as a great starter, we'd like to first
poll the hotel name for each one of the boxes. And if you remember, I said that we have a specific
spend tag with this unique class name that says s our hotel underscore underscore name. So I'm
going to find all the elements with that class name. So it will be going back to pi charm and
say something like their full titles. So again, receive self here as a parameter. And then I'm
going to basically iterate over each one of the boxes. So it is going to be for deal box in
self dot deal boxes. And I will say deal box dot find element by class name, and we will paste in
the value or the class that we are looking for, which is ASR dash ortel, underscore underscore
name. And then what we'd like to do with this element is basically pulling its inner
HTML, because if you have noticed in here, this element has the alltel name inside its inner
HTML, which you can really see from here. So it is just going to be as easy as saying to that
expression, something like that. So let me first split this to multiple lines. And then I can say
on top of that dot get attribute. And we would like to receive the inner HTML of that element.
And if you remember, when I use the get attribute innerHTML, I also executed some metal that will
be responsible to delete all the white spaces. And if you remember, it was dot strip, like that.
And that will be it, this entire expression should really display the hotel's names. So let me first
assign this entire expression to a variable like hotel name, or deal name doesn't really matter.
And then we can basically try to use here, print hotel name and see if that works. Now, if you
remember, pull titles is not called anywhere. So I'm just going to go to working dot p y. And
I'm going to launch the methods that we need to report the results in this report results
method. So it will be report dot full titles. And now let's see what is going on
in the run.py file. And if you remember, we removed the report results section. So in
that case, it will be what that report results. And I'm just going to leave everything here as
it is. And now our Ward should be responsible to display all the hotel's names. So if
we go to our terminal, and say, again, Python run.pi, then let's see the results. And
as expected, we change the currency, we add new york and one adult, and we apply the filtrations.
And we saw the prices. And now let's see what we have in the terminal. And you can see
that we really have all the hotels names, we really have everything that we need. So
we really have here 25 hotels, and let's actually see if the sorting matches our convention. So
the first hotel should be here to place New York City Times Square. And if we go here, you can see
that it doesn't quite match. And I know the reason for that because sometimes you probably need to
refresh after receiving those kinds of results. And we probably don't want to execute polling each
one of the titles too much fast. And they remember that this was a workaround. That I applied when I
developed this project before I present it to you now. So what I'm going to do before pulling the
results, I'm just going to trigger a refresh to that page. So the board will have a second or two
to basically grab the data properly. So I'm just going to go to Python. And I'm going to say here,
bot dot refresh. And this workaround should do the trick. So I'm just going to say here, a work
around to plate our bot to grab the data properly. Now, let me try to execute our board one more time
and see now if it is going to work as expected. Now, I think that the reason it happens, it is
because we try to pull the data. And this holding didn't finish each job. So it makes sense to
refresh everything before we really tried to pull all the titles. So let's just clean the screen and
say python run.pi. And wait again a few seconds. Okay, so now the first hotel is appeal Edison
Times Square. And if we go to our terminal, and then you can see that the first hotel is
hotel Edison Times Square. And the second one should be Holiday Inn. And the third one should
be Paul Times Square. So let's verify that. Okay, so I think that now the results are displayed
as expected, this refresh really gives our board a second to breed, and to grab the data in the
ordering that we want. Now I want to do something important before I go ahead with this tutorial.
And that will be changing the amount of the check in date and the checkout date. And this is because
it has been a week or two weeks since I recorded the last episode in this series. So I just want
to make sure that the dates are going to match the today's date. So that's why I'm just going to
jump the date by one month only by changing those 206 besides 05. All right, so now we are ready
to continue to customize the data that we need. Now we said that we'd like to customize the data
in a nice table, where we will display the hotel's name and price and also storing the hotel's score,
meaning the rating could be a great idea. So if you remember, we ended up by customizing inside
the booking report file, this poll titles middle and this one is actually going over each of the
deal boxes and tries to pull some attributes that is going to be useful for us. So we could
take advantage that we iterate over each one of the deal boxes. And we could actually try to pull
the price and the score along the way. So that's why I'm going to remove the printing line from
here. And I'm just going to comment out what I'm doing in each iteration step. So I will comment
here, following the ortel name. And then later on, I'm also going to change the pole titles to more
generic function like pull deal box attributes something in that kind. And now I'm going to
go over and start basically pulling the prices. Now to save some time, then I'm just going to show
here, what was the approach of finding the price on each deal box. And as well as how I found the
score of each hotel. So that's why I'm going to straightforward, say here hotel underscore price.
And that will be equal to do underscore box dot find element by class name. And then the value
here is going to be so let's open up strings. And then I'm going to say V UI dash price dash
display, underscore underscore value. And so if I have a class with this value, then it means that
this is going to give us the price. So that's why I can allow myself to do that. Now I'm going to
use the same approach of getting the innerHTML attribute. And the only thing the whitespace is
and if we remember we have done this in the hotel name as well. So I'm going to copy that and paste
this in and that line, I mean those three lines will be responsible to pull the hotel price. And
then if we go down below, and we also say here hotel score, and that will be by deal box, dot
get attribute and there is a great reason why I use here get attribute and not me dot wait find
element by something. And that is because this element has already an HTML attribute that looks
like data dash score. And so what that means it means that if we were to pull only the value of
this attribute in here, then it means that we are going to receive back the author score in scale
of 10. And so no tail score could be 8.5 9.1 9.5, and so on. And so now that I have done this, then
again, I'd like to clean the whitespaces. So just for safety, I'm only going to launch your dot
strip, like we did previously with price and hotels name. Alright, so now that we have a name,
price and score for each one of the deal boxes, then let's test first our problem. Now, I am
going to do something that might look weird to you. But I will explain just in a minute why I'm
doing this. So in order to test this out, then I'm going to go up here, and I'm going to use a list
that I want to name it something like collection. And that is going to be equal to an empty list.
And then as we keep iterating over name, price and score, I am basically going to need to add those
attributes to this collection. So we could have an organized and structured data. And I'm going
to use nested lists here where the collection will be the list. And that will include multiple
lists. And each list that it is going to have is going to include the three elements and one of
them is going to be name, the other one the price. And the third one is going to be score. So I'm
going to use here something like collection, dot append, and then I'm going to add to that one
more list. And then I will say hotel name, alltel price, and the other one should be hotel
score. And now that I have done this, then I really want to test out if I have all the
data that I wanted to pull from the beginning. So I'm going to use here return collection. And
I'm going to go back to our booking.py file. And I'm going to search for the method where we
report the results. And I think this should be here. And then I'm going to launch here
the method that that we have just finished to design. And that is going to be pull
deal box attitudes. Now, if you remember, we use return statements. So when we execute
this line, straightforward, then we are not going to see anything. So we're going to need to
wrap this up with the print built in statement so that we will be able to see the data.
Alright, so now that we have done this, then let's open our terminal and test the results.
So I'm going to bring our terminal to here. And I'm going to say Python run dot p y, and
let's see if everything is going to function correctly. Now let me move the web browser to
the screen. And let's see what will happen. Alright, so the bot is running. And now we should
see in the console of our terminal the result. So I'm going to open that up. And let's zoom out a
bit so we can understand what is going on here. Alright, so you can see that we are sort of having
a weird output. But let me break down what is going on here. So you can see that the first and
the last characters are actually square brackets, because this is the collection of data that we
have now. And you can see that this includes the list of First of all, and then the second
hotel and then the third hotel and so on. Now, I'm not sure why we see here an empty string. And
that is probably because this Webster square Tony, they rentals does not have a score. So that's
why it is an empty list. And you can see that as I keep going, we are having a lists inside
one bigger list that each list represents a collection of data about hotel name, hotel price,
and also hotels call. And that is a great start to visualize our data with the pretty table library
that I talked about in the very beginning of the series. And again, this library is going to help
us to visualize the data in a nice table divided into columns and rows. And now let's see what we
need to do in order to be able to visualize our data nicer. Alright, so let's go ahead and see
how to visualize our data now. So I'm going to clean the screen, and I'm going to install a
library that is called a pretty table. So it is going to be pip install pretty table like that.
Now for those that are asking why I'm not using visual environment here, right now, because I'm
installing a library on the system interpreter, you can go ahead and do that. Because it will
help you to basically have organized environment for this specific project. I just don't feel
like going through something in few seconds, at least if I don't have a full tutorial on
that on my channel. So that's why I'm going to straightforward install those packages in
the system interpreter and I'm going to rely on that on this project. But if you feel comfortable
using virtual environments, then I really welcome, you will to do so because this is a nicer way
to organize your projects in your machine. Alright, so now I will use this line. And
you can see that I have this installed, so it means that we can work with this library.
So now I'm going to go back to our PI charm and see how we call work with that. Alright, so now
that we have the collection of data in here, then we are going to write here a few more lines
to basically display this in a table. So I'm going to scroll up. And I'm going to import the
pretty table library. But I'm going to import only one class from this library. So it is going
to be from 3d with the table, import free t table like the following. And then we need to
instantiate this class. And so it is going to be here. So I'm going to say right here,
something like that. So I will use here table is equal to 50 table, and this one is going to
receive a few arguments. And the first one is very important, which is the field names. Now I said
that in the table, we are going to have columns. So in our case, we probably want to declare here,
three columns. And the first one will be the name and then the price and then the score. So I'm
going to pass here straight forward a list that is going to look like the following. So I'm going to
use here, alltel name, and then I'm going to use hotel price. And then I'm going to use hotel score
like that. And again, those are going to be used as the columns. So let me use actually a keyword
parameter in here so we can understand. Alright, so now that I pass this argument, then we need
to go ahead and create some rows in our table. So it is going to be as easy as using the Add
rows method. And then we are allowed to pass a collection of data. And guess what we are going
to pass in the nested list that I created a few minutes ago. So that's why in here, I use a nested
list. So it will be easier for us to basically pass in directly this collection list object.
So it is going to make our lives very easy. So now the only thing that we need to do in this
booking.py file is going to be table dot add underscore rows. And then we can basically
pass in whatever this returns in here. So it is going to be just copying and pasting this
right there. And then I'm going to basically leave it as it is. And actually we need to print
the table itself. So excuse me for deleting the print line before. Now we need to print the table
itself to really see the real table with columns and rows. Alright, so now that we are ready,
now let's go back to our terminal and actually clean the screen and run our word. So it
is going to be Python run.pi again, and let's see what will be the results. So I'm going
to display the results in here. And we will see in the background just in a few seconds,
the table that we expect to see. So now, you can see that we have this nice organized
the table that is really responsible to display everything that you need about the deals that
you read from the booking website. And you can see that it is very, very organized. And you can
see that it is with the sorting of lower to higher because we have applied this filtration throughout
the series. And you can see that it is just more easier to read the data in that way. And you can
also use this pretty table library for different projects as well. I really like this library
to visualize data when I need to do some tasks. And I want to display the data that I received
back. Usually I work with this library because it really displays the data nicer, and it's just
more comfortable to look at. Alright, so now that we have completed this, then it could have been
nicer to control each time how we want to execute our bot. So we might want to see results for
different locations in the future. And for sure, we also like to change our check in date and
check our date, depending on what is the exact time that we want to prepare for a location. So
that's why maintaining those kinds of information in the code itself might not be a great idea. So
that's why what we can do exactly like I showed in the very beginning of the series, how the
project is developed from the beginning is to turn those hard coded strings into obeying inputs.
And then we will have the ability to ask the user about those kinds of pieces of information. So
we could have here something like input and then We could ask here where you want to go. And
then what will end up happening is that the string that I'm going to pass in here as the
input is automatically going to be passed in inside this board dot select place to go method.
And so it will be useful because now we will not have to change the code, every time that we want
to look up for a different location to prepare our vacation. So that's why I am going to do this
approach for check in date and checkout date and as well as adults count. And I'm going to leave
the currency as it is because it will probably be nicer to see the prices in United States dollars,
you can change it to whatever currency you want. But let's leave it just hard coded in here and
only change those. Alright, so I'm going to ask you besides hard coding in the check in
date, something like this. So I'm going to ask, what is the check in date? And now I will also
copy this statement and paste this in here. And then I will ask, what is the check out date? And I
will also ask you something like, how many people something like that, and then we are ready to go.
Okay, so now I will allow myself to run again, Python, run dot p y. And let's see what
will happen. So at first we see our program, and you can see that nothing will happen only
after we select our currency, because our program expects for an input from us. So it is going to be
now answering each step at a time. So it is going to be something like so let's say that we want to
go to Los Angeles now. So I'm going to put that and you can see that now it asks for me, what is
the check in there. So now if I open the browser, then we can see that it has already selected
the Los Angeles. So that is perfect, it means that it really works. And we should see
the exact same result, when we provide in check in and checkout date. Now we should be careful in
here because we want to give the correct format. So it will be year dash Mont and only the day
of demand right after that. So I'm going to use that. And then I will say check out date
something like the following. So let's say we want to go for five days. And then you'll see
that it asked for how many people. And meanwhile, I can check if this works. And you can see that
it fills in the correct information. And now I will provide in four people, for example. And you
can see that we receive an error. And I believe that is because we did not convert the count
of adults to an interview. Now by default. So this is a great mistake that we had in here. And
let's fix this quickly. So let's bring our program and explain what is going on here. So you can see
that in select adults, if we use here Ctrl V, you can see that here we are operating some actions
that are requiring from this count to being an interview. And you can see that exactly from this
line where we use minus one. So it complains about how a string could not use subtracting in here.
So that's why we should go ahead and automatically convert this to an integer. So I'm going to use
an int built in function here and allow myself to execute this program one more time. So let's clean
the screen. And again, use Python run dot p y. And let's minimize this up and then providing
the information. So it's going to be Los Angeles. And then it is going to be again this date and
then that checkout date and then we can say for and you can see that now we don't receive any
arrows. So I believe in few seconds, we should see the results in a nice table. And you can see
that exactly, this is what is going on here. And we actually have an appeal with 10 scores.
So that is great news about this Grand Park la told the the states and Okay, so you can
really see that the results are perfect and everything functions well. And the fact
that we use input code really helps us to execute this program. Every time that we want
to test out the results for different locations and as well as for different dates. So we could
select the next month or the next three weeks or even tomorrow. So we will have this dynamic
option to just providing the information once we run the program and we don't really
need to change the code every time. Alright, so I think this will be it about designing this
Selenium project. Now of course, there is always room for improvement and also adding some features
here and there. But I think that I have covered everything that I wanted to accomplish from
the very beginning. And that is the fact that we display the results in a console in a nice
way depending on the information that has been provided in where we want to go and the check
in checkout date and how many people so if you enjoyed this series, then be sure to hit the like
button and drop a comment. So we can really spread this video to more people on YouTube. And I
will see you in my future videos. So again, hit the thumbs up button and as well as
subscribe to my channel and see you around.