Home > OS >  Can't click link using puppeteer - Thingiverse
Can't click link using puppeteer - Thingiverse

Time:07-07

I'm trying to automate away downloading multiple files on thingiverse. I choose an object at random. But I'm having a hard time locating the link I need, clicking and then downloading. Has someone run into this before can I get some help?

I've tried several other variations.

import puppeteer from 'puppeteer';

async function main() {
    const browser = await puppeteer.launch({
        headless: true,
    });

    const page = await browser.newPage();
    const response = await page.goto('https://www.thingiverse.com/thing:2033856/files');
    const buttons = await page.$x(`//a[contains(text(), 'Download')]`);
    if(buttons.length > 0){
        console.log(buttons.length);
    }  else {
        console.log('no buttons'); 
    }
    await wait(5000);
    await browser.close();
    return 'Finish';
}
async function wait(time: number) {
    return new Promise(function (resolve) {
        setTimeout(resolve, time);
    });
}

function start() {
    main()
        .then((test) => console.log('DONE'))
        .catch((reason) => console.log('Error: ', reason));
}

start();

Download Page

Code

CodePudding user response:

I was able to get it to work. The selector is: a[class^="ThingFile__download"]

Puppeteer is: const puppeteer = require('puppeteer-extra');

Before the await page.goto() I always recommend setting the viewport:

await page.setViewport({width: 1920, height: 720});

After that is set, change the await page.goto() to have a waitUntil option:

const response = await page.goto('https://www.thingiverse.com/thing:2033856/files', { waitUntil: 'networkidle0' }); // wait until page load

Next, this is a very important part. You have to do what is called waitForSelector() or waitForFunction().

I added both of these lines of code after the const response:

await page.waitForSelector('a[class^="ThingFile__download"]', {visible: true})

await page.waitForFunction("document.querySelector('a[class^=\"ThingFile__download\"]') && document.querySelector('a[class^=\"ThingFile__download\"]').clientHeight != 0");

Next, get the buttons. For my testing I just grabbed the button href.

const buttons = await page.$eval('a[class^="ThingFile__download"]', anchor => anchor.getAttribute('href'));

Lastly, do not check the .length of this variable. In this case we are just returning the href value which is a string. You will get a Promise of an ElementHandle when you try getting just the button:

const button = await page.$('a[class^="ThingFile__download"]');
console.log(button)
if (button) { ... }

Now if you change that page.$ to be page.$$, you will be getting a Promise of an Array<ElementHandle>, and will be able to use .length there.

const buttonsAll = await page.$$('a[class^="ThingFile__download"]');
console.log(buttonsAll)
if (buttons.length > 0) { ... }

Hopefully this helps, and if you can't figure it out I can post my full source later if I have time to make it look better.

  • Related