Cookie banners, newsletter popups, and other nags can appear at any point during a workflow, not just on the first page. WithPersistentSelector and PersistentCallIfFound register a selector and a callback that GPAL checks for on every navigation, so your main workflow can stay focused on the task at hand.
This is a trimmed version of the actual test program. It defines a cookie-banner selector, registers it as a persistent handler before navigating, then runs a normal workflow that downloads a file. The persistent handler fires automatically whenever the banner shows up, without any extra code in the main chain.
using System;
using System.Collections.Generic;
using GenerallyPositive;
using GenerallyPositive.Browser;
using static GenerallyPositive.Enums;
GPAL.WithTypingDelay(50)
.WithAutoUpdateWebDriver()
.WithPublishToConsole();
GPALFile htmlFile = @"c: emp est.html";
Selector allCookies = (Selector)GPAL.Selector
.WithSelectorName("Accept Cookies")
.WithXPath("//button")
.MatchText("Accept all cookies");
Selector downloadLink = (Selector)GPAL.Selector
.WithSelectorName("Download Link")
.WithXPath("//a[@id='download']");
IBrowser browser = GPAL.Browser
.WithBrowserType(BrowserType.Chrome)
.WithPersistentSelector(allCookies)
.PersistentCallIfFound(FoundAllCookies)
.WithDriverLocation(@"c:drivers")
.GoTo("https://example.com/downloads")
.ToGPALObject();
browser
.WithSelector(downloadLink)
.CallIfFound(CallIfFound)
.RightClickAndDownload(htmlFile)
.NewTab("https://example.com/another-page")
.WaitFor(2_000)
.Close(true);
public static CallIfStatus FoundAllCookies(IBrowser browser, List<GPALElement> foundElements, List<GPALElement> matchedElements, Selector selector, bool matchedAll)
{
CallIfStatus retVal = CallIfStatus.NotHandled;
foreach (GPALElement webElement in foundElements)
{
if (webElement.Text.Contains("cookies"))
{
webElement.Click();
retVal = CallIfStatus.Handled;
}
}
return retVal;
}
public static CallIfStatus CallIfFound(IBrowser browser, List<GPALElement> foundElements, List<GPALElement> matchedElements, Selector selector, bool matchedAll)
{
return CallIfStatus.Handled;
}
A persistent selector is just a regular Selector - give it a name and a way to find the element. Here it's an XPath for any button, narrowed down with MatchText so it only matches the cookie-acceptance button specifically, not every button on the page.
Selector allCookies = (Selector)GPAL.Selector
.WithSelectorName("Accept Cookies")
.WithXPath("//button")
.MatchText("Accept all cookies");
WithPersistentSelector adds the selector to the browser's standing watch list. PersistentCallIfFound attaches the callback that runs whenever that selector matches something - on the first page load, after clicking a link, after opening a new tab, anywhere. Both calls happen on the same fluent chain used to configure and launch the browser.
IBrowser browser = GPAL.Browser
.WithBrowserType(BrowserType.Chrome)
.WithPersistentSelector(allCookies)
.PersistentCallIfFound(FoundAllCookies)
.WithDriverLocation(@"c:drivers")
.GoTo("https://example.com/downloads")
.ToGPALObject();
You don't need to re-check for the cookie banner after every click or tab change in your main workflow. GPAL evaluates every persistent selector on each navigation event and calls your handler automatically.
FoundAllCookies looks at the matched elements, and if any of them contain the word "cookies" it clicks the element and returns CallIfStatus.Handled. Returning NotHandled tells GPAL the popup wasn't actually dealt with, which is useful if your handler sometimes needs to defer to other logic.
public static CallIfStatus FoundAllCookies(IBrowser browser, List<GPALElement> foundElements, List<GPALElement> matchedElements, Selector selector, bool matchedAll)
{
CallIfStatus retVal = CallIfStatus.NotHandled;
foreach (GPALElement webElement in foundElements)
{
if (webElement.Text.Contains("cookies"))
{
webElement.Click();
retVal = CallIfStatus.Handled;
}
}
return retVal;
}
With the persistent handler in place, the rest of the workflow just does its job - find the download link, react to it, download a file, open another tab. If the cookie banner reappears on the new tab, the persistent handler fires again without any changes here.
browser
.WithSelector(downloadLink)
.CallIfFound(CallIfFound)
.RightClickAndDownload(htmlFile)
.NewTab("https://example.com/another-page")
.WaitFor(2_000)
.Close(true);
Passing true kills the running web driver process. Use true when the workflow is completely done; use false if another workflow in the same run still needs that driver.
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();