Selenium Course for Beginners - Web Scraping Bots, Browser Automation, Testing (Tutorial)

Download information and video details for Selenium Course for Beginners - Web Scraping Bots, Browser Automation, Testing (Tutorial)
Uploader:
freeCodeCamp.orgPublished at:
8/31/2021Views:
882.3KDescription:
Learn Selenium by building a web scraping bot in Python. Selenium is a powerful web automation tool that can be used for browser automation, to test front-end code, and create web scraping bots. 💻 Code: ✏️ Course developed by JimShapedCoding. Check out his channel: ⭐️ Additional resources ⭐️ 🔗 Python Download: 🔗 Pycharm Download: 🔗 Selenium Documentation: 🔗 Copied and Pasted during the video: ‣ (Section 1&2) ‣ (Section 3) 🔗 Chromedriver download website: 🔗 All the Explicit waits: 🔗 My Personal website for code snippets: ❤️ Try interactive Python courses we love, right in your browser: (Made possible by a grant from our friends at Scrimba) ⭐️ Course Contents ⭐️ ⌨️ (0:00:00) Getting Started with the basics ⌨️ (0:16:44) Explicit vs Implicit ⌨️ (0:28:11) Sending Keys & CSS Selector ⌨️ (0:43:42) Structure a Bot Project ⌨️ (1:03:13) Deal Searching ⌨️ (1:44:38) Booking Filtrations ⌨️ (2:07:24) Execution from a CLI ⌨️ (2:21:31) Deal Reporting 🎉 Thanks to our Champion and Sponsor supporters: 👾 Wong Voon jinq 👾 hexploitation 👾 Katia Moran 👾 BlckPhantom 👾 Nick Raker 👾 Otis Morgan 👾 DeezMaster 👾 AppWrite -- Learn to code for free and get a developer job: Read hundreds of articles on programming:
Video Transcription
Selenium is a portable framework for testing web applications.
Jim from Jim Shape Coding teaches this Selenium course.
He has created many popular courses both on the Free Code Camp 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 our 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 IDE like PyCharm 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 hour 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 selenium.
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 errors, then it means that everything is great.
And we can go back to PyCharm and basically import this library and see how we can use it.
Alright, so here I'm going to import
from selenium import web driver.
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 web driver dot Chrome, like that.
And as you can see here,
there's 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 will instantiate the class like that.
Now, we could go ahead and try to execute this, but we will receive some errors.
And the errors are going to talk about something that is called Chrome driver that does not exist on my computer, and as well as it is not in the pad.
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 web driver uses to perform those automated actions in a Chrome browser.
So that means that we need to download this chrome driver dot exe 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 separated tab and we can write 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.
as you can see, we have the major version as 89.
So for yourself, it could be 909192, or even 84.
But you need to make sure that this major version is going to be matched to the version that you are going to download from the Chrome driver page.
So in my case, I'm 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 downloads library.
And you want to move this to a location that you want to have your chrome driver.
So for myself, it is going to be under the C drive.
And inside the folder that I named selenium 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 folder now.
So as you can see, the location of that would be C selenium drivers like that.
And you can, again, put it in whatever location you like to.
And right after 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 Python 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 chrome driver 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 this 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 OS.
And I'm going to now put one more value to the already existing path environment variable.
So I'm going to say OS dot n, v run like that.
And then I'm going to look up for the key of path and make sure that you should do it all in capitalize like I did.
And now we'd like to use plus equals because we are adding a path value to already existing path.
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 forward 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 chrome driver.
Alright, so right after we have done this, then we should add here the R letter before the double quotes.
And this is actually a convention for a prefix that is going to mark it as a row 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.
All right, 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 basically take basic actions to get started with it.
So I'm going to use this selenium easy.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 kind 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 its 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 PyCharm.
Now before I do that, let me copy the link of the website because we are going to use it just in a minute.
Alright, so now if I open PyCharm, 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 straightforward 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 its 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 fine 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
dot 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's 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 seeing something like driver that implicitly wait, and here we should specify the amount of seconds that we'd like to wait to this website to 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.
And 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 of 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 started 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 used 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 really need to wait 30 seconds if the element is already there in that webpage.
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 weight.
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 the implicitly weight, it is going to be set up as a timeout across all your selenium project.
So what that means, it means that you only need to call this implicitly weight method one time, and then it will go ahead and set an implicit weight amount
for all the elements that you are 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 set the implicitly weight, it is going to be basically applied across all the elements that we are going to try to find them somehow in the future.
Alright, so now that we completely understood the behavior of implicitly weight,
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 to indicate something like this, we need to understand when this text in here is going to be exactly equal to complete with an explanation 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 explanation mark is coming from this HTML element, which says us that its type is div.
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's 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 can 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 styling 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 this element.
So it will be by dot text.
And it should display us the text in here.
So if we do that, and run this one more time, let's test the results of that.
Okay, so we have a new page being appeared.
And as you can see, it immediately showed the text of this element, which was starting download.
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 weight.
Now with this, we can actually allow our program to wait for an expected condition.
And then we can basically wait until this condition returns true.
So what that means, it means that we look to this true expression in here.
So I can say here, completed
with the explanation 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 true.
And let's go ahead and see how we can do that.
Alright, so in order to use the explicit weight, 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 dot common dot 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 dot support
that UI like that we need to import the built in class inside the selenium that is called web driver weight.
And we'd also like to import one final thing which is going to be selenium dot web driver 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 import.
But there's 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 web driver weight class.
So I will say web driver wait 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 that should 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 separated line.
So I'm going to press enter in here.
And then we need to write the condition that we want it to be true 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 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 separated 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 down.
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 tuple 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 method.
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 explanation mark.
So now if we run our program, then we should not receive any errors, because this condition is probably going to return us true 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 really verifies that the download of some file has been completed successfully.
So it is very nice to play around between those weight methods, we can use implicitly wait to find elements in our entire page.
And we can also use the explicit weight, 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, element 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 sending 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'm 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 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, then 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 PyCharm.
And actually say here, driver 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 its 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 some keys to it.
So I'm going to go back to PyCharm.
And I will say here,
sum 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
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 launch the method of send keys like that.
Now you can put here whatever you'd like to, as you can see, it expects for a value.
So this could be any value that you'd 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 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 something like driver dot 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.
OK, 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.
OK, so I think we got a new challenge in here as we see this output and we need to somehow perform an automation 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 pop up 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 pop up.
And we don't see any message from the except block.
So what that means, it means that the selenium identified the element with this class name, and it immediately clicked 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'd like to show you before we go ahead with the get total element.
And I'm talking about the fact that we can send 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 want to basically automate some actions that are required to maybe copy some text.
So you need to automate control C. And again, that's useful because sometimes you want to automate pressing on some key directly rather than sending some random text.
So I'm going to import here from selenium
dot web driver 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 keyboard.
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 f1234.
And we even have the nums that are existing in the right side of our keyboard, 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 PyCharm 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 dot numpad five, and then it will basically send 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 of it, it is the fact that you can send all the keyboard keys that exist out there.
Alright, so now we only have the get total button to filter.
Now, not always we'd like to filter the HTML elements by their ID or class name, we might have 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 let me 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 on click 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 CSS selector.
And 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 PyCharm.
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 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 on click
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, it is because I used single quotes here from the beginning.
And we do not want to mismatch 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 selector options because there are tons of options that you can filter an 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.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 selector 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'm in 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 a tag elements whose href attribute value begins with HTTPS.
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 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 bot 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 PyCharm 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 happened 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 structure 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 subdirectory that is named booking 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 dot 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, it is just more comfortable to me.
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 boat 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 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's actually a great reason that I'm 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 dot py file.
Now notice how the run dot py file is outside of the booking directory.
And that is one more reason that I have created this double underscore init 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 dot 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 are 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 dot 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 receive 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 alert before we start, I will not recommend running this bot around while 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 large of 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 said 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 web driver 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 two 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 self 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 this 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 path like that.
And if you 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 Selenium series.
So it will be R for row string and I will open here double quotes and I will say C colon backslash Selenium
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 driver path is equal to driver 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 web driver 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 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 web driver dot Chrome class as well.
So this line is going to be successfully instantiate an instance of the web driver dot Chrome class as well.
And to prove that, let's go down and design a random method.
So let's say here something like def 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 web driver 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 bots.
Alright, so I'm actually going to make use of this method.
And I'm going to point our bot 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 bot on.
So it will be
https www.booking.com.
Now, actually, here is the exact reason that I have created the constants.py.
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 uppercase.
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 dot 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.baseurl 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 path in the system level path variable.
So that's why we used something that was looking like OS dot envy Ron, if you remember.
So let's do this before we use this super method.
Because again, otherwise, the selenium is going to complain for that error.
So I'm going to go up top here.
And I'm going to say import OS.
And I'm going to go down.
And I'm going to use here OS dot
environ.
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 pad 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'm 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 used the same expression pretty much inside our class.
Alright, so let's go back to PyCharm and continue.
And now what we can basically do is go to our run dot py file and import this class and create an instance of it.
So we can really use its methods like land first page.
So if we go to run dot 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 path.
And now I can really try to use the first method 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 dot py file and test if everything works.
So if I run that,
Then let's see what will happen.
OK, 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 methods.
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 bot 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'd 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.py 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 to simulate you 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 dot py file.
And on the right pane, I will have the run dot 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 bought.
And then I will go here and I will say bought dot land first page.
Now the beauty of using something like that, it is the fact that once Python, which is 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 method that is called double underscore exit.
So to implement that, then I'm going to go here, and I'm going to say def double underscore exit.
And I'm just going to use the 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.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 you 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 rundown 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 wait expression, then it executes automatically the double underscore exit method.
This is how context 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 down or when we don't want to tear 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 method, something like if teardown.
So this basically refers sorry, this should be self dot teardown.
And we should go here and say self dot teardown.
equals to teardown.
And then I can basically use here and 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 teardown 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, because 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 web driver dot 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 method in here, which is looking like land first page.
And it basically lends the bot on this const dot base URL, which is booking.com that is located in the constants dot 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 method 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 weight,
And for example, 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 it could also proceed to the next find element method by less time because not always would 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 bot.
So now let me go and run our run.py file.
And now you can see that the web browser has been opened in maximize 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 the check in, check out 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'm 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 text box.
So
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'm 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's 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 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 could 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 filtering this button with the data tool tip 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'm 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 PyCharm and down below I'm going to say def
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 too 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 py on the right side.
So let me split that vertically.
And let me open this in here.
like that.
And then let me call this button.
So it will be bought dot change currency like that.
And then let me run this run dot py file and test the results.
So
As expected, we are on the home page and you can see that we have automated clicking on the 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 run dot py 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 inner HTML 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 this a element and we should use something that will help us to identify this 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 data model header async URL, 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 see in PyCharm how we can do that.
Alright, so down below, I'm going to use a new variable that we can name it selected currency element.
And that is going to be
B 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 this long expression that will help us to identify this element.
So it will be data dash modal dash header 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 to 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 key had in this element that we look 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 dot py by again, splitting the pains
working on one dot 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.
And
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 GBP.
Alright, so let's try to do that.
So let's open the pie charm again.
And besides sending USD, let's send GBP and run our program again.
And let's see now what will happen.
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 are ready to go forward with the next steps that our bot 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 should 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 opened 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 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 its 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 ID.
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 at 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 send the place to go that is arriving from this parameter.
And then I'm going to go to run dot py.
And I'm going to say bought dot select place to go.
And let's use here, New York as the 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 bot.
So I'm going to do that just in a minute.
Alright, 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 Li.
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 this 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 beta 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 of two, and so on.
So that's why we could identify an element with the expression of data dash i is equal to zero.
So I'm going to open our PyCharm 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 li and square brackets again and it will be data
dash i is equal to zero like that.
And then right after we have done this, then we are going to say first result 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 dot py 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, and as well as check out date.
So this is great.
And this means that we have done a wonderful job identifying how we could click on that specific element.
Alright, 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 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.
We 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 TD 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 CSS selector 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 PyCharm.
And let's try to automate that.
So down here in booking.py, right where our booking class is, I'm going to type in one more method that we can call it something like select, check,
we can just call it select date, something like that.
And then we will receive two parameters like check in date, and as well as check out date.
And we can go down and we can say check in element is equal to self dot find elements by CSS selector.
And
And this is going to have as an argument, the following statements.
So I will open single quotes, and I will use TD, because this is the element we look to automate.
And then we will open up and close 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 state is hard coded in here.
And I'm just going to use formatted string and replace the value
from being hot 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 date for deciding the dates of our vacation.
So I'm going to go down and I'm going to say check out date.
element, excuse me, and it should 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 check out element,
dot click.
And this should be enough to basically decide the check in and check out dates.
And the only thing that we have to do now is go back to our run dot py and execute this method by passing into arguments.
So it will be bought dot select dates.
And we are going to pass in check in date is equal to let's say 2021.
dash zero five for May, and then day of 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'd 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 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 bot in whatever way you'd like to.
All right, so now, first of first, let's start identifying this entire area in here.
So inspect and do it again.
All right, so we look for the element that will basically color the entire area of this
selection button.
So I think this should 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 XP guests toggle.
So I'm going to just copy this value.
And I'm going to go to our bot.
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.py.
And then I will go here and I will say bot 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 location.
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 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 453 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 pie charm.
And you know what, before that, we need to understand how we're going to click on decrease 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 look to 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 see the same thing for increased number of adults with 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 all right, there it is.
So you can see that it has area label increase 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 while true, 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 true, 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 adult element dot click.
Now, if I leave the code as it is, then it is always going to try to click on decrease 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 while 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 do 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
is actually getting updated continuously as well.
And the reason I want to select this element is actually because it has ID.
And if you 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 here again, 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 count 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 Python 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 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 string to integers.
So we are going to convert this 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 rundown 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 all right, so you 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 with 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 PyCharm 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 this argument when we call this method.
So now let's go to our method and minimize this while true 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 label 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 built in function.
So we can really have control in 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 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're not going to make use of the terrible value.
So
Now we are ready to test the entire program.
So I'm going to launch our run dot py file.
And we should see the adults count being set to 10.
So if we run our bot, and wait a minute,
Alright, 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 of 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 kind.
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 self dot find element by CSS selector.
And we should find a button with this key value pair, and basically assign this to a variable like search button.
And then later on, we'd like to click on that.
Alright, so here, I'm just going to call this bot dot click search, and see if everything works properly.
Now to really test the entire logic, let me on the comment 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 values 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 this 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 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 do this 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 could 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.py.
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 selenium 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 this page?
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 web driver.
So if I go to booking.py, then we can actually see that throughout 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 driver 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 write here pass to ignore the arrows.
And I will go to booking dot py.
And I will basically go up top of this file.
And I will say from booking dot booking filtration, import booking 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 T 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 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 checkboxes.
So I'd like to first work with that element, because you can see that we have some more checkboxes in that page.
And I don't want to confuse these five stars, for example, with that one, because this same checkbox is appearing also in the popular filters.
So that's why it is a better idea to first take our bot 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 I'm 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 check boxes.
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 underscore class.
So that is perfect because we can try to use our bot 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 PyCharm and you can see that I'm inside the booking filtration 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 apply 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 idea of the element that we 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 typings are working, then I will use a minute to explain this with a more familiar 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 lists.
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.
And 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 web driver 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
colon web driver.
And once we have set the type of this driver parameter, then we are always going to have self dot driver 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.
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 selector.
So let me show you how this could be done.
So star child elements,
this is how 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's 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 dot driver, and we launch
On top of that, these find elements by sister method.
So this will end up giving us all the elements of this entire web page.
And this is wrong because we only want the elements of star filtration box element.
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 or
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 dot p y.
So I'm going to go here.
And I'm going to always execute bot 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 applyFiltrations method inside the booking.py file.
So now let's execute our entire project.
So I will run run.py 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.
All right.
So if we go back to here, then you can see that we receive as a result 40.
And 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 you 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 a tags.
And those a tags are what really we should click on them.
And you can see that each of those a 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 inner HTML 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.
and 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,
inner HTML 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 booking 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 Jim, then if we want to receive the gym value only, then you should launch up the get attribute method.
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 here something like star
value.
And we want to turn this to a formatted string.
And we want to change this to star 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, pass.
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 seeing before that is called strip.
Now, the 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 HTMLs.
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 inner HTML 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.py.
But before we do that, we should go to booking.py because this is where we use the applied 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 here and let's do this keyword.
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 clicked 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's going to be one more feature 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 something in that kind.
So that's why we should somehow receive as a parameter, not just one star value, but maybe receive more than one star value.
And the way that we can achieve this is by turning the star 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 double asterisk sign.
And this is commonly seen with args.
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.
Alright, so now that I have changed this to being an arbitrary argument, then let me change this to star 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 star value.
in star 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 star values.
And the way that we are 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 the 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.
All right, 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, then 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.
All right, 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 bot 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 filtrations or basically just some more utilities that can help us to customize our results better.
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 IDs equal to price.
So we can grab this key value attribute and find this with 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 sort price lowest 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 type.
And we will open up our square brackets.
And we will say data ID is equal to actually I copied the 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 dot click,
And 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.
And the place that we call them is inside this booking dot p y file inside apply filtrations.
So right after we apply some star writing, we could also sort our results.
So we could say filtration
but sort 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 in action.
And let me actually test our program a bit and only use four to five stars.
Alright, so if we run this, then and wait a bit, let's see what will happen.
All right, 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 filtrations, 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 be not always want to open it in a specific ID.
Further than that, sometimes executing bots from the command line is just more comfortable rather than going to PyCharm and basically pointing to a project and then using the shortcut of Shift F10 to execute your project.
Sometimes you only want to do it from a terminal executing Python and then referring to the file.
In our case, it is run.py.
Now, I'm not going to lie to you, but our project currently does not support such a behavior
because we have this tricky line inside the booking dot py file that is going to add the location of our driver path to the path environment variable.
Now executing such a line from PyCharm will work because PyCharm 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 command 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 py, then you can see that it complains about how the Chrome driver 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 environment.
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 print to our users that the user needs to basically execute some line from a command line that will add the C selenium drivers folder to the pad system variable.
So let's go ahead and try to design that.
So I'm going to go
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 except 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 running this program from command line interface.
So that is just a great start handling things inside the except block.
Of course, there's 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 dot p y.
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 accept lock because we really have some exception.
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 chrome driver 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 catch 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 in path.
So I'm going to go back to PyCharm.
And I'm going to say if in path 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 will 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 dot py.
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 pad 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 this in 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 nicer message that says you are trying to run the bot from command line and the backslash in is just an escaping characters to just jump to the next line.
So in the next line, we say please add to path 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
path system around variable.
Now, as I said, in the first episodes, 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 chrome driver into it.
And if you use Linux, then you should execute this line, which is looking pretty much similar.
Only the windows includes the set comment.
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 add here.
So it will be selenium drivers.
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.py.
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.py.
And now you can see that our bot works and you can see that everything is pretty much functioning as expected.
You 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 receive some warnings that we are really going to fix soon.
But at all in the big picture, our bot functions perfect if we even execute it from a terminal.
Alright, so now you might notice some weird warnings about David tools listening to our local host 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 dot py file, and basically add some additional configurations to our web driver instance.
So it is going to be as easy as going back to PyCharm 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 Dave 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 a list with one element and it is going to be enabled 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 dot py.
And I'm just going to let our bot running.
And 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.
Alright, so now that we were able to figure this out, then there's 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 pie charm.
And I'm going to say here a is equal to two divided
by zero like that.
And we should receive basically a zero division error before even our bot starts.
So that is why we should now go back to our terminal again.
And let's clean the screen and try to execute our bot one more time and see the results.
Alright, so you can see that we see now the original exception, which says to us zero division error, because we really tried to divide a number by zero.
So we will have some errors.
And you can see how our bot 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 bot project.
And we can now continue 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 bot, then we'd like to visualize the results of the deals in a nice way.
So the user can really have a greater look
what are the results for the best deals.
And we probably want to avoid doing that with the pie charm.
And we probably want to visualize it nice with terminal.
So that is why I want the ability to execute this bot 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 dot py 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 stick 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 see to display the hotels 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 hotel list inner.
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's a great chance that you did not practice it.
But I'm just going to make a short walkthrough how I identified when I developed this project, all of those 25 boxes.
So
So let's go to console.
All right.
So the console 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 we 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 method 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 walkthrough 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 getElementById.
Now pay attention that E, B and the I are capitalized.
And then I'm going to say here, hotelList 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 E, 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 sr underscore property
block 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 hotel 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 PyCharm inside the booking dot py 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 underscore inner.
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 loop.
So I'm going to do that in here.
And this by class name is going to receive as argument sr underscore property, underscore block.
And I need to assign this entire expression to some variables.
So we can name it hotel 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 hotel boxes.
And I'm going to go to our run.py.
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 am 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, then you can see that we received 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 hotels name.
So we should find a pattern to get the title of all the 25 deals.
So let's try to find this 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 s r 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 separated 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 include methods that will parse
the specific data that we need from each one of the deal boxes.
So this explanation is pretty much making sense.
Alright, 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 boxes 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 hotel list inner.
So let's work on that.
So I'm going to go here.
And I'm 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 method doesn't exist.
But I'm just assuming the future of our product.
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 booking dot py file, and I'm going to just leave everything here as it is.
And I'm just going to continue working on booking report.
Okay, so now that we have an HTML element 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 method that will say pull
deal boxes, and this will receive self as a parameter.
And I'm going to say self, excuse me, this will be self dot boxes, section element, dot find element by class name.
And this will have the argument
as s our 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 deal boxes.
And then we will have control for all the elements under this name, which is making much more sense.
And I'm sorry that I missed the s right after find elements.
So obviously, this 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 defined elements by class name.
And that is because we did not have typing for the box section element.
And we are already familiar with this from the seventh episode.
So now that is going to be a very similar action to what we have seen previously throughout 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 web driver, dot remote dot web element, import web element like that.
And then I'm going to say that this box of 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 pull the hotel name for each one of the boxes.
And if you remember, I said that we have a specific spin tag with this unique class name that says is 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 PyCharm and say something like def pull titles.
So I can 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 of the class that we are looking for, which is sr dash hotel 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 hotel 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 inner HTML, I also executed some method 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 hotels 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 pool titles is not called anywhere.
So I'm just going to go to booking dot p y.
And I'm going to launch the method that we need to report the results in this report results method.
So it will be report dot pool
titles.
And now let's see what is going on in the run dot py file.
And if you remember, we remove the report result section.
So in that case, it should be bought dot report results.
And I'm just going to leave everything here as it is.
And now our bot should be responsible to display all the hotels
names.
So if we go to our terminal, and say again, Python run dot py, 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 sort 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 at 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 kind of results.
And we probably don't want to execute pulling each one of the titles too much fast.
And I 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 bot 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 workaround to let our bot to grab
the data properly.
Now let me try to execute our bot one more time and see now if it is going to work as expected.
Now I think that the reason happens it is because we try to pull the data and the sorting didn't finish each job.
So it makes sense to refresh everything before we really try to pull all the titles.
So let's just clean the screen and say Python run dot p y.
And wait again a few seconds.
OK, so now the first hotel is Hotel 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 Pod Times Square.
So let's verify that.
OK, so I think that now the results are displayed as expected.
This refresh really gives our bot a second to breathe 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 dates
by one month only by changing those to 06 besides 05.
Alright, 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 hotels name price and also storing the hotels score, meaning the rating could be a great idea.
So if you remember, we ended up by customizing inside the booking report file, this pool titles method, and this one is actually going over each of the deal boxes and tries to pull some attribute that is going to be useful for us.
So we could take as 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, pulling the hotel name.
And then later on, I'm also going to change the pool titles to more generic function like pool 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 deal 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 bui dot
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 inner HTML attribute and deleting the white spaces.
And if you 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's a great reason why I use here get attribute and not a method with 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 hotel score in scale of 10.
So an hotel 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 white spaces.
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 program.
Now I'm 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 that will include multiple lists.
And each list that it is going to have is going to include three elements.
And one of them is going to be named the other one 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, hotel
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 we have just finished to design.
And that is going to be pull deal box attributes.
Now, if you remember, we used 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 results.
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 hotel 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 30 day 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 list inside one bigger list that each list
represents a collection of data about hotel name, hotel price, and also hotel score.
And that is a great start to visualize our data with the pretty table library that I talked about in the very beginning of this 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 pretty tables.
So it is going to be pip install, pretty table like that.
Now, for those that are asking why I'm not using virtual 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 a 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 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 Python and see how we could 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.
And
But I'm going to import only one class from this library.
So it is going to be from pretty, pretty table, import pretty 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 pretty 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 straightforward, a list that is going to look like the following.
So I'm going to use here, hotel 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 used 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 dot 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 bot.
So it is going to be Python run dot py 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 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 these 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 receive back.
Usually I work with this library because it really displays the data nicer and it is just more comfortable to look at.
All right, 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 out 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 this series, how the project is developed from the beginning is to turn those hard coded strings into being 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 bot 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'm going to do this approach for
check in date and check out 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 wanna 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 date?
So now if I open the browser, then you 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 check out date.
Now we should be careful in here because we want to give the correct format.
So it will be year
dash month, and only the day of the month 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 asks for how many people and meanwhile, I can check if this world and you can see that it filled 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 integer.
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 control B, you can see that here we are operating some actions that are requiring from this count to being an integer.
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 provide in 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 four.
And you can see that now we don't receive any errors.
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 hotel with 10 scores.
So that is great news about this Grand Park LA 30 day stays.
And okay, so you can really see that the results are perfect and everything functions well.
And the fact that we use input could really help 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.
Similar videos: Selenium Course for Beginners

Prisma ORM Full Course 2025 | Become a Prisma Pro in 2.5 Hours

Python Full Course for Beginners

Mesh Machine - My Powerful New Blender Workflow! (Tutorial)

5 Best Bevel Tricks Beyond The Basics (Blender Tutorial)

Python Full Course For Beginners| Job Ready Python Course by Sagar Chouksey 🔥

