Here's a trimmed-down version of the workflow, start to finish. Each piece is broken down and explained below.
using GenerallyPositive;
using GenerallyPositive
using static GenerallyPositive
GPAL
List<string> urls = new List<string>
{
"https://bot-detection
"https://fingerprint
"https://example
};
IBrowser browser = GPAL
foreach (string url in urls)
{
browser
browser
if (true == UrlHelper
{
browser
browser
}
for (int page = 0; page < 10; page++)
{
string fileName = $@"pixpage_{page}
GPALFile screenCapFile = GPAL
GPAL
_ = browser
if (0 < page && true == browser
break;
}
}
browser
public static CallIfStatus GenericCallIfNotFound(IBrowser browser, List<GPALElement> foundElements, List<GPALElement> matchedElements, Selector selector, bool matchedAll)
{
string message = $"Unable to locate Selector [{selector
GPAL
return CallIfStatus
}
GPAL.CallIfNotFound registers a workflow-wide handler that fires whenever a selector fails to match, on top of any per-selector CallIfNotFound. Here it logs an ERROR event with the selector's name and first path, then returns CallIfStatus.Handled so the workflow continues instead of throwing.
GPAL
public static CallIfStatus GenericCallIfNotFound(IBrowser browser, List<GPALElement> foundElements, List<GPALElement> matchedElements, Selector selector, bool matchedAll)
{
string message = $"Unable to locate Selector [{selector
GPAL
return CallIfStatus
}
The real test program keeps a List
WithUseStealth combines several flags - dark mode, a Google referrer header, a patched chromedriver binary, and CDP leak protection - to make the browser look less like an automated session. WithProfileDataDirectory points at a real Chrome profile directory, so cookies, history, and fingerprint-relevant state persist between runs instead of starting from a blank slate every time.
IBrowser browser = GPAL
StealthType is a flags enum - combine as many as the target site needs with bitwise OR. See Browser Profiles: Signed-In vs Temporary for more on persistent profile directories.
Different anti-bot pages need different one-off handling: some need extra wait time before a fingerprint check finishes, others need a cookie banner dismissed before screenshots make sense. UrlHelper.AreEquivalent compares the current URL against a known target regardless of trailing slashes or minor formatting differences, so each branch only runs for the site it applies to.
if (true == UrlHelper
{
browser
browser
}
The inner loop takes up to 10 screenshots, scrolling down with browser.PageDown between each. GPAL.CaptureScreen(browser).SaveToFile writes each frame to a GPALFile-backed PNG, and browser.IsEndOfPage() stops the loop early once scrolling has reached the bottom.
for (int page = 0; page < 10; page++)
{
string fileName = $@"pixpage_{page}
GPALFile screenCapFile = GPAL
GPAL
_ = browser
if (0 < page && true == browser
break;
}
Programmatic scrolling is itself a signal some anti-bot systems watch for. If a site's detection score changes after scrolling, that's the page reacting to PageDown, not a GPAL bug.
The real test program wraps all of this in nested foreach loops over BrowserType and AutomationEngine, using continue inside a switch to skip combinations that aren't relevant to the current test run (for example, skipping every engine except OttoMagic). This is a common pattern for regression-testing a workflow across every supported configuration without duplicating the workflow code.
Array browserTypes = Enum
foreach (BrowserType bt in browserTypes)
{
switch (bt)
{
case BrowserType
default: continue;
}
Array automationEngines = Enum
foreach (AutomationEngine ae in automationEngines)
{
switch (ae)
{
case AutomationEngine
default: continue;
}
// build browser and run the workflow body here
}
}
A switch with continue for every value you want to skip keeps the loop body focused on the combinations you actually care about, and makes it obvious at a glance which engines and browser types are in scope for a given test run. See Automation Engines and Conditional Logic.
Showing off some plain text in these paragraphs eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Here you can find different accents and emphasis sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
This is a link and how it could look like bestlinkinthebeautifulworld. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Here's just some classic bold text adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam notBoldSecondbestlinkinthebeautifulworld illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at adipisicing elit libero vel voluptas? Expedita, adipisicing facere dolores voluptatem ad ab rem assumenda soluta!
Other cuple of colors in case we want to emphasize several ways adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at voluptatem libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Repudiandae quas consequuntur illo numquam assumenda autem exercitationem distinctio perspiciatis in natus. Eius dicta similique ipsam ipsa minima, nemo quae enim tempore.
GPAL
.CallIfNotFound(GenericCallIfNotFound)
.WithPublishToConsole();
//System.Drawing.Rectangle windowSize = new System.Drawing.Rectangle(10, 10, 1500, 1024);
// NOTE: we have to set browser = before we execute any steps
// this is due to the 'GenericCallIfNotFound' which might throw an exception, and BankScraper will not have the browser set when it calls scraper.Close()
// until the complete fluent line gets executed (meaning every step, meaning browser is not set until everything else succeeds)
browser = GPAL.Browser
.WithBrowserType(Enums.BrowserType.Chrome)
.WithProfileDataDirectory(ChromeProfileLocation)
.WithUseAutomationEngine(AutomationEngine.Selenium)
.WithWindowSize(new System.Drawing.Rectangle(0,0,1920,1080))
.ToGPALObject();