发布于 2026-01-06 6 阅读
0

如何在PlayStation 5总是缺货的情况下买到它

如何在PlayStation 5总是缺货的情况下买到它

在新冠疫情肆虐的当下,游戏主机比以往任何时候都更加抢手。由于人们大部分时间都待在家中,许多人转向电子游戏来消磨时间,导致最新最热门的游戏主机几乎瞬间售罄。如果你没能成为首发时抢购到一台的幸运儿,那么你的选择只有两个:1)每天守在零售商的网站上,希望碰巧在你访问时有货;2)从eBay上的转售商那里购买,价格通常会高出200%。这两种选择听起来都毫无吸引力。

但是,如果你是一位聪明的软件工程师,你就会意识到,在这种情况下,你可以利用你的软件工程技能来获得优势。为什么不利用你的知识编写一个简单的程序,在你想要的商品重新上架时提醒你呢?

有一个名为Playwright 的Node.js 库,它支持在大多数浏览器上实现自动化。设置非常简单,不到一个小时就能构建一个简单的网页抓取脚本。

举个例子,我们用 Playwright 写个程序,当 PlayStation 5 游戏机在百思买重新上架时发送提醒。这样做的一个缺点是,你需要为每个销售该商品的零售商编写自定义爬虫,但实际上,这样的零售商有多少呢?可能不到 10 家。而且,编写这些脚本的过程也基本相同。

第一步:安装和入门

首先,请确保已安装 Node.js。要检查是否已安装 Node.js,请node -v在终端中运行 `node -v`。如果返回 Node.js 的版本信息(例如,类似 `node -v` 的内容),则说明已安装。否则,您可以从此处v14.13.1安装。安装完成后,请在终端中运行 `node -v`。npm i -D playwright

接下来,在你的脚本中,require使用 Playwright 创建一个异步函数来启动浏览器(在本例中为 Firefox)。

const { firefox } = require('playwright');
(async () => {
  const browser = await firefox.launch();
  // do something here...
})();
Enter fullscreen mode Exit fullscreen mode

脚本运行时,该函数将立即被调用。

此脚本中的代码将大量使用 async/await 模式。如果您想了解更多相关信息,请参阅相关文档,其中有详细的解释。

步骤二:前往零售商网站

我们来编写一个专门用于在百思买搜索 PlayStation 5 游戏机的函数,并将其传递给浏览器。然后我们可以在异步函数中调用它。

(async () => {
  const browser = await firefox.launch();
  searchBestBuyForPS5(browser);
})();
Enter fullscreen mode Exit fullscreen mode

在该searchBestBuyForPS5函数内部,首先需要做的就是访问零售商的网站。

var searchBestBuyForPS5 = async (browser) => {
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto('https://www.bestbuy.com');
  // more code to come...
}
Enter fullscreen mode Exit fullscreen mode

步骤 3:搜索产品

从这里开始,你的函数会根据你所操作的网站的 DOM 结构略有不同。要在百思买网站上搜索 PlayStation 5 游戏机,我们首先需要检查页面并获取包含搜索输入框的元素。

替代文字

对于百思买来说,搜索输入框的 ID 是'gh-search-input'。我们可以使用该 ID 来指定输入搜索词的位置。

  await page.type('#gh-search-input', 'playstation 5 console', {delay: 100});
  await sleep(3000);
  await page.press('.header-search-button', 'Enter');
  await sleep(1000);
Enter fullscreen mode Exit fullscreen mode

(这段代码仍然要放在searchBestBuyForPS5函数中,紧接在第二步的代码之后。)

让我们来分析一下这段代码块。在代码块的第一行,typePlaywright 函数接收两个或多个参数。第一个参数是选择器,用于选择我们想要的元素。在本例中,我们指定要选择 id 为 `<element>` 的元素'gh-search-input'。第二个参数是文本,也就是搜索词。在本例中,它是 `<search-word>` 'playstation 5 console'。(在继续之前,最好在零售商的网站上实际输入你的搜索词,并确保搜索结果包含你想要的产品。)第三个参数是一个可选的延迟参数。它的作用是将搜索栏中每个字母的输入延迟 100 毫秒,以更好地模拟人类的输入方式。如果不这样做,网站可能会怀疑你使用的是机器人,而实际上,你的确在使用机器人。

上面代码块中的第二行代码允许程序有时间输入完整的搜索词,然后再继续执行。该行调用的 sleep 辅助函数如下所示:

const sleep = (milliseconds) => {
  return new Promise(resolve => setTimeout(resolve, milliseconds))
}
Enter fullscreen mode Exit fullscreen mode

第三行代码选中了搜索栏的提交按钮(类名为 `<class name>`),'header-search-button'然后按下回车键。之后,出于上述反机器人检测的原因,程序会休眠一秒钟。

这些代码执行完毕后,我们应该可以访问一个显示搜索结果的页面:

替代文字

第四步:确定目标物品

或者更具体地说,获取目标项的 innerHTML。

替代文字

从搜索结果页面来看,我们想要查找的元素似乎是类名为 `<li>` 的 `<li>` 元素'sku-item',因此我们可以利用这个信息来识别它们。但是,在找到它们之前,我们必须确保这些 DOM 元素已经完全渲染完毕。

  await page.innerHTML('li.sku-item'); // wait for elements to render
  const results = await page.$$('li.sku-item');
  for (let i = 0; i < results.length; i++) {
    // get name of item
    const skuHeader = await results[i].$('h4.sku-header'); 
    const html = await skuHeader.innerHTML();

    // check whether item's name contains "playstation 5" and "console"
    if (html.toLowerCase().includes('playstation 5') && html.toLowerCase().includes('console')) {
      // check in-stock status...
    }
  }
Enter fullscreen mode Exit fullscreen mode

(注:.$.$$都是查询选择器。区别在于,如果没有找到匹配项,则.$返回 null ,而返回空数组。)null.$$

第五步:检查商品是否有库存

在上面的代码块的条件语句中,我们可以检查商品是否有库存。首先,我们必须选择提供商品库存状态信息的元素。在这个特定的页面上,“售罄”按钮与“加入购物车”按钮相同,只是被禁用了。因此,它仍然有一个类名'add-to-cart-button',我们可以使用它来查询该按钮。

      const button = await results[i].$('button.add-to-cart-button')
      const buttonText = await button.innerText()
      if (buttonText !== "Sold Out") {
        // alert user!
      }
Enter fullscreen mode Exit fullscreen mode

步骤 6:通知用户商品已重新到货!

此时,如果我们的程序检测到某件商品已重新上架,它必须立即通知我们,以便我们在商品再次售罄前抢购。一种方法是使用Twilio发送短信提醒。为此,您需要注册一个 Twilio 账户并购买一个用于发送这些提醒的号码。

完整代码

如果您想在一个地方查看所有代码,请看这里:

// require playwright and launch browser
const { firefox } = require('playwright');
(async () => {
  const browser = await firefox.launch({ headless: false });
  searchBestBuyForPS5(browser);
})();

// helper function for sleeping
const sleep = (milliseconds) => {
  return new Promise(resolve => setTimeout(resolve, milliseconds))
}

// search whether PS5 is in stock at Best Buy
var searchBestBuyForPS5 = async (browser) => {
  // go to Best Buy's site
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto('https://www.bestbuy.com');

  // enter search term "playstation 5 console"
  await page.type('#gh-search-input', 'playstation 5 console', {delay: 100});
  await sleep(3000);
  await page.press('.header-search-button', 'Enter');
  await sleep(1000);

  // wait for result products to render and put them in a results array
  await page.innerHTML('li.sku-item');
  const results = await page.$$('li.sku-item');

  // iterate through results array
  for (let i = 0; i < results.length; i++) {
    // get product's name
    const skuHeader = await results[i].$('h4.sku-header');
    const html = await skuHeader.innerHTML();

    // check whether product's name contains "playstation 5" and "console"
    if (html.toLowerCase().includes('playstation 5') && html.toLowerCase().includes('console')) {
      // get Sold Out/Add to Cart button
      const button = await results[i].$('button.add-to-cart-button');
      const buttonText = await button.innerText();

      // if the product is not sold out, alert the user
      if (buttonText !== "Sold Out") {
        console.log("Available!");
        // alert the user!!!
      }
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

好了,就是这样!这是一个简单的分步指南,教你如何编写一个程序,让你知道想要的商品何时补货。虽然这里展示的程序专门用于在百思买搜索 PlayStation 5 游戏机,但很容易修改用于其他用途。要搜索其他商品,只需替换搜索词即可。在其他零售商处搜索商品稍微复杂一些,因为程序需要访问该页面 DOM 中的特定元素,但编写程序的过程是相同的。

这些步骤还可以用于其他用途。例如,类似的流程可以用来在商品降价时提醒您。只需修改代码,使其在价格发生变化时发出提醒,而不是在“售罄”按钮变为“加入购物车”时发出提醒即可。

最后需要注意的是,为了确保脚本有效,必须持续且频繁地调用它。例如,如果脚本每周只运行一次,那就和您手动检查零售商网站没什么区别。为此,您可以使用任务调度程序(例如 cron)每隔几分钟调用一次该脚本。这里有一篇关于如何使用 cron 的文章。祝您购物愉快!

文章来源:https://dev.to/marisayou/how-to-get-a-playstation-5-when-it-s-always-out-of-stock-5d4i