in

Puppeteer Sharp 和 XPath 的终极网页抓取指南

Puppeteer Sharp 和 XPath 的终极网页抓取指南

如果你想开始进行网页抓取,Puppeteer Sharp 是一个强大的工具。

使用 Puppeteer Sharp,你可以在 C# 这一强大且高效的编程语言中,轻松使用 Puppeteer 的无头浏览器命令。然而,要成功地从网页抓取数据,你需要克服一些挑战。

首先是告诉 Puppeteer 要抓取哪些数据。在选择器方面有很多选项,有时 CSS 可能会让人感到模糊。

其次,你需要避免被封锁。网站所有者会尝试阻止网页抓取器,如果你想持续收集数据,就需要注意这一点。

最后,你需要知道如何与目标页面互动、执行函数、发送表单数据并模拟真实用户行为。

今天,你将学习如何克服所有这些问题。我们将结合使用 XPath、住宅代理Puppeteer Sharp 和一些代码来实现这一切。

你将学习如何抓取数据,如何使用 XPath,如何截屏、打印 PDF、与表单互动、点击按钮等等。

掌握这些知识后,你可以构建一个多用途的网页抓取器。这与程序化网站特别契合。

让我们开始吧!


什么是 Puppeteer Sharp?

Puppeteer Sharp 是一个 C# 库,用于移植 NodeJS 库 Puppeteer。它允许你通过代码控制无头浏览器。这意味着你可以以编程方式执行任何真实用户会执行的操作。

你可以使用它进行软件测试、自动化和网页抓取。在我们的示例中,我们将重点放在网页抓取以及如何使用这些功能从网站提取数据。


如何开始使用 Puppeteer Sharp?

要使用 Puppeteer Sharp,你需要一个集成开发环境(IDE),如 Visual Studio。在其中创建一个新的 Web 应用程序项目:

Create a new web application project in Visual Studio

转到工具 > 管理 NuGet 包 > 搜索 Puppeteer,您会发现 PuppeteerSharp 是其中的一个热门选项

NuGet Packages - PuppeteerSharp

勾选小框,点击“添加包”,然后你就可以开始了。


我可以在 Puppeteer 中使用 XPath 吗?

你可以使用定位器来发送关于无头浏览器将与哪些元素交互的信息。这些定位器可以是 CSS 选择器、文本内容检查、布局组件检查(哪个元素在另一个元素的右侧),以及 XPath。

元素的 XPath 是该元素在 DOM 树上的地址。它可以是一个通用选择器,比如 CSS(针对多个元素),但它也可以轻松地明确识别一个特定的元素。

例如,一个常见的 CSS 选择器看起来像这样:

html body div#container article div.text h2

而XPath看起来像这样:

/html/body/div[4]/div/article/div[1]/div[2]/h2[1]

在这种情况下,XPath 告诉你需要遵循 DOM 树的哪些分支,以精确找到你想要的元素。


我如何找到按钮的 XPath?

你可以使用代码检查器找到按钮或任何元素的 XPath。右键单击目标元素并点击“检查”。然后,在检查器面板中,右键单击你想要的元素,点击复制 > XPath:

How to find the XPath of a button

我如何使用 XPath 选择按钮?

一旦你有了元素的 XPath,我们就可以选择该元素。使用以下代码片段:

using var browserFetcher = new BrowserFetcher();
   await browserFetcher.DownloadAsync(BrowserFetcher.DefaultChromiumRevision);
   var browser = await Puppeteer.LaunchAsync(new LaunchOptions
   {
        Headless = true
   });

var page = await browser.NewPageAsync();
await page.GoToAsync("https://en.wikipedia.org/wiki/Mario_Kart:_Super_Circuit");
var link = await page.XPathAsync("//html/body/div[1]/div/div[3]/main/div[2]/div[3]/div[1]/p[3]/a[1]");
var innerTextHandle = await link[0].GetPropertyAsync("innerText");
var innerText = await innerTextHandle.JsonValueAsync();

// Use the link text in any way you want to
Trace.WriteLine(innerText);

return View();

这段代码启动了 Puppeteer 库,创建了一个新的浏览器窗口和一个新的页面,并导航到一个 wiki 页面。然后,它使用 XPath 从内容中选择一个链接。请注意,XPathAsync 函数返回一个包含所有结果的数组,即使你只有一个项目。

因此,为了与该元素交互,你需要像我们对 link[0] 所做的那样访问数组元素

该选择器的 CSS 等效代码可能是:

var link = await page.QuerySelectorAsync("a[href='/wiki/List_of_best-selling_Game_Boy_Advance_video_games']");

可以用什么代替 XPath?

你可以使用 XPath 来选择你的元素。一些其他的替代方法没有那么严格,比如 CSS 选择器,它们可能会返回更多的元素。你可以使用 :nth-child() 或 nth-of-type CSS 伪类以及 > 分隔符来获得与 XPath 选择器相同的结果,指定你想在 DOM 树中跟随的确切元素。

例如,这个 XPath:

//html/body/div[1]/div/div[3]/main/div[2]/div[3]/div[1]/p[3]/a[1]
相当于下面的CSS选择器:
html > body > div:nth-of-type(1) > div > div:nth-of-type(3) > main > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(1) > p:nth-of-type(3) > a:nth-of-type(1)

怎么在 Puppeteer Sharp 中使用代理IP?

如果你想用 Puppeteer Sharp 抓取页面,你必须避免被检测到。尽管网页抓取是合法的,但很多网站会尝试阻止它,因为通过大规模分析数据可以为其他企业提供竞争优势。

这些网站通过查看连接请求中的一些指标来检测网页抓取工具。其中之一是连接头信息。一些抓取库不会自动设置正确的浏览器头信息,因此可以通过这种方法被检测到。但由于你使用的是 Puppeteer Sharp,你实际上是使用真实的浏览器连接到这些网站。因此,请求就像你手动访问该页面一样。

网站所有者关注的另一个点是请求的 IP 地址。它帮助他们识别那些加载大量页面、加载页面速度过快或每天同一时间加载页面的用户。

你可以通过使用像 IPRoyal 的住宅代理这样的服务来规避这一点。有了它,每个请求都会获得一个新的 IP 地址,使他们无法追踪你。从他们的角度来看,这些是来自世界各地的不同用户在加载页面。

一旦你注册了住宅代理服务,你就可以访问客户端区域。在那里,你可以看到你的连接详细信息,如下所示:

IPRoyal residential proxies dashboard

现在是时候在代码中使用它了。

正如你在前面的代码片段中看到的,你可以使用LaunchOptions向Puppeteer传递参数。你可以使用代理启动浏览器,代码如下:

var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
           Headless = true,
           Args = new[] { "--proxy-server=geo.iproyal.com:12321" }
 });

如果你不想将当前IP地址列入白名单,请使用以下代码片段验证你的代理连接:

await page.AuthenticateAsync(new Credentials() { Username = "username", Password = "password" });

这里有一个片段将所有内容整合在一起:

var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
    Headless = true,
    Args = new[] { "--proxy-server=geo.iproyal.com:12321" }
});

using (var page = await browser.NewPageAsync())
{
    await page.AuthenticateAsync(new Credentials() { Username = "username", Password = "password" });

    await page.GoToAsync("https://ipv4.icanhazip.com/");
    await page.ScreenshotAsync("proxy-screenshot.png");
}

浏览器页面准备好后,你可以做任何你想做的事情。别忘了调整超时限制,以确保有足够的时间处理你的代码和代理请求。


如何使用 Puppeteer Sharp 抓取任何内容?

现在让我们通过一些示例来探索你的网页抓取需求的几个不同用例。在这里,你会看到任务列表以及如何使用 Puppeteer Sharp 和 XPath 来实现它们。别忘了在代码的开头添加你的代理详细信息,你也可以随时使用 QuerySelectorAsync 替换 XPath 选择器为 CSS 选择器。

如何使用 Puppeteer Sharp 截图

你可以使用以下代码片段对页面进行截图:

var page = await browser.NewPageAsync();
await page.GoToAsync("https://en.wikipedia.org/wiki/Mario_Kart:_Super_Circuit");
await page.ScreenshotAsync("screenshot.png");

你可以更改浏览器大小以更改图像输出。另外,你还可以查询特定元素并截图:

var page = await browser.NewPageAsync();

        await page.GoToAsync("https://en.wikipedia.org/wiki/Mario_Kart:_Super_Circuit");
        var sidebar = await page.XPathAsync("//html/body/div[1]/div/div[3]/main/div[2]/div[3]/div[1]/table");

        await sidebar[0].ScreenshotAsync("sidebar.png");

如何使用 Puppeteer Sharp 将 HTML 转换为 PDF

你可以将页面保存为 PDF 文件。要使用 Puppeteer Sharp 将 HTML 页面转换为 PDF,可以使用以下代码:

var page = await browser.NewPageAsync();
await page.GoToAsync("https://en.wikipedia.org/wiki/Mario_Kart:_Super_Circuit");
await page.PdfAsync("page.pdf");

就像截图一样,你可以更改浏览器的尺寸,这也会改变 PDF 的尺寸。

如何定义 Puppeteer Sharp 的超时

你可以使用 NavigationOptions 类来控制 Puppeteer Sharp 的超时。因此,你可以使用类似这样的代码,而不是简单的 GoToAsync 命令:

var page = await browser.NewPageAsync();
await page.GoToAsync("https://en.wikipedia.org/wiki/Mario_Kart:_Super_Circuit", new NavigationOptions { Timeout = 60000 });

在这里设置你想要的超时值,单位是毫秒。默认值是30秒,因此设置为30000。

如何使用 Puppeteer Sharp 填写并提交表单

你可以通过多种方法与表单交互。可以输入文本并与页面交互,这是相当简单的方法。在这种情况下,主要的缺点是你需要使用 CSS 选择器。但随后,你可以使用 XPath 选择器点击“提交”按钮。

如何设置输入值

你可以使用页面变量上的 TypeAsync 方法为输入框设置值。在这种情况下,你需要使用 CSS 选择器,而不是 XPath。以下是如何在 Wikipedia 页面中的搜索框中输入内容(等同于 XPath /html/body/div[1]/div/header/div[2]/div/div/div/form/div/div/div[1]/input ):

await page.GoToAsync("https://en.wikipedia.org/wiki/Mario_Kart:_Super_Circuit");
page.TypeAsync("html > body > div:nth-of-type(1) > div > header > div:nth-of-type(2) > div > div > div > form > div > div > div:nth-of-type(1) > input",”value to type”).Wait();

然后,你可以通过按回车键或使用一些 C# 代码点击搜索按钮来执行搜索操作。

如何使用 Puppeteer Sharp 执行 JS 函数

你可以使用 PuppeteerSharp 在目标页面上执行 JS 代码。这类似于打开开发者工具并测试 JS 代码。

以下是一个示例:

using (var page = await browser.NewPageAsync())
{
    var four = await page.EvaluateExpressionAsync<int>("()=> 2 + 2");
    var myObject = await page.EvaluateFunctionAsync<dynamic>("(value) => ({my: value})", 4);
    Console.WriteLine(myObject.my);
}

在这段代码中,我们首先创建一个变量来存储 JS 函数的结果。第二个示例基于传递的变量(4)执行一个 JS 函数,然后我们在控制台中记录这个变量。

你可以使用类似的代码片段直接从页面中提取数据,例如价格、库存、图表等。

使用 EvaluateExpressionAsync,你可以运行任何你想要的 JS 代码。此外,你可以预处理数据,添加和删除元素,使你在 C# 代码中处理抓取的页面或将其保存到数据库中变得更容易。


Puppeteer Sharp VS Playwright

如果你在考虑选择哪个库,答案很简单。两者都是很好的选择,所以你可以选择你最熟悉的选项。

不过,Playwright 更新更频繁,更具未来适应性。但 Puppeteer Sharp 也能很好地工作,是快速项目和原型设计的一个不错选择。


常见问题解答

browser.newpage 不是一个函数

确保你有前提条件,并且在整个代码中使用了异步函数。否则,你将无法检索到正确的浏览器状态。

执行上下文被销毁,最有可能是由于导航

当你导航到其他页面时,你可能会失去对某些变量中数据的访问,因为它们已经不存在了。因此,你可能会告诉 Puppeteer Sharp 处理在该上下文中不存在的元素。

ElementHandle[] 没有 ‘GetPropertyAsync' 的定义

在这种情况下,完整的错误消息可能是这样的:

ElementHandle[] does not contain a definition for 'GetPropertyAsync' and no accessible extension method 'GetPropertyAsync' accepting a first argument of type 'IElementHandle[]' could be found (are you missing a using directive or an assembly reference?)

如果尝试从使用XPath加载的元素访问类而不访问数组项,就会发生这种情况。当你运行page.XPathAsync(” XPath “)时,c#总是返回一个包含元素的数组,即使它只有一个元素。因此,例如,你只能使用variableame[0]获取该元素的属性。


结    论

今天我们探讨了如何使用 PuppeteerSharp 和 XPath 来执行许多操作。你可以在你的程序化 SEO 网站或一般的抓取任务中使用这些操作。希望你喜欢这篇文章,下次再见!

Written by 河小马

河小马是一位杰出的数字营销行业领袖,广告中国论坛的重要成员,其专业技能涵盖了PPC广告、域名停放、网站开发、联盟营销以及跨境电商咨询等多个领域。作为一位资深程序开发者,他不仅具备强大的技术能力,而且在出海网络营销方面拥有超过13年的经验。