Screenscraping a Datepicker with Scrapy + Selenium - selenium

So i need to scrap a page like this for example or this and i am using Scrapy + Seleninum to interact with a datepicker calendar.
Basically i need to check for the availabilities of the rooms for each day in a month for example, so my idea was trying to click the not disabled links/dates on the datepicker and check if an error message appears or not for me to know if its available or not.
I have no idea if this is the proper way or even how to do this with this tools. I have been playing around with them but still looks like i am far from a final solution.
Does anyone know how i can tackle this or even provide the code for me to achieve this?

Hi please find the answer below
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.manage().window().maximize();
driver.get("https://www.airbnb.pt/rooms/516301?check_in=2016-04-14&guests=1&check_out=2016-04-17");
// selecting firstdate picker -- check in
driver.findElement(By.xpath("//*[#class='col-sm-6']/input")).click();
// note calendar is not completely visible hence to make it visible
// scroll a little bit down
((JavascriptExecutor) driver).executeScript("window.scrollBy(0,200)");
// take all calendar dates inside the list
// here i have update my code to skip stale element exception
List<WebElement> alldates = driver.findElements(By.xpath("//*[#class='ui-datepicker-calendar']/tbody/tr/td/a[contains(#class, 'ui-state-default')]"));
System.out.println("Size is : "+ alldates.size());
// suppose you want to select 27 form the all dates
// keeping it as a parameter
String dateToBeSelected = "19"; // check in
for(int i=0;i<alldates.size();i++){
alldates = driver.findElements(By.xpath("//*[#class='ui-state-default']"));
System.out.println("dates is : " + alldates.get(i).getText());
// selects a check-in date
if( alldates.get(i).getText().equals(dateToBeSelected)){
alldates.get(i).click();
break;
}
}
// on selection of Checkin date check out calender automatically pop ups
System.out.println("--------------------------");
String datetobeselected = "27";
for(int i=0;i<alldates.size();i++){
alldates = driver.findElements(By.xpath("//*[#class='ui-state-default']"));
System.out.println("dates is : " + alldates.get(i).getText());
// selects a check-in date
if( alldates.get(i).getText().equals(datetobeselected)){
alldates.get(i).click();
break;
}
}
// actually after calendar selection whatever text is shown in red color
// i am not sure what is it (sorry only English)
// identify the text with red color is present or not
boolean errorMsg = driver.findElement(By.xpath("//*[#class='panel-body panel-light']/div[2]/p")).isDisplayed();
if(errorMsg){
System.out.println("error msg is displayed");
}else{
System.out.println("error msg is not - displayed");
}
Hope this helps you also note this above example takes check-in and checkout date as parameter if you want code to take non disabled date automatically please feel free to ask i will update my answer.

Related

Automate date-picker based on month text

I am trying to automate date-picker on a page, and I want to hit the previous/next button until I reach a desired month in the calendar. But the button does not click, only once it clicks and test cases passes without going any further. Current month is September it clicks and goes to August and the test case passes without being clicked further, lets say if I wish to click till January it does not happen
#FindBy(css=".ui-datepicker-month") //month displayed in date-picker
WebElement labelCalendarMonth;
#FindBy(id="txtStartDate_calendarButton") // button to open the date-picker
WebElement searchStartDateButton;
#FindBy(xpath="//a[#title='Prev']") // previous button in date-picker
WebElement calendarSearchStartDatePreviousBtn;
public void selectStartMonth(WebElement ele, String value) {
if(!labelCalendarMonth.getText().equals(value))
{
ele.click();
}
}
public void clickCalendarSearchStartDatePreviousBtn() throws InterruptedException
{
selectStartMonth(calendarSearchStartDatePreviousBtn, "January");
}
#Test()
public void testAddResourceSchedule() throws InterruptedException
{
resourceSchedulePage.clickCalendarSearchStartDatePreviousBtn();
}
I have worked with https://www.booking.com/ and they do have date picker, so just to give you little head up how do we handle this situation where we have to click till certain amount of time, for e.g: till Jan in your case, we can do the following :-
It's kind of obvious that we have to have infinite while loop.
while(true){
if(driver.findElement(By.xpath("month xpath which you wanna selct ")).getText().equalsIgnoreCase(month) && driver.findElement(By.xpath("year xpath that you wanna select")).getText().equalsIgnoreCase(year)) {
break;
}
else {
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("next botton xpath here, which is on date picker."))).click();
Thread.sleep(500);
}
}
Basically, the thing is you need to define month and year in advance in a string format. before running this code.
I have written a good solution here as well where I am clicking till end of Nov-2022

How do i tell Selenium to wait until report get ready to download

After the selection of date from the date picker,clicking on 'View Report' button and then its take a time to generate the report and then it download the report.. My following code is working without an error but how do i use fluent wait instead of Thread.sleep(20000),(last line in below code). For fluent or explicit wait i ask to wait for what condition? Also wanted to verify whether the file has been downloaded or not with assertion. Any help will be appreciated.
public void generateReport() throws Exception {
clickDatePicker.click();
log.info("Select the Date from datepicker");
Select month = new Select(selectMonth);
month.selectByValue("0");
log.info("Selected the Month from datepicker");
Select year = new Select(selectYear);
year.selectByValue("2020");
log.info("Selected the Year from datepicker");
act.moveToElement(selectDate).click().build().perform();
buttonViewReport.click();
log.info("Finally clicked on Get Report button ");
Thread.sleep(20000);
}
Check the below method, which will make sure the script will wait until the download is started (for max of the minutes specified in the method call)
public void waitUntilDownloadStarted(WebDriver driver, int maxWaitTimeInMinutes) throws InterruptedException {
// Store the current window handle
String mainWindow = driver.getWindowHandle();
// open a new tab
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("window.open()");
// switch to new tab
// Switch to new window opened
for(String winHandle : driver.getWindowHandles()){
driver.switchTo().window(winHandle);
}
// navigate to chrome downloads
driver.get("chrome://downloads");
Instant startTime = Instant.now();
int elapsedTime = (int) Duration.between(startTime, Instant.now()).toMinutes();
// wait until the download is started
while ( (Long)js.executeScript("return document.querySelector('downloads-manager').shadowRoot.querySelectorAll('#downloadsList downloads-item').length") == 0) {
Thread.sleep(1000);
elapsedTime = (int) Duration.between(startTime, Instant.now()).toMinutes();
if (elapsedTime > maxWaitTimeInMinutes) {
break;
}
}
// close the downloads tab2
driver.close();
// switch back to main window
driver.switchTo().window(mainWindow);
}
Tested as below.
waitUntilDownloadStarted(driver, 10);
Does anything appears like that your download has been generated? or inspect any change in HTML. then you can use the following code to wait until change appears.
WebDriverWait wait=new WebDriverWait(driver, 20000);
wait.until(ExpectedConditions.numberOfElementsToBe(locator, number));
where 20000 is time in milliseconds

How to get Position of button in selenium c#

One Video is there below that one button is there i need to automate that button wheather that button is present below that video or not any one please help me to resolve this
If the button is a part of the page DOM and it can be searched by Selenium you should be able to access it's Location property like:
System.Drawing.Point location = driver.FindElement(By.XPath("//your_element_locator")).Location;
Console.WriteLine("My element location: " + location);
If you want to conditionally execute this or that code block depending on presence/absence of the element you can go for FindElements() function like
if (driver.FindElements(By.XPath("//your_element_locator")).Count > 0)
{
// element is present
}
else
{
//element is absent
}
If the button is not present in the DOM and it's a part of video - you will have to go for image recognition frameworks like AForge.NET, Emgu CV or SeeTest

How to check link is already clicked in java?

I am new to Selenium and also new to java coding.
Can you please tell me coding for already selected or active link of table and print data of table for already selected link then go to next link automatically?
I would recommend you the following approach.
Algorithm is simple:
1) if a link has certain color attributed -> then it is supposed to be not clicked yet
2) otherwise ( if color attribute differs) -> it has been clicked
So you should find selector of the link to analyze:
String cssLink ="blalbalbla";
then you find this element (link):
WebElement link1 = driver.findElement(By.cssSelector(cssLink));
then you get color attribute of it:
String colorExtracted= link1.getAttribute('color');
then you can analyze color obtained:
boolean result;
if(colorExtracted==clicked) {
result = true;
}
else {
result=false;
}
Hope this idea helps you.

'sendKeys' are not working in Selenium WebDriver

I am not able to put any value in my application using WebDriver. My application is using frames.
I am able to clear the value of my textbox with driver.findElement(By.name("name")).clear();, but I'm unable to put any value using driver.findElement(By.name("name")).sendKeys("manish");. The click command works for another button on the same page.
I also had that problem, but then I made it work by:
myInputElm.click();
myInputElm.clear();
myInputElm.sendKeys('myString');
Before sendkeys(), use the click() method (i.e., in your case: clear(), click(), and sendKeys()):
driver.findElement(By.name("name")).clear();
driver.findElement(By.name("name")).click(); // Keep this click statement even if you are using click before clear.
driver.findElement(By.name("name")).sendKeys("manish");
Try clicking on the textbox before you send keys.
It may be that you need to trigger an event on the field before input and hopefully the click will do it.
I experienced the same issue and was able to collect the following solution for this:
Make sure element is in focus → try to click it first and enter a string.
If there is some animation for this input box, apply some wait, not static. you may wait for an element which comes after the animation. (My case)
You can try it out using Actions class.
Clicking the element works for me too, however, another solution I found was to enter the value using JavaScript, which doesn't require the element to have focus:
var _element= driver.FindElement(By.Id("e123"));
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript("arguments[0].setAttribute('value', 'textBoxValue')", _element);
Use JavaScript to click in the field and then use sendkeys() to enter values.
I had a similar problem in the past with frames. JavaScript is the best way.
First pass the driver control to the frame using:
driver.switchTo().frame("pass id/name/index/webelement");
After that, perform the operation which you want to do on the webelement present inside the frame:
driver.findElement(By.name("name")).sendKeys("manish");
I have gone with the same problem where copy-paste is also not working for that text box.
The below code is working fine for me:
WebDriver driver = new FirefoxDriver();
String mobNo = "99xxxxxxxx";
WebElement mobileElementIrs =
driver.findElement(By.id("mobileNoPrimary"));
mobileElementIrs.click();
mobileElementIrs.clear();
mobileElementIrs.sendKeys(mobNo);
I had a similar problem too, when I used
getDriver().findElement(By.id(idValue)).clear();
getDriver().findElement(By.id(idValue)).sendKeys(text);
The value in "text" was not completely written into the input. Imagine that "Patrick" sometimes write "P" another "Pat",...so the test failed
The fix is a workaround and uses JavaScript:
((JavascriptExecutor)getDriver()).executeScript("$('#" + idValue + "').val('" + value + "');");
Now it is fine.
Instead of
driver.findElement(By.id("idValue")).sendKeys("text");
use,
((JavascriptExecutor)getDriver()).executeScript("$('#" + "idValue" + "').val('" + "text" + "');");
This worked for me.
I had a similar problem recently and tried some of the suggestions above, but nothing worked. In the end it fell back on a brute-force retry which retries if the input box wasn't set to what was expected.
I wanted to avoid thread.sleep for obvious reasons and saw different examples of it failing that looked like some kind of race or timing condition.
public void TypeText(string id, string text)
{
const int numberOfRetries = 5;
for (var i = 1; i < numberOfRetries; i++)
{
try
{
if (TryTypeText())
return;
}
catch (Exception)
{
if (i == numberOfRetries)
throw;
}
}
bool TryTypeText()
{
var element = _webDriver.FindElement(By.Id(id));
element.Click();
element.Clear();
element.SendKeys(text);
if (element.TagName.ToLower() == "input"
&& !DoesElementContainValue(element, text, TimeSpan.FromMilliseconds(1000)))
{
throw new ApplicationException($"Unable to set the type the text '{text}' into element with id {id}. Value is now '{element.GetAttribute("value")}'");
}
return true;
}
}
private bool DoesElementContainValue(IWebElement webElement, string expected, TimeSpan timeout)
{
var wait = new WebDriverWait(_webDriver, timeout);
return wait.Until(driver =>
{
try
{
var attribute = webElement.GetAttribute("value");
return attribute != null && attribute.Contains(expected);
}
catch (StaleElementReferenceException)
{
return false;
}
});
}
In my case, I had some actions.keyDowns(Keys.CONTOL).XXXX;
But I forgot to add the keyUp for that button and that prevented from sending keys and resulted in weird behaviors
Adding X.keyUp() after the x.keyDown() fixed the issue
Try using JavaScript to sendkeys().
WebElement element = driver.findElement(By.name("name"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", element);
More information on JavaScript Executor can be found at
JavascriptExecutor - Selenium.
Generally I keep a temporary variable. This should work.
var name = element(by.id('name'));
name.clear();
name.sendKeys('anything');