首页 > 解决方案 > 使用 puppeteer 单击元素列表

问题描述

我想使用 puppeteer 从 ZipRecruiter 中为我的个人项目刮取工作数据。我目前的方法是使用 puppeteer 转到一个 ziprecruiter URL,例如https://www.ziprecruiter.com/candidate/search?search=React&location=San+Francisco并获取所有可点击的作业名称。由于这些项目实际上不是<a>标签,我不能简单地获取它们的 href 属性并使用 puppeteer 转到该页面,然后将页面的 HTML 传递给cheerio 以抓取我需要的数据。

相反,我试图将所有职位(类为('.just_job_title'))保存在一个变量中,然后使用 puppeteer 单击每个职位,打开新页面,如果此页面属于 ZipRecruiter,则抓取我需要的信息。然后使用page.goBack()返回到原来的URL。但是,我当前的方法导致错误:UnhandledPromiseRejectionWarning: Error: Protocol error (Runtime.callFunctionOn): Target closed.我不太确定如何实现我上面概述的所需场景。

这是我的代码:

export async function getJobsZipRecruiter(params) {
const ZIPRECRUITER_URL = `https://www.ziprecruiter.com/candidate/search?search=React&location=San+Francisco`;

try {
  console.log('Trying to scrape *************');
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  await page.goto(ZIPRECRUITER_URL);
  await page.waitForSelector('#createAlertPop');

 
  const jobs = await page.$$('.just_job_title');

  jobs.forEach(async (job) => {
      await page.waitForSelector('.just_job_title');
      await job.click();
      console.log('Yes it worked');
      // Get the data you want here and push it into the data array
      await page.goBack();
    });

  console.log(jobs)


  await browser.close();
  return zipRecruiterJobs;
} catch (err) {
  console.log(err);
}


}

标签: javascriptnode.jsasynchronouspuppeteer

解决方案


  1. .forEach()不适合异步任务:它一次启动所有 callbacs,因此在您的情况下,所有功能都混合在一起并与一页混乱的事情一起工作。通常 for..of 循环更好。

  2. '.just_job_title'element 是链接的子元素,因此您可以收集所有href并逐个处理它们。

尝试这样的事情:

const puppeteer = require('puppeteer');

async function getJobsZipRecruiter(params) {
  const ZIPRECRUITER_URL = `https://www.ziprecruiter.com/candidate/search?search=React&location=San+Francisco`;

  try {
    console.log('Trying to scrape *************');
    const browser = await puppeteer.launch({ headless: false });
    const [page] = await browser.pages();
    await page.goto(ZIPRECRUITER_URL);
    await page.waitForSelector('#createAlertPop');

    const urls = await page.evaluate(() => Array.from(
      document.querySelectorAll('a[href][data-tracking="job_title"].job_link.t_job_link'),
      link => link.href,
    ));

    console.log(urls);
    const zipRecruiterJobs = [];

    for (const url of urls) {
      await page.goto(url);
      if (!page.url().startsWith('https://www.ziprecruiter.com/')) continue;
      await page.waitForSelector('h1.job_title');
      // Get the data you want here and push it into the data array
      zipRecruiterJobs.push(
        await page.evaluate(() => document.querySelector('h1.job_title').innerText)
      );
    }

    await browser.close();
    console.log(zipRecruiterJobs);
    return zipRecruiterJobs;
  } catch (err) {
    console.log(err);
  }
}

getJobsZipRecruiter();

推荐阅读