0

I’m currently using selenium in a web bot to purchase items on a website. When I search for the item I want to buy and it cannot be found I use driver.navigate().refresh() to refresh the page to see if it is there now, it will keep doing this until it finds the product when it is released on the page. However, I wish to start my bot a few hours before the release of the product which currently doesn’t work as after roughly 30 seconds of refreshing the page I get banned from the page due to the anti-ddos software they use. One option is to increase the delay between refreshing, however I need to catch the release of this product as soon as possible so I’m trying to find a way that my program can wait/sleep until 30 seconds before the release however I’m struggling to find a way to do this.

Kaan
  • 5,434
  • 3
  • 19
  • 41
  • Can't you keep the sleep short but after waking up you check the time, and if the time is very close to release time only then you make the request? You can actually start with a long sleep time like take the time left less than 5 mins or so, and then only if it is close shorten the sleep times between requests. – jbx Oct 21 '19 at 17:02

2 Answers2

2

Just call Thread.sleep with the appropriate amount of milliseconds:

public static void main(String[] args) throws InterruptedException {
    long currentTime = System.currentTimeMillis();
    long releaseTime = currentTime + 1000 * 60 * 60 * 24 * 3; // 3 days

    Thread.sleep(releaseTime - currentTime);
}

Another way would be to use java.time classes:

public static void main(String[] args) throws InterruptedException {
    LocalDateTime now = LocalDateTime.now();
    LocalDateTime release = LocalDateTime.of(2019, 10, 30, 13, 30);

    long sleepDuration = Duration.between(now, release).toMillis();
    TimeUnit.MILLISECONDS.sleep(sleepDuration);
}

Java 9 introduces new methods to the Duration class like toSeconds(), toMinutes() and so on.

You could also consider using a ScheduledExecutorService to schedule your tasks. This is especially useful if you have multiple tasks to schedule and don't want having multiple threads being blocked for that:

private static final ScheduledExecutorService service = new ScheduledThreadPoolExecutor(2);

private static ScheduledFuture<?> scheduleTask(Runnable task, LocalDateTime releaseTime) {
    Duration duration = Duration.between(LocalDateTime.now(), releaseTime);
    return service.schedule(task, duration.toSeconds(), TimeUnit.SECONDS);
}

In general, to sleep until the next Thursday at 10:59 you could use the following code:

LocalDateTime release = LocalDateTime.now()
            .with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY))
            .withHour(10)
            .withMinute(59);

Duration duration = Duration.between(LocalDateTime.now(), release);
TimeUnit.MILLISECONDS.sleep(duration.toMillis());
Alex R
  • 3,139
  • 1
  • 18
  • 28
  • Why not just `while (release.isBefore(LocalDateTime.now())) { } ` and then fall through into the routine after that point? – Bryan Oct 21 '19 at 17:07
  • 2
    @Bryan Because that would be busy waiting blocking the CPU – Alex R Oct 21 '19 at 17:08
  • @Bryan it would be the equivalent of asking "are we there yet?" on a car ride. – Kayaman Oct 21 '19 at 17:11
  • His current bot constantly refreshes until it's banned but could conceivably have the same wait behavior. – Bryan Oct 21 '19 at 17:12
  • 1
    @Bryan Nobody says it couldn't, but I just don't think that it's a good solution. – Alex R Oct 21 '19 at 17:14
  • Thanks, this looks suitable I'll try this out for the next online store update –  Oct 21 '19 at 17:24
  • that works well, however, the user of the bot would have to alter this every week is there a way for it to work for every Thursday at 10:59:30 –  Oct 21 '19 at 18:48
  • You could take the current time, find the next Thursday using a `TemporalAdjuster`, and then do the calculation as before. Take a look a [this](https://stackoverflow.com/questions/24177516/get-first-next-monday-after-certain-date). Is that what you meant? – Alex R Oct 21 '19 at 19:25
  • @AlexR My current code is this: `LocalDateTime now = LocalDateTime.now(); LocalDateTime release = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY); long sleepDuration = Duration.between(now, release).toMillis(); TimeUnit.MILLISECONDS.sleep(sleepDuration);` which is functional an waits for the next thursday however i still need the level of time accuracy from the previous method (`LocalDateTime release = LocalDateTime.of(2019, 10, 24, 10, 59, 30);`) –  Oct 21 '19 at 22:22
  • @AlexR do you know how I would get my current code to wait until the next Thursday and then when it is Thursday to wait until 10:59:30 –  Oct 21 '19 at 22:25
  • @GeorgeFitzpatrick You can use the `LocalDateTime#withHour` [JavaDoc](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/LocalDateTime.html#withHour(int)), `withMinute`, and `withSecond` functions for that. Just chain these calls and assign them to the `release` variable right before you calculate the `Duration`. – Alex R Oct 21 '19 at 23:44
  • @GeorgeFitzpatrick Should I add that to my answer or is there another reason you 'unaccepted' it? – Alex R Oct 21 '19 at 23:56
  • Thanks again that works perfectly. Also could you please add that to your answer then I'll mark it as correct as I feel it would be easier for other users with the same problem to find the answer –  Oct 22 '19 at 11:14
1

I think rather than sleeping you should take a look at scheduled tasks with cron expressions in Spring... that way you don't have a blocked thread just sitting there.

Scheduled Tasks with Spring
Cron Expressions

davesbrain
  • 606
  • 7
  • 12
  • Are you sure that your last sentence is true? I think the `Scheduled` annotation uses a `ScheduledExecutorService` using a `DelayQueue` which still results in a blocked thread. – Alex R Oct 21 '19 at 17:23
  • I'm not sure about the blocked thread, but I am pretty sure it is a cleaner development pattern. – davesbrain Oct 21 '19 at 17:50
  • Sure, if you are already using Spring then this might be the cleaner option. But the OP never mentioned Spring. – Alex R Oct 21 '19 at 18:00