新标签不会在 puppeteer Node js 中打开

New tab doesnt open in puppeteer Node js

我正在使用 Puppeteer 构建一个自动购物机器人。我已将此功能 addToCart 添加到购物车。添加产品后,我想在同一个浏览器会话中打开一个新的 url,但它不起作用。

const puppeteer = require("puppeteer");

const product_url =
  "https://www.amazon.com/gp/product/B08ZL7LZW3?pf_rd_r=J6QNRZDRJ7Z8FSF2HVXR&pf_rd_p=6fc81c8c-2a38-41c6-a68a-f78c79e7253f&pd_rd_r=d3adff00-5e6f-4456-8fd0-bd187f2ff86d&pd_rd_w=oO6kF&pd_rd_wg=aoGGq&ref_=pd_gw_unk";

const checkout_url = "https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1";

async function givePage() {
  const browser = await puppeteer.launch({
    headless: false,
  });
  const page = await browser.newPage();
  return page;
}

async function addToCart(page) {
  await page.goto(product_url);
  await page.waitForSelector(
    "button[class='single_add_to_cart_button button alt']"
  );

  await page.click(
    "button[class='single_add_to_cart_button button alt']",
    (elem) => elem.click()
  );
}

async function checkout() {
  var page = await givePage();
  await addToCart(page);
  await page.waitForNavigation();
  const page2 = await browser.newPage(); // open new tab
  await page2.goto("https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1"); // go to github.com
  await page2.bringToFront(); // make the tab active
}

checkout();

每次调用givePage都会从头创建一个新的浏览器,但在函数returns时放弃对浏览器对象的引用,导致无法获取新页面或关闭它。

您可能想要制作一个浏览器,从中拉出一个页面,然后从不同的功能重复访问同一页面。

或者,您可能希望使用一个浏览器,然后按需生成新页面(“选项卡”),就像这里的情况一样。

在变量中缓存承诺是实现这些目标的一种方法。在外部范围内,您可以编写

const browserPromise = puppeteer.launch({headless: false});

请注意,没有 await。这个想法是缓存解析到浏览器的承诺。当稍后在代码中调用 await browserPromise 时,promise 始终解析为相同的底层浏览器实例。同样的方法也适用于页面——const pagePromise = browser.newPage(); 多次调用将始终为您提供相同的页面对象。

这是一个例子。错误处理和 getting past Amazon's robot blocker 留作练习。

const puppeteer = require("puppeteer");

const product_url = "https://www.amazon.com/gp/product/B08ZL7LZW3?pf_rd_r=J6QNRZDRJ7Z8FSF2HVXR&pf_rd_p=6fc81c8c-2a38-41c6-a68a-f78c79e7253f&pd_rd_r=d3adff00-5e6f-4456-8fd0-bd187f2ff86d&pd_rd_w=oO6kF&pd_rd_wg=aoGGq&ref_=pd_gw_unk";
const checkout_url = "https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1";

const browserPromise = puppeteer.launch({headless: false});

const newPage = () => browserPromise.then(browser => browser.newPage());

async function addToCart(page) {
  await page.goto(product_url);
  await page.waitForSelector(
    "button[class='single_add_to_cart_button button alt']"
  );

  await page.click(
    "button[class='single_add_to_cart_button button alt']",
    (elem) => elem.click()
  );
}

async function checkout() {
  const page = await newPage();
  await addToCart(page);
  await page.waitForNavigation();
  const page2 = await newPage(); // open new tab
  await page2.goto("https://www.amazon.com/gp/buy/shipoptionselect/handlers/display.html?hasWorkingJavascript=1"); // go to github.com
  await page2.bringToFront(); // make the tab active

  const browser = await browserPromise;
  await browser.close();
}

checkout();

也就是说,对于像这样的小脚本,您始终可以将所有代码内联到一个函数中。如果您的脚本执行一个简单的任务并且可以用 10 或 20 行代码编写,那么创建抽象可能还为时过早。

对于较大的脚本,您可能希望增加抽象并将浏览器和相关页面功能集中在一个 class 或对象中,但是无论您有一个对象 属性 还是一个松散的承诺, awaiting 一个浏览器或页面重复承诺的基本方法是相同的。