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

Video Statistics and Information

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