javascript - 使用 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);
}
}
解决方案
.forEach()
不适合异步任务:它一次启动所有 callbacs,因此在您的情况下,所有功能都混合在一起并与一页混乱的事情一起工作。通常 for..of 循环更好。'.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();
推荐阅读
- node.js - 使用 NodeJS 获取具有特定文件扩展名的整个谷歌云中的文件名和路径列表
- php - php smarty模板引擎中的IP API
- c++ - C++ 是否有 __new__ 等价物?
- node.js - Hyperledger 结构 - 使用 sendTransactionProposal() API 时无响应
- flutter - Flutter 自定义 Painter 设计
- python - 如何将列表传递到模板
- nginx - Nginx 代理传递指令:上游错误中的端口无效
- javascript - 如何在前端显示保存在localStorage中的对象的数据?目标:展示未注册用户添加到收藏夹的产品
- debian - debian系统管理工具
- android - 如何在 RecyclerView 中使用 FrameLayout