如何使用 NodeJS 和 puppeteer 从 udemy 抓取图像

Posted

技术标签:

【中文标题】如何使用 NodeJS 和 puppeteer 从 udemy 抓取图像【英文标题】:How do I scrape images from udemy using NodeJS and puppeteer 【发布时间】:2021-12-27 17:05:09 【问题描述】:

这是我的代码 - 抓取课程标题可以,但图像有问题

const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth')
puppeteer.use(StealthPlugin());
const fs = require('fs/promises')
function sleep(ms)

    return new Promise(resolve => setTimeout(resolve, ms));

async function start()

    const browser = await puppeteer.launch( headless: true );
    const page = await browser.newPage();
    await page.goto("https://www.udemy.com/pl/courses/development/web-development/?lang=pl&sort=popularity&persist_locale=&locale=pl_PL");
    await sleep(5000);
    const names = await page.evaluate(() => 
        return Array.from(document.querySelectorAll(".course-list--container--3zXPS div.udlite-focus-visible-target.udlite-heading-md.course-card--course-title--vVEjC")).map(x => x.textContent)
    )
    const images = await page.evaluate(() => 
        return Array.from(
            document.querySelectorAll(".course-list--container--3zXPS div.course-card--image-wrapper--1F9ny")
        ).map((image) => image.getAttribute(`src`));
    );


    let m = ";";
    for (let i = 0; i < names.length; i++)
    
        names[i] = i+m+names[i]+m+images[i]
    
    await fs.writeFile("courses.txt", names.join("\r\n"))
    await page.screenshot( path: "udemy.png", fullPage: true );
    await browser.close();

start()

现在它返回 null 而不是图像 url,如果我将 src 更改为 srcset 没有任何变化。 我要抓取图片的页面是https://www.udemy.com/pl/courses/development/web-development/?lang=pl&sort=popularity&persist_locale=&locale=pl_PL

在此脚本截取的屏幕截图中,我可以看到课程图标被涂黑。我可以刮掉屏幕截图上可见的图像,但不能刮掉那些被涂黑的图像。

【问题讨论】:

sleep()waitForTimeout() 是臭名昭著的错误来源,因为在某些元素出现在动态页面中之前,您可能会弄错时间。最好将其更改为 waitForSelector() 并为您所依赖的元素使用选择器。另一方面,你们中的一些选择器似乎包含自动生成的类名——如果你能摆脱它们以使你的脚本更稳定的话。 我使用了await page.waitForSelector("#u606-popper-trigger--138 &gt; div &gt; div.course-card--image-wrapper--1F9ny") 而不是await sleep(5000);- 我从我正在抓取的站点复制了一个图像元素的选择器- 现在脚本只是无休止地等待。 【参考方案1】:

好的,我找到了答案 - 我在 QuerySelectorAll 的末尾添加了 setVievport 函数和 img

const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth')
puppeteer.use(StealthPlugin());
const fs = require('fs/promises')
function sleep(ms)

    return new Promise(resolve => setTimeout(resolve, ms));

async function start()

    const browser = await puppeteer.launch( headless: false );
    const page = await browser.newPage();
    await page.goto("https://www.udemy.com/pl/courses/development/web-development/?lang=pl&sort=popularity&persist_locale=&locale=pl_PL",  "waitUntil": "networkidle0" );
    
    await sleep(1000);
    const bodyWidth = await page.evaluate(() => document.body.scrollWidth);
    const bodyHeight = await page.evaluate(() => document.body.scrollHeight);
    await page.setViewport( width: bodyWidth, height: bodyHeight );
    await sleep(1000);

    const names = await page.evaluate(() => 
        return Array.from(document.querySelectorAll(".course-list--container--3zXPS div.udlite-focus-visible-target.udlite-heading-md.course-card--course-title--vVEjC")).map(x => x.textContent)
    )
    const images = await page.evaluate(() => 
        return Array.from(
            document.querySelectorAll(".course-list--container--3zXPS div.course-card--image-wrapper--1F9ny img")
        ).map((image) => image.getAttribute(`src`));
    );


    let m = ";";
    for (let i = 0; i < names.length; i++)
    
        names[i] = i+m+names[i]+m+images[i]
    
    await fs.writeFile("courses.txt", names.join("\r\n"))
    await page.screenshot( path: "udemy.png", fullPage: true );
    await browser.close();

start()

【讨论】:

以上是关于如何使用 NodeJS 和 puppeteer 从 udemy 抓取图像的主要内容,如果未能解决你的问题,请参考以下文章

使用 Puppeteer 如何从目录上传随机文件并将其删除?

Nodejs中puppeteer抓取浏览器HAR数据

如何使用 puppeteer 和 Node js 为 pdf 页面生成屏幕截图

如何在Puppeteer和NodeJS中把提示框的消息分配给一个变量?

Chrome Headless puppeteer CPU 过多

Puppeteer + Nodejs 通用全屏网页截图方案常用参数实现