Skip to content

Instantly share code, notes, and snippets.

@hlaueriksson
Last active November 12, 2023 21:19
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save hlaueriksson/4a4199f0802681b06f0f508a2916164d to your computer and use it in GitHub Desktop.
Save hlaueriksson/4a4199f0802681b06f0f508a2916164d to your computer and use it in GitHub Desktop.
PuppeteerSharp Documentation

Puppeteer Sharp

Puppeteer Sharp is a .NET port of Puppeteer.

✅ Chromium

Puppeteer

Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. Puppeteer runs headless by default, but can be configured to run full (non-headless) Chrome or Chromium.

Selectors

e.g. Page.QuerySelectorAsync, Page.QuerySelectorAllAsync

Script

e.g. Page.EvaluateExpressionAsync<T>, Page.EvaluateFunctionAsync<T>

Puppeteer Sharp Contributions

using System;
using System.Threading.Tasks;
using NUnit.Framework;
namespace PuppeteerSharp.Contrib.Sample
{
public class Examples
{
async Task<IBrowser> Browser()
{
await new BrowserFetcher().DownloadAsync();
var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true,
});
// SupportedBrowser
_ = new[] { SupportedBrowser.Chrome, SupportedBrowser.Firefox, SupportedBrowser.Chromium };
// Platform
_ = new[] { Platform.MacOS, Platform.MacOSArm64, Platform.Linux, Platform.Win32, Platform.Win64 };
return browser;
}
[Test]
public async Task close_Browser()
{
var browser = await Browser();
await browser.CloseAsync();
}
[Test]
public async Task using_Browser()
{
await using var browser = await Puppeteer.LaunchAsync(new());
// ...
}
async Task<IPage> Page()
{
var browser = await Browser();
var page = await browser.NewPageAsync();
return page;
}
[Test]
public async Task using_Page()
{
await using var browser = await Puppeteer.LaunchAsync(new());
await using var page = await browser.NewPageAsync();
// ...
}
[Test]
public async Task close_Page()
{
var page = await Page();
await page.CloseAsync();
}
[Test]
public async Task navigation()
{
var page = await Page();
await page.GoToAsync("https://github.com/hardkoded/puppeteer-sharp");
await page.GoBackAsync();
await page.GoForwardAsync();
await page.ReloadAsync();
}
[Test]
public async Task timeout()
{
var page = await Page();
var timeout = (int)TimeSpan.FromSeconds(30).TotalMilliseconds; // default value
page.DefaultNavigationTimeout = timeout;
page.DefaultTimeout = timeout;
await page.GoToAsync("https://github.com/hardkoded/puppeteer-sharp", timeout);
await page.GoToAsync("https://github.com/hardkoded/puppeteer-sharp", new NavigationOptions { Timeout = timeout });
}
[Test]
public async Task wait()
{
var page = await Page();
var timeout = (int)TimeSpan.FromSeconds(3).TotalMilliseconds;
var tasks = new Task[]
{
page.WaitForExpressionAsync("1 + 1 === 2", new() { Timeout = timeout }),
/*
page.WaitForFileChooserAsync(new() { Timeout = timeout }),
*/
page.WaitForFrameAsync("https://github.com/hardkoded/puppeteer-sharp", new() { Timeout = timeout }),
page.WaitForFunctionAsync("() => window.location.href === 'https://github.com/hardkoded/puppeteer-sharp'", new WaitForFunctionOptions { Timeout = timeout }),
page.WaitForNavigationAsync(new() { Timeout = timeout }),
/*
page.WaitForNetworkIdleAsync(new() { Timeout = timeout }),
*/
page.WaitForRequestAsync("https://github.com/hardkoded/puppeteer-sharp", new() { Timeout = timeout }),
page.WaitForResponseAsync("https://github.com/hardkoded/puppeteer-sharp", new() { Timeout = timeout }),
page.WaitForSelectorAsync("#readme", new() { Timeout = timeout }),
page.WaitForTimeoutAsync(timeout),
//page.WaitForXPathAsync(), // Obsolete
};
await page.GoToAsync("https://github.com/hardkoded/puppeteer-sharp");
await Task.WhenAll(tasks);
// Frame
var frame = page.MainFrame;
tasks = new Task[]
{
frame.WaitForExpressionAsync("1 + 1 === 2", new() { Timeout = timeout }),
frame.WaitForFunctionAsync("() => window.location.href === 'https://github.com/hardkoded/puppeteer-sharp'", new WaitForFunctionOptions { Timeout = timeout }),
frame.WaitForNavigationAsync(new() { Timeout = timeout }),
frame.WaitForSelectorAsync("#readme", new() { Timeout = timeout }),
frame.WaitForTimeoutAsync(timeout),
//frame.WaitForXPathAsync(), // Obsolete
};
await page.GoToAsync("https://github.com/hardkoded/puppeteer-sharp");
await Task.WhenAll(tasks);
// WaitUntilNavigation
_ = new[] { WaitUntilNavigation.Load, WaitUntilNavigation.DOMContentLoaded, WaitUntilNavigation.Networkidle0, WaitUntilNavigation.Networkidle2 };
// WaitForFunctionPollingOption
_ = new[] { WaitForFunctionPollingOption.Raf, WaitForFunctionPollingOption.Mutation };
}
[Test]
public async Task values_from_Page()
{
var page = await Page();
await page.GoToAsync("https://github.com/hardkoded/puppeteer-sharp");
_ = page.Url;
await page.GetContentAsync();
await page.GetCookiesAsync();
await page.GetTitleAsync();
await page.PdfDataAsync();
await page.ScreenshotDataAsync();
}
[Test]
public async Task values_from_ElementHandle()
{
var page = await Page();
await page.GoToAsync("https://github.com/hardkoded/puppeteer-sharp");
var element = await page.QuerySelectorAsync("main h1");
await element.GetPropertiesAsync();
await element.GetPropertyAsync("href");
await element.JsonValueAsync();
await element.ScreenshotDataAsync();
}
[Test]
public async Task form()
{
var page = await Page();
await page.GoToAsync("https://www.techlistic.com/p/selenium-practice-form.html");
// input / text
await page.TypeAsync("input[name='firstname']", "Puppeteer");
// input / radio
await page.ClickAsync("#exp-6");
// input / checkbox
await page.ClickAsync("#profession-1");
// select / option
await page.SelectAsync("#continents", "Europe");
// input / file
var file = await page.QuerySelectorAsync("#photo");
await file.UploadFileAsync(@"..\..\..\..\..\icon.png");
// button
await page.ClickAsync("#submit");
// other
await page.BringToFrontAsync();
await page.FocusAsync("#submit");
await page.HoverAsync("#main");
await page.TapAsync("#main");
// IElementHandle
var element = await page.QuerySelectorAsync("main");
await element.ClickAsync();
/*
await element.DragAndDropAsync();
*/
await element.FocusAsync();
await element.HoverAsync();
await element.PressAsync("Control");
/*
await element.SelectAsync();
*/
await element.TapAsync();
await element.TypeAsync("");
await element.UploadFileAsync();
}
[Test]
public async Task query()
{
var page = await Page();
await page.GoToAsync("https://github.com/hardkoded/puppeteer-sharp");
var element = await page.QuerySelectorAsync("div#readme");
var elements = await page.QuerySelectorAllAsync("div");
Assert.IsNotNull(element);
Assert.IsNotEmpty(elements);
var missingElement = await page.QuerySelectorAsync("div#missing");
var missingElements = await page.QuerySelectorAllAsync("div.missing");
Assert.IsNull(missingElement);
Assert.IsEmpty(missingElements);
var elementInElement = await element.QuerySelectorAsync("h1");
var elementsInElement = await element.QuerySelectorAllAsync("h1");
Assert.IsNotNull(elementInElement);
Assert.IsNotEmpty(elementsInElement);
// other
var handle = await page.QuerySelectorAllHandleAsync("div#readme");
await page.QueryObjectsAsync(handle);
await element.QuerySelectorAllHandleAsync("h1");
}
[Test]
public async Task evaluate()
{
var page = await Page();
await page.GoToAsync("https://github.com/hardkoded/puppeteer-sharp");
var outerHtml = await page.EvaluateExpressionAsync<string>($"document.querySelector({"'#repository-container-header strong a'"}).outerHTML");
var innerText = await page.EvaluateExpressionAsync<string>($"document.querySelector({"'#repository-container-header strong a'"}).innerText");
var url = await page.EvaluateExpressionAsync<string>($"document.querySelector({"'#repository-container-header strong a'"}).getAttribute('href')");
var hasContent = await page.EvaluateExpressionAsync<bool>($"document.querySelector({"'#repository-container-header strong a'"}).textContent.includes({"'puppeteer-sharp'"})");
Assert.AreEqual("<a data-pjax=\"#repo-content-pjax-container\" data-turbo-frame=\"repo-content-turbo-frame\" href=\"/hardkoded/puppeteer-sharp\">puppeteer-sharp</a>", outerHtml);
Assert.AreEqual("puppeteer-sharp", innerText);
Assert.AreEqual("/hardkoded/puppeteer-sharp", url);
Assert.IsTrue(hasContent);
await page.EvaluateExpressionHandleAsync("document.body");
await page.EvaluateExpressionOnNewDocumentAsync("document.body");
await page.EvaluateFunctionHandleAsync("() => 1 + 1 === 2");
await page.EvaluateFunctionOnNewDocumentAsync("() => 1 + 1 === 2");
var element = await page.QuerySelectorAsync("#repository-container-header strong a");
outerHtml = await page.EvaluateFunctionAsync<string>("e => e.outerHTML", element);
innerText = await page.EvaluateFunctionAsync<string>("e => e.innerText", element);
url = await page.EvaluateFunctionAsync<string>("e => e.getAttribute('href')", element);
hasContent = await page.EvaluateFunctionAsync<bool>("(e, value) => e.textContent.includes(value)", element, "puppeteer-sharp");
Assert.AreEqual("<a data-pjax=\"#repo-content-pjax-container\" data-turbo-frame=\"repo-content-turbo-frame\" href=\"/hardkoded/puppeteer-sharp\">puppeteer-sharp</a>", outerHtml);
Assert.AreEqual("puppeteer-sharp", innerText);
Assert.AreEqual("/hardkoded/puppeteer-sharp", url);
Assert.IsTrue(hasContent);
outerHtml = await element.EvaluateFunctionAsync<string>("e => e.outerHTML");
innerText = await element.EvaluateFunctionAsync<string>("e => e.innerText");
url = await element.EvaluateFunctionAsync<string>("e => e.getAttribute('href')");
hasContent = await element.EvaluateFunctionAsync<bool>("(e, value) => e.textContent.includes(value)", "puppeteer-sharp");
Assert.AreEqual("<a data-pjax=\"#repo-content-pjax-container\" data-turbo-frame=\"repo-content-turbo-frame\" href=\"/hardkoded/puppeteer-sharp\">puppeteer-sharp</a>", outerHtml);
Assert.AreEqual("puppeteer-sharp", innerText);
Assert.AreEqual("/hardkoded/puppeteer-sharp", url);
Assert.IsTrue(hasContent);
outerHtml = await (await element.GetPropertyAsync("outerHTML")).JsonValueAsync<string>();
innerText = await (await element.GetPropertyAsync("innerText")).JsonValueAsync<string>();
url = await (await element.GetPropertyAsync("href")).JsonValueAsync<string>();
hasContent = await (await element.GetPropertyAsync("textContent")).EvaluateFunctionAsync<bool>("(p, value) => p.includes(value)", "puppeteer-sharp");
Assert.AreEqual("<a data-pjax=\"#repo-content-pjax-container\" data-turbo-frame=\"repo-content-turbo-frame\" href=\"/hardkoded/puppeteer-sharp\">puppeteer-sharp</a>", outerHtml);
Assert.AreEqual("puppeteer-sharp", innerText);
Assert.AreEqual("https://github.com/hardkoded/puppeteer-sharp", url);
Assert.IsTrue(hasContent);
await element.EvaluateFunctionHandleAsync("() => 1 + 1 === 2");
}
[Test]
public async Task is_()
{
var page = await Page();
await page.GoToAsync("https://github.com/hardkoded/puppeteer-sharp");
Assert.IsFalse(page.IsClosed);
//page.IsDragInterceptionEnabled // Obsolete
var frame = page.MainFrame;
Assert.IsFalse(frame.IsOopFrame);
var element = page.QuerySelectorAsync("#include_email");
Assert.IsFalse(element.IsCompleted);
Assert.IsFalse(element.IsCompletedSuccessfully);
Assert.IsFalse(element.IsCanceled);
Assert.IsFalse(element.IsFaulted);
}
}
}
@stianl
Copy link

stianl commented Sep 22, 2020

Came across this from Google looking for an example of using WaitForExpressionAsync.
I also applied the timeout from your example:

var timeout = TimeSpan.FromSeconds(3).Milliseconds;

It seemed obvious to me that the value of timeout would be 3000 with this code, but apparently it is 0 - so in effect I believe this sets the timeout to infinite instead of 3 seconds.

@hlaueriksson
Copy link
Author

@stianl Thanks for spotting that bug! This gist is now updated.

The correct way to get the timeout from a TimeSpan is:

var timeout = (int) TimeSpan.FromSeconds(3).TotalMilliseconds;

It is not the first, nor the last time, I made that mistake.

@SimonG97
Copy link

SimonG97 commented Sep 27, 2022

I have a question for css style files which are included in the project i am not able to load them with Puppeteer Sharp. Those files are being loaded.

@hlaueriksson
Copy link
Author

@SimonG97 If you have a question about Puppeteer Sharp you can ask in the Q&A Discussions in the GitHub repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment