Goal: Automate data backup from a third party site.
Scenario:
The data is available on a web page as a series of elements. ex:
[Data A]
[Data B]
[Data ...]
- Click on a
Dataelement.
- After a short delay, elements will be populated under the data element and a [Save] button will appear. ex:
+ [Data A]
[ ] item 1
[ ] item 2
...
[ ] item N
[Save]
- Select all
items
- Click [Save] to download.
Repeat steps 1-4 to save each Data element for a complete backup.
In synchronous psuedo code this would be:
alerts [array]
for i in alerts
click alerts[i].load
check if data ready; ready when save button appears
click select_all
click save
How can this be done in Javascript?
-
What is causing the new element to come into existence?tmdesigned– tmdesigned2020年01月29日 00:47:37 +00:00Commented Jan 29, 2020 at 0:47
-
Are you writing code to scrape or otherwise interact with a 3rd party page, or do you control this page?David– David2020年01月29日 00:53:49 +00:00Commented Jan 29, 2020 at 0:53
-
@tmdesigned step 1. clicking the specific alert.encore2097– encore20972020年01月29日 01:45:02 +00:00Commented Jan 29, 2020 at 1:45
-
@David 3rd party siteencore2097– encore20972020年01月29日 01:45:07 +00:00Commented Jan 29, 2020 at 1:45
-
@MisterJojo your comment directly contradicts the docs api.jquery.com/click w3schools.com/jsref/met_html_click.asp ; perhaps a thorough reading of the docs is in order unless you desire to confuse others and hinder their learningencore2097– encore20972020年01月29日 18:56:19 +00:00Commented Jan 29, 2020 at 18:56
2 Answers 2
It's a little unclear on the flow of your steps and what you are wanting the output to be. However, I think what you're ultimately after is how to listen to an event, wait some time, then do another event.
Below is an example of using Promises to create a wait method.
- Click Alerts button
- Save button appears
- 5 second wait time is triggered
- After 5 seconds, you will see a
console.logmessage
const btn = document.getElementById('alerts');
btn.addEventListener( 'click', async () => {
createSaveElement();
console.log('waiting 5 seconds');
await wait(5);
console.log('finished waiting 5 seconds');
});
function createSaveElement() {
const container = document.getElementById('container');
const saveBtn = document.createElement('button');
saveBtn.innerText = 'Save';
container.append(saveBtn);
}
async function wait(seconds) {
return new Promise( (resolve, reject) => {
setTimeout( () => {
resolve();
}, seconds * 1000);
});
}
<button id="alerts">Alerts</button>
<div id="container"></div>
3 Comments
Promise. You can you while loop logic there, but I would suggest you look into DOM Mutation Events or some other method to tell you when the page has loaded the data you're after. At the end of all that, resolve your Promise. You can pass whatever data you want into the resolve(...) function. It will be returned to whatever is awaiting it.Got it done with a macro and Firefox console.
Solution that works:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function backup() {
var alerts = $('.alerts');
var imax = alerts.length;
for (let i = 0; i < imax; i++) {
alerts[i].click();
await sleep(2000);
$('.ui-select-all').click();
await sleep(200);
$('#save');
await sleep(500);
}
}
backup();
Solution that may work:
JavaScript pausing execution of function to wait for user input
A recursive, callback version
If there's a succinct event based approach I'd prefer and accept that as the answer
Update: optimal solution: Event delegation allows an event listener to be attached to a dynamically created element, even if that element does not yet exist. The event listener can call an anonymous function after the sub element is created.
https://davidwalsh.name/event-delegate
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events