In general, the way I approach problems like this is to find the top most element that contains all the product information for a single product. Return those elements as a collection and iterate through it. In each iteration, look for the different info containing elements... check for existence and get data if they exist. This method will allow you to neatly capture all properties/data for each product as a package.
The problem with your approach is that you are storing data elements, e.g. subtitles, separate from the product. So, imagine if your have 4 products on the page and only 2 of them have subtitles. You loop through the 4 products (by index) accessing the subtitles... you will have 2 problems: 1) You will run off the end of the subtitles array because there are only 2 and you are looping to 4. 2) Your subtitles array won't match up with the product in the product array.
Imagine this is your page
Product1
Subtitle1
Product2
Product3
Subtitle3
Product4
Your array of products will contain: Product1, Product2, Product3, Product4
Your array of subtitles will contain: Subtitle1, Subtitle3
So when you loop using the product index you will get:
Product1, Subtitle1
Product2, Subtitle3 // notice the mismatch 2 and 3
Product3, Array out of index error
So you ran off the end of your subtitles array and your subtitles don't match up with the corresponding product. Hopefully that makes more sense with the example...
Anyway, here's how I do this. I didn't have the mobile app so I went to flipkart.com and searched for flip covers and wrote the code below to demonstrate what I'm talking about. This code works, I just ran it.
public static void main(String[] args)
{
WebDriver driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.get("http://www.flipkart.com/search?q=flip+cover&as=on&as-show=on&otracker=start&as-pos=4_q_flip+cover&sid=search.flipkart.com&storePath=search.flipkart.com&type=pr&redirectToResponseURL=false&redirection=true&isMsiteTraffic=1");
List<Product> products = new ArrayList<>(); // List of Product type that will contain each product on the page
List<WebElement> productContainers = driver.findElements(By.cssSelector("div.gd-col.gu3")); // the outermost element that contains all data related to a given product
// loop through the product container elements and extract each bit of data that we care about
for (WebElement productContainer : productContainers)
{
String name = productContainer.findElement(By.cssSelector("a[data-tracking-id='prd_title']")).getText().trim();
String ratingStars = ""; // we have to initialize these variables at this scope so we can access them later outside the IF below
String NoOfRatings = ""; // NOTE: if a rating does not exist for this product, ratingStars and NoOfRatings will be empty string, ""
// these next two lines are how we determine if a piece of data exists... get the element using .findElements...
List<WebElement> ratingContainer = productContainer.findElements(By.cssSelector("div.pu-rating"));
// ... and then check to see if the list is empty
if (!ratingContainer.isEmpty())
{
// ratings exist for this product, grab the relevant data
WebElement rating = ratingContainer.get(0).findElement(By.cssSelector("div.fk-stars-small"));
ratingStars = rating.getAttribute("title"); // product rating in stars
NoOfRatings = ratingContainer.get(0).getText().trim(); // the total number of ratings, you can parse this string and extract the number, if desired
}
String finalPrice = productContainer.findElement(By.cssSelector("div.pu-final")).getText().trim(); // the price, you can extract the number, if desired
products.add(new Product(name, finalPrice, ratingStars, NoOfRatings)); // add all the relevant data into a nice, neat package just for this one product
}
// dumps the data for the products on the page
for (Product product : products)
{
System.out.println("Product: " + product.name);
System.out.println("Rating: " + product.ratingStars);
System.out.println("Number of ratings: " + product.NoOfRatings);
System.out.println("Final price: " + product.finalPrice);
System.out.println("-----------------------------");
}
}
// this class holds just 4 bits of data for each product, you can obviously add more to the class if you want to store more data
public static class Product
{
public String name;
public String finalPrice;
public String ratingStars;
public String NoOfRatings;
public Product(String name, String finalPrice, String ratingStars, String NoOfRatings)
{
this.name = name;
this.finalPrice = finalPrice;
this.ratingStars = ratingStars;
this.NoOfRatings = NoOfRatings;
}
}
The output looks like
-----------------------------
Product: KolorEdge Flip Cover for Lenovo A6000 Plus (Black)
Rating: 3 stars
Number of ratings: (26 ratings)
Final price: Rs. 160
-----------------------------
Product: Jeelo Flip Cover for Motorola Moto G 2nd Generation (Bl...
Rating: 3 stars
Number of ratings: (128 ratings)
Final price: Rs. 137
-----------------------------
...