javaPolarM2 is a Java automation tool that uses Selenium WebDriver to scrape and export training data from the Polar Flow website.
For a given training session it will:
- Log in to Polar Flow automatically
- Export the session files (CSV, GPX, TCX) via the Polar export API
- Scrape the training detail page — training benefit, cardio load, sport heading, pace target, phases (intervals), laps, and automatic laps
- Write all scraped data to a structured XML file on disk
- Copy the matching track file to the configured output directory
- Fill in and submit a local or remote PHP upload form
| Requirement | Recommended version |
|---|---|
| Java JDK | 11 or higher |
| Apache Maven (or Gradle) | latest stable |
| Selenium Java | 4.x |
| ChromeDriver | must match your installed Chromium/Chrome version |
| Chromium or Google Chrome | latest stable |
Maven — add to pom.xml:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.20.0</version>
</dependency>Gradle — add to build.gradle:
implementation 'org.seleniumhq.selenium:selenium-java:4.20.0'ChromeDriver must match the major version of the Chromium/Chrome browser installed on your machine.
- Check your Chrome version: open Chrome →
chrome://settings/help - Download the matching ChromeDriver from: https://googlechromelabs.github.io/chrome-for-testing/
- Extract the binary and note the full path — you will need it for
WEB_DRIVER_PATHbelow.
Open javaPolarM2.java and fill in the constants at the top of the class before running.
// Directory where output XML, CSV and GPX files are written
private static final String POLAR_FILES_PATH = "/path/to/polar/output/robotflow/";
// Absolute path to the chromedriver binary
private static final String WEB_DRIVER_PATH = "/path/to/chromedriver";
// Directory where the browser saves downloaded files
private static final String DOWNLOADS_PATH = "/path/to/downloads/robotflow/";The Polar and Runkeeper URLs are correct as shipped. Only change these if the sites restructure their URLs.
private static final String URL_LOCAL_HOST = "http://localhost/your-project/";
private static final String URL_REMOTE_HOST = "www.example.com/your/upload_form.php";The credentials for the remote host are currently hardcoded inside
openRemoteHost(). Move them to constants or an external config file before deploying.
private static String polarUser = "your.email@example.com";
private static String polarPassword = "yourPolarPassword";
private static String polarName = "YourName"; // used in output file names
private static String runKeeperUser = "your.email@example.com";
private static String runKeeperPassword = "yourRunKeeperPassword";Security note: Do not commit credentials to version control. Consider reading them from environment variables or a properties file at startup.
In main(), the training ID is currently hardcoded for testing. Switch to the dynamic version when you are ready:
// Option A – dynamic: reads the ID from the current page URL
// String trainingId = extractTrainingNumber(driver);
// Option B – hardcoded: useful for repeatable testing
String trainingId = "0000000000"; // ← replace with a real training ID# Compile
mvn compile
# Run
mvn exec:java -Dexec.mainClass="javaPolarM2.javaPolarM2"Or run directly from your IDE (IntelliJ IDEA, Eclipse, VS Code with the Java extension).
Logging is configured via mylogging.properties in the project root. If the file is missing, a fallback ConsoleHandler at level FINE is used automatically.
Example mylogging.properties:
handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=FINE
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
javaPolarM2.javaPolarM2.level=FINEAll output files are written to POLAR_FILES_PATH:
| File | Description |
|---|---|
YYYYMMdd_HHmmss.xml |
Scraped training data in XML format |
<polarName>_YYYY-MM-dd.* |
Copied track files (GPX / CSV / TCX) |
- The XPath selectors are tightly coupled to the current Polar Flow page layout and may break after a site update.
- The remote-host credentials in
openRemoteHost()are hardcoded — move these to a config file for production use. loginPolarLegacy()targets an older login page layout and is kept only for reference; useloginPolar()instead.