d-b
d-b

Reputation: 971

How to create a basic bookmarklet that mimics Selenium?

I know Selenium, Java/Python, XPaths etc and am looking for a basic "skeleton" Javascript bookmarklet that lets me perform simple Selenium like operations on the current page, e.g. (pseudocode),

begin
document.click ("//button[@class='buy']")
wait 2 seconds
document.entertext("//form[@class='name']", "John Smith")
wait 2 seconds
document.check("//radiobutton[@class='agrees']")
end

Googling returns an infinite number of articles but so far I haven't found anything that addresses this situation.

The reason for my request is that I enter the exact same (static) values in webforms day after day.

Upvotes: 0

Views: 383

Answers (3)

Jane Soboleva
Jane Soboleva

Reputation: 136

Something like this? The code below can be saved into index.html, pressing a "Test" button simulates what you described — "buy" is clicked, then 2 seconds later the name is entered, and 2 seconds later "agree" is clicked.

<html><head><title>test</title></head>
<body>
<button class="test" onclick="myFunction()">Test</button>
<button class="buy" onclick="unhide_form()">Click me</button>
<form id="main_form" style="display: none">
  <label for="fname">First name:</label><br>
  <input class="name" type="text" id="fname" name="fname" value="" placeholder="Your name"><br>
  <input type="radio" id="agrees" class="agrees" value="agr">
    <label for="agrees">Agrees</label>
  <input type="submit" value="Submit">
</form> 
<script>
async function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
async function unhide_form() {
    var f = document.getElementById("main_form")
    f.style = "display: block"
}
async function myFunction() {
    document.getElementsByClassName("buy")[0].click()
    await sleep(2000)
    document.getElementsByClassName("name")[0].value = "John"
    await sleep(2000)
    document.getElementsByClassName("agrees")[0].click()
}
</script>
</body></html>

Not sure if that'll be enough for the real task you're facing; if not, tell more details, like the URL of the site you're visiting, the automation steps (fields you're filling, buttons you're clicking, etc), and what exactly fails.


EDIT: I see. I'm new to doing this in javascript as well, so I also learned something new in the process :) Here's the code:

function submit_wayback_machine_form(url_to_save) {
    elems = document.evaluate('//*[@id="web-save-url-input"]', document, null, XPathResult.ANY_TYPE, null );
    elem = elems.iterateNext()  //elem is now the text field
    elem.value = url_to_save    //changing its text to URL we want
    
    elems = document.evaluate('//input[starts-with(@value, "SAVE PAGE")]', document, null, XPathResult.ANY_TYPE, null );
    elem = elems.iterateNext()
    elem.click()
}

submit_wayback_machine_form("https://google.com")

Tested it, appears to be working: screenshot

Also, here are the useful links I got the info from:

  1. https://developer.mozilla.org/en-US/docs/Web/XPath/Introduction_to_using_XPath_in_JavaScript — took the xpath code from this page;
  2. https://devhints.io/xpath — a nice cheatsheet for XPath (maybe you already knew all this, but even if so, I'm saving it for myself for the future reference)
  3. also, I recommend "XPath Helper" extension for Chrome, helps me quickly test whether my XPath is correct: https://chrome.google.com/webstore/detail/xpath-helper/hgimnogjllphhhkhlmebbmlgjoejdpjl

EDIT2:

Does Javascript not support something like element.click (Xpath)? Why the iteration and evaluation of everything?

That's just how it works, we document.evaluate(...) the XPATH expression first, and then we iterate through results (multiple elements may fit the same XPATH expression).

If I had to simplify it a bit for a more convenient usage... How about this?

//this one returns the first fitting element
function getFirstElementByXPATH(xpath) {
    elems = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null);
    elem = elems.iterateNext()
    return elem
}

//this one returns an array of fitting elements
function getAllElementsByXPATH(xpath) { 
    elems = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null)
    results = []
    while (1) {
        elem = elems.iterateNext()
        if (elem != null) {
            results.push(elem)
        } else {
            break
        }
    }
    return results
}

Then, you can use

getFirstElementByXPATH("//li/div/button/span").click()
//or
getAllElementsByXPATH("//li/div/button/span")[0].click()
//or
element = getFirstElementByXPATH("//my_custom_expression_1")
element.click()
elements = getAllElementsByXPATH("//my_custom_expression_2")
elements[0].click()
elements[1].value = "abc"

Hopefully it's convenient enough!

Upvotes: 3

Leftium
Leftium

Reputation: 17903

Not a JS bookmarklet, but the Browserflow extension/service might be better to "enter the exact same (static) values in webforms day after day."

I used Browserflow to scrape data from paginated results that required clicking a button to append more results.

No JavaScript knowledge is required (although you can use JavaScript to do more complicated things if you want.)

Note this is a paid service with a limited free tier.

Upvotes: 0

pguardiario
pguardiario

Reputation: 54984

In general it looks like this:

(() => {
  document.querySelector('.buy')?.click();
  setTimeout(() => somethingElse(), 2000);
  setTimeout(() => document.querySelector('.agrees')?.click(), 4000);
})()

But I can't tell what the something else is and it won't work if there's a navigation between steps

Upvotes: 1

Related Questions