返回博客
指南
Raluca Penciuc2023年3月3日阅读时间:8分钟

如何抓取Yelp.com数据(2023年更新版)——分步指南

如何抓取Yelp.com数据(2023年更新版)——分步指南

环境搭建

在开始之前,请确保您已备齐所需工具。

首先,请从官方网站下载并安装 Node.js,务必选择长期支持(LTS)版本。此操作将自动安装 Node 包管理器(NPM),我们后续将通过它安装其他依赖项。

在本教程中,我们将使用 Visual Studio Code 作为集成开发环境(IDE),但您也可以选择使用任何其他 IDE。为您的项目创建一个新文件夹,打开终端,并运行以下命令来创建一个新的 Node.js 项目:

npm init -y

这将在项目目录中生成一个 package.json 文件,用于存储项目及其依赖项的相关信息。

接下来,我们需要安装 TypeScript 以及 Node.js 的类型定义。TypeScript 提供了可选的静态类型检查功能,有助于防止代码中的错误。为此,请在终端中运行:

npm install typescript @types/node --save-dev

您可以通过运行以下命令验证安装是否成功:

npx tsc --version

TypeScript 使用名为 tsconfig.json 的配置文件来存储编译器选项及其他设置。要在项目中创建此文件,请运行以下命令:

npx tsc -init

请确保将“outDir”的值设置dist”。这样,我们将把 TypeScript 文件与编译后的文件分开。您可以在 TypeScript 官方文档中找到有关此文件及其属性的更多信息。

现在,在项目中创建一个“src”目录,并新建一个“index.ts”文件。我们将在此保存爬取代码。要执行 TypeScript 代码,必须先进行编译,因此为了确保不会遗漏这一步,我们可以使用自定义命令。

请打开“package.json”文件,并将“scripts”部分修改如下:

"scripts": {

    "test": "npx tsc && node dist/index.js"

}

这样,当你需要运行脚本时,只需在终端中输入“npm run test”即可。

最后,为了从网站抓取数据,我们将使用 Puppeteer——这是一个用于 Node.js 的无头浏览器库,允许您通过编程方式控制网页浏览器并与网站进行交互。要安装它,请在终端中运行以下命令:

npm install puppeteer

强烈建议在确保数据完整性时使用该工具,因为如今许多网站都包含动态生成的内容。如果您感兴趣,可以在继续之前查阅 Puppeteer 文档,全面了解其功能。

数据来源

现在环境已配置完毕,我们可以开始探讨数据提取了。本文中,我选择抓取都柏林一家爱尔兰餐厅的页面:https://www.yelp.ie/biz/the-boxty-house-dublin?osq=Restaurants。

我们将提取以下数据:

  • 餐厅名称;
  • 餐厅评分;
  • 餐厅评论数量;
  • 商家网站;
  • 商家电话号码;
  • 餐厅的实体地址。

您可以在下方的截图中看到所有这些信息已被标出:

Yelp business page with highlighted areas for the restaurant name, rating, and contact information

通过在这些元素上打开开发者工具,您将能够看到我们将用于定位 HTML 元素的 CSS 选择器。如果您对 CSS 选择器的运作机制还不太熟悉,欢迎查阅这篇入门指南

提取数据

在编写脚本之前,让我们先验证一下 Puppeteer 的安装是否成功:

import puppeteer from 'puppeteer';

async function scrapeYelpData(yelp_url: string): Promise<void> {

    // Launch Puppeteer

    const browser = await puppeteer.launch({

        headless: false,

    	  args: ['--start-maximized'],

    	  defaultViewport: null

    })

    // Create a new page

    const page = await browser.newPage()

    // Navigate to the target URL

    await page.goto(yelp_url)

    // Close the browser

    await browser.close()

}

scrapeYelpData("https://www.yelp.ie/biz/the-boxty-house-dublin?osq=Restaurants")

这里我们打开一个浏览器窗口,新建一个页面,导航至目标 URL,然后关闭浏览器。为了简化操作并便于可视化调试,我以非无头模式全屏打开了浏览器窗口。

现在,让我们看看网站的结构:

Yelp business page with browser devtools highlighting the HTML for the listing title and star rating

Yelp 的页面结构似乎有些复杂,因为类名是随机生成的,且极少有元素具有唯一的属性值。

但无需担心,我们可以灵活地设计解决方案。首先,要获取餐厅名称,我们定位页面上唯一的“h1”元素。

// Extract restaurant name

const restaurant_name = await page.evaluate(() => {

    const name = document.querySelector('h1')

    return name ? name.textContent : ''

})

console.log(restaurant_name)

接下来,要获取餐厅评分,你会发现除了星星图标外,明确的数值其实存在于“aria-label”属性中。因此,我们定位那个“aria-label”属性以“star rating”字符串结尾的“div”元素。

// Extract restaurant rating

const restaurant_rating = await page.evaluate(() => {

    const rating = document.querySelector('div[aria-label$="star rating"]')

    return rating ? rating.getAttribute('aria-label') : ''

})

console.log(restaurant_rating)

最后(针对这一特定 HTML 部分),我们可以发现只需定位高亮显示的锚点元素,就能轻松获取评论数量。

// Extract restaurant reviews

const restaurant_reviews = await page.evaluate(() => {

    const reviews = document.querySelector('a[href="#reviews"]')

    return reviews ? reviews.textContent : ''

})

console.log(restaurant_reviews)

轻而易举。现在让我们看看商家信息小部件:

Yelp contact card with highlighted website URL, phone number, and directions, alongside devtools HTML view

遗憾的是,在此情境下我们无法依赖 CSS 选择器。所幸,我们可以利用另一种方法定位 HTML 元素:XPath。如果您对 CSS 选择器的运作机制还不太熟悉,欢迎查阅这篇入门指南

要提取餐厅的网站地址,我们采用以下逻辑:

定位文本内容为“Business website”的“p”元素;

定位其紧邻的兄弟元素

定位锚点元素及其“href”属性。

// Extract restaurant website

const restaurant_website_element = await page.$x("//p[contains(text(), 'Business website')]/following-sibling::p/a/@href")

const restaurant_website = await page.evaluate(

    element => element.nodeValue,

    restaurant_website_element[0]

)

console.log(restaurant_website)

现在,对于电话号码和地址,我们可以遵循完全相同的逻辑,但有两个例外:

  • 对于电话号码,我们停止查找紧邻的兄弟元素,并提取其 textContent 属性;
  • 对于地址,我们需要定位父元素的下一级同级元素。
// Extract restaurant phone number

const restaurant_phone_element = await page.$x("//p[contains(text(), 'Phone number')]/following-sibling::p")

const restaurant_phone = await page.evaluate(

    element => element.textContent,

    restaurant_phone_element[0]

)

console.log(restaurant_phone)

// Extract restaurant address

const restaurant_address_element = await page.$x("//a[contains(text(), 'Get Directions')]/parent::p/following-sibling::p")

const restaurant_address = await page.evaluate(

    element => element.textContent,

    restaurant_address_element[0]

)

console.log(restaurant_address)

最终结果应如下所示:

The Boxty House

4.5 star rating

948 reviews

/biz_redir?url=http%3A%2F%2Fwww.boxtyhouse.ie%2F&cachebuster=1673542348&website_link_type=website&src_bizid=EoMjdtjMgm3sTv7dwmfHsg&s=16fbda8bbdc467c9f3896a2dcab12f2387c27793c70f0b739f349828e3eeecc3

(01) 677 2762

20-21 Temple Bar Dublin 2

绕过机器人检测

虽然初看之下抓取 Yelp 似乎很简单,但随着项目规模的扩大,这一过程会变得更加复杂且具有挑战性。该网站采用了多种技术来检测和阻止自动化流量,因此当你的抓取工具规模扩大后,就会开始遭到封锁。

Yelp 会收集多种浏览器数据来生成并关联您的唯一指纹。其中包括:

  • Navigator 对象的属性(deviceMemory、hardwareConcurrency、platform、userAgent、webdriver 等)
  • 时序与性能检测
  • 服务 worker
  • 屏幕尺寸检测
  • 以及更多

要克服这些挑战并继续进行大规模抓取,一种方法是使用抓取 API。此类服务提供了一种简单可靠的方式,可从 yelp.com 等网站获取数据,而无需自行构建和维护抓取工具。

WebScrapingAPI 便是此类产品的典型代表。其代理轮换机制能彻底规避验证码,而丰富的知识库则支持对浏览器数据进行随机化处理,使其行为与真实用户无异。

配置过程快速简便。您只需注册一个账户,即可获得 API 密钥。该密钥可在控制面板中获取,并用于验证您发送的请求。

Dashboard quickstart guide showing three steps: API access key, API Playground, and integration into your application

既然您已经配置好了 Node.js 环境,我们就可以使用相应的 SDK。运行以下命令将其添加到项目依赖项中:

npm install webscrapingapi

现在只需发送一个 GET 请求,即可获取网站的 HTML 文档。请注意,这并非访问 API 的唯一方式。

import webScrapingApiClient from 'webscrapingapi';

const client = new webScrapingApiClient("YOUR_API_KEY");

async function exampleUsage() {

    const api_params = {

        'render_js': 1,

    	  'proxy_type': 'residential',

    }

    const URL = "https://www.yelp.ie/biz/the-boxty-house-dublin?osq=Restaurants"

    const response = await client.get(URL, api_params)

    if (response.success) {

        console.log(response.response.data)

    } else {

        console.log(response.error.response.data)

    }

}

exampleUsage();

通过启用“render_js”参数,我们可以使用无头浏览器发送请求,就像您之前在本教程中做的那样。

获取 HTML 文档后,您可以使用其他库(如 Cheerio)来提取所需数据。没听说过它?请查看这篇指南,助您快速入门!

结论

本文为您提供了使用 TypeScript 和 Puppeteer 抓取 Yelp 数据的全面指南。我们详细介绍了环境搭建、定位和提取数据的过程,并阐述了为何使用专业的抓取工具比自行开发更优。

从 Yelp 抓取的数据可用于多种用途,例如识别市场趋势、分析客户情绪、监控竞争对手、创建精准营销活动等。

总体而言,对 Yelp.com 进行网页抓取对于希望在本地市场获得竞争优势的任何人来说都是一项宝贵的资产,而本指南为此提供了绝佳的起点。

关于作者
Raluca Penciuc, 全栈开发工程师 @ WebScrapingAPI
Raluca Penciuc全栈开发工程师

Raluca Penciuc 是 WebScrapingAPI 的全栈开发工程师,主要负责开发爬虫、优化规避机制,并探索可靠的方法以降低在目标网站上的被检测概率。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网络数据。