|
|
@@ -0,0 +1,174 @@
|
|
|
+package parser;
|
|
|
+
|
|
|
+import java.time.Duration;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Optional;
|
|
|
+
|
|
|
+import org.openqa.selenium.By;
|
|
|
+import org.openqa.selenium.JavascriptExecutor;
|
|
|
+import org.openqa.selenium.StaleElementReferenceException;
|
|
|
+import org.openqa.selenium.WebElement;
|
|
|
+import org.openqa.selenium.chrome.ChromeDriver;
|
|
|
+import org.openqa.selenium.support.ui.ExpectedConditions;
|
|
|
+import org.openqa.selenium.support.ui.WebDriverWait;
|
|
|
+
|
|
|
+import com.gargoylesoftware.htmlunit.ElementNotFoundException;
|
|
|
+
|
|
|
+import object.ResultDTO;
|
|
|
+
|
|
|
+public class BetSafeParser extends ParserBase {
|
|
|
+
|
|
|
+ List<ResultDTO> result = new ArrayList<>();
|
|
|
+
|
|
|
+ public BetSafeParser() {}
|
|
|
+
|
|
|
+ public List<ResultDTO> seleniumPaseSoccerMatches() {
|
|
|
+ String url = "https://www.betsafe.com/sv/odds/fotboll";
|
|
|
+
|
|
|
+ ChromeDriver driver = getSeleniumDriver();
|
|
|
+
|
|
|
+ driver.manage().deleteAllCookies();
|
|
|
+ driver.get(url);
|
|
|
+ JavascriptExecutor js = driver;
|
|
|
+ WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
|
|
|
+ wait.until(ExpectedConditions
|
|
|
+ .numberOfElementsToBeMoreThan(By.xpath("//div[contains(@class,'obg-event-row-event-container')]"), 0));
|
|
|
+
|
|
|
+ List<WebElement> matchDivs = driver
|
|
|
+ .findElements(By.xpath("//div[contains(@class,'obg-event-row-event-container')]"));
|
|
|
+
|
|
|
+ List<WebElement> expandableDivs = driver
|
|
|
+ .findElements(By.xpath(
|
|
|
+ "//div[contains(@class, 'obg-m-events-master-detail-header') and not(contains(@class, 'expanded'))]"));
|
|
|
+
|
|
|
+ // leta upp child span med text "kommande idag" och kanske "imorgon"
|
|
|
+ // Behöver också kolla om det finns mer att ladda obg-show-more-less-button
|
|
|
+ // ng-star-inserted
|
|
|
+ // Kontrollera att det inte står "Show less" då den minimerar igen
|
|
|
+ for (WebElement element : expandableDivs) {
|
|
|
+ try {
|
|
|
+ String xpath = ".//span[text()='Live']";
|
|
|
+ if (checkIfElementExists(element, xpath)) {
|
|
|
+ element.click();
|
|
|
+ wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath(
|
|
|
+ "//div[contains(@class,'obg-event-row-event-container')]"), matchDivs.size()));
|
|
|
+ matchDivs = driver
|
|
|
+ .findElements(By.xpath("//div[contains(@class,'obg-event-row-event-container')]"));
|
|
|
+ scrollElementIntoView(driver, element);
|
|
|
+ }
|
|
|
+
|
|
|
+ xpath = ".//span[text()='Kommande idag']";
|
|
|
+ if (checkIfElementExists(element, xpath)) {
|
|
|
+ element.click();
|
|
|
+ wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath(
|
|
|
+ "//div[contains(@class,'obg-event-row-event-container')]"), matchDivs.size()));
|
|
|
+
|
|
|
+ matchDivs = driver
|
|
|
+ .findElements(By.xpath("//div[contains(@class,'obg-event-row-event-container')]"));
|
|
|
+ scrollElementIntoView(driver, element);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ xpath = ".//span[text()='Imorgon']";
|
|
|
+ if (checkIfElementExists(element, xpath)) {
|
|
|
+ element.click();
|
|
|
+ wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath(
|
|
|
+ "//div[contains(@class,'obg-event-row-event-container')]"), matchDivs.size()));
|
|
|
+
|
|
|
+ matchDivs = driver
|
|
|
+ .findElements(By.xpath("//div[contains(@class,'obg-event-row-event-container')]"));
|
|
|
+ scrollElementIntoView(driver, element);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (ElementNotFoundException e) {
|
|
|
+ // Empty by design, no more matches today
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ expandAllMatches(driver, wait, matchDivs);
|
|
|
+
|
|
|
+ matchDivs = driver
|
|
|
+ .findElements(By.xpath("//div[contains(@class,'obg-event-row-event-container')]"));
|
|
|
+
|
|
|
+ js.executeScript("window.stop;");
|
|
|
+ for (WebElement match : matchDivs) {
|
|
|
+ parseMatch(driver, match);
|
|
|
+ }
|
|
|
+ System.out.println("found " + matchDivs.size() + " matches");
|
|
|
+
|
|
|
+ driver.close();
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void expandAllMatches(ChromeDriver driver, WebDriverWait wait, List<WebElement> matchDivs) {
|
|
|
+ List<WebElement> buttons = driver
|
|
|
+ .findElements(By.xpath("//button[contains(@class,'obg-show-more-less-button')]"));
|
|
|
+ scrollElementIntoViewCenter(driver, buttons.get(0));
|
|
|
+
|
|
|
+ for (WebElement button : buttons) {
|
|
|
+ WebElement findElement = button.findElement(By.xpath(".//span"));
|
|
|
+ while (!findElement.getText().contains("färre")) {
|
|
|
+ scrollElementIntoViewCenter(driver, buttons.get(0));
|
|
|
+ button.click();
|
|
|
+ findElement = button.findElement(By.xpath(".//span"));
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if (buttons.size() > 0) {
|
|
|
+ wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath(
|
|
|
+ "//div[contains(@class,'obg-event-row-event-container')]"), matchDivs.size()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void parseMatch(ChromeDriver driver, WebElement match) {
|
|
|
+ // teams div, two div children with hometeam awayTeam
|
|
|
+ // "class obg-event-info-participant obg-event-info-participant-default-layout"
|
|
|
+ try {
|
|
|
+ List<WebElement> participants = match
|
|
|
+ .findElements(By.xpath(".//div[@class='obg-event-info-participant-label ng-star-inserted']"));
|
|
|
+
|
|
|
+ String homeTeamName = participants.get(0).getAttribute("title");
|
|
|
+ String awayTeamName = participants.get(1).getAttribute("title");
|
|
|
+
|
|
|
+ List<WebElement> oddsContainers = match.findElements(By.xpath(".//obg-event-row-market-container"));
|
|
|
+
|
|
|
+ Optional<WebElement> matchOddsContainer = oddsContainers.stream()
|
|
|
+ .filter(p -> p.findElement(By.xpath("//header/div/span"))
|
|
|
+ .getText().equals("Matchresultat"))
|
|
|
+ .findFirst();
|
|
|
+ float odds1 = -1f;
|
|
|
+ float oddsX = -1f;
|
|
|
+ float odds2 = -1f;
|
|
|
+ if (matchOddsContainer.isPresent()) {
|
|
|
+ List<WebElement> oddsValueContainers = matchOddsContainer.get()
|
|
|
+ .findElements(By.xpath(".//section//span[@test-id='odds']"));
|
|
|
+
|
|
|
+ if (!oddsValueContainers.isEmpty()) {
|
|
|
+ odds1 = formatFloat(oddsValueContainers.get(0).getText());
|
|
|
+ oddsX = formatFloat(oddsValueContainers.get(1).getText());
|
|
|
+ odds2 = formatFloat(oddsValueContainers.get(2).getText());
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ result.add(new ResultDTO(homeTeamName, awayTeamName, odds1, oddsX, odds2));
|
|
|
+ System.out.println(homeTeamName + "-" + awayTeamName + " odds (" + odds1 + "," + oddsX + "," + odds2 + ")");
|
|
|
+ } catch (StaleElementReferenceException e) {
|
|
|
+ System.out.println("Stale element, refreshing");
|
|
|
+ driver.navigate().refresh();
|
|
|
+ parseMatch(driver, match);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private float formatFloat(String string) {
|
|
|
+ float result = -1f;
|
|
|
+ try {
|
|
|
+ result = Float.parseFloat(string);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ // Empty by design
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+}
|