如果你想开始进行网页抓取,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 应用程序项目:
转到工具 > 管理 NuGet 包 > 搜索 Puppeteer,您会发现 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:
我如何使用 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 地址,使他们无法追踪你。从他们的角度来看,这些是来自世界各地的不同用户在加载页面。
一旦你注册了住宅代理服务,你就可以访问客户端区域。在那里,你可以看到你的连接详细信息,如下所示:
现在是时候在代码中使用它了。
正如你在前面的代码片段中看到的,你可以使用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 网站或一般的抓取任务中使用这些操作。希望你喜欢这篇文章,下次再见!