Browser Automation

Left-Click and Download a File

Complete Program

Here's the whole workflow, start to finish. Each piece is broken down and explained below.

using System;

using System.Collections.Generic;

using System.Diagnostics;

using GenerallyPositive;

using GenerallyPositive.Browser;

using static GenerallyPositive.Enums;


GPAL

.WithExceptionHandler(ExceptionHandler)

.WithInformationHandler(InformationHandler)

.WithImageMatchingPercentage(80)

.WithSimulateMouseMovement(false)

.WithTypingDelay(100)

.WithPublishToConsole();


string url = "https://example.com/sample-downloads/";


Selector downloadLink = (Selector)GPAL.Selector

.WithXPath("//a[normalize-space()='Download sample pdf file']")

.WithCSS("#table-files > tbody > tr:nth-of-type(1) > td.file-link > a")

.WithOffsetX(115)

.WithOffsetY(18);


GPALFile downloadTarget = "c:\sdi\sample.pdf";


Selector closeByText = (Selector)GPAL.Selector

.WithText("Close").CallIfFound(CloseCallIfFound).WithSelectorName("Close by Close");

Selector closeByButton = (Selector)GPAL.Selector

.WithCSS("#dismiss-button").CallIfFound(CloseCallIfFound).WithSelectorName("Close by X");


IBrowser browser = GPAL.Browser

.WithBrowserType(BrowserType.Chrome)

.WithAutomationEngine(AutomationEngine.Selenium)

.WithLoadImages(true)

.WithBlockPopUps(true)

.WithOverwriteExistingFile(true)

.WithDriverLocation("C:\drivers")

.WithOpenPDFExternally(true)

.ToGPALObject();


browser.GoTo(url);


browser.WithPersistentSelector(closeByText).PersistentCallIfFound(CloseCallIfFound);

browser.WithPersistentSelector(closeByButton).PersistentCallIfFound(CloseCallIfFound);


browser

.WithSelector(downloadLink)

.LeftClickAndDownload(downloadTarget);


browser.Close(true);


CallIfStatus CloseCallIfFound(IBrowser browser, List<IGPALElement> foundElements, List<IGPALElement> matchedElements, Selector selector, bool matchedAll)

{

if (1 == matchedElements.Count && false == matchedElements[0].TagName.ToLower().Equals("script"))

matchedElements[0].Click();

return CallIfStatus.Handled;

}


void ExceptionHandler(object sender, EventArgs e)

{

Debug.WriteLine(((GPAL.GPALEventArgs)e).Message);

Debug.WriteLine(((GPAL.GPALEventArgs)e).ExceptionRaised?.Message);

}


void InformationHandler(object sender, EventArgs e)

{

Debug.WriteLine(((GPAL.GPALEventArgs)e).Message);

}

GPALFile as a Download Target

downloadTarget is a GPALFile, not a plain string. Assign it from a full path the same way you'd assign a string, but it carries file metadata GPAL can use - here it's the destination LeftClickAndDownload writes the PDF to once the click triggers the browser's download.

GPALFile downloadTarget = "c:\sdi\sample.pdf";


browser

.WithSelector(downloadLink)

.LeftClickAndDownload(downloadTarget);

NOTE

WithOverwriteExistingFile(true) lets a repeat run replace the file at the same path instead of saving it under a new name with a timestamp added. WithOpenPDFExternally(true) makes the browser download the PDF rather than render it inline. Downloads go straight to the download folder by default; WithPromptForDownload(true) turns the Save As prompt back on.

Persistent Selectors for an Ad That Comes Back

Some ads reappear after the page settles, so a one-time LeftClick isn't enough. WithPersistentSelector registers a selector GPAL looks for at the start of every action, and PersistentCallIfFound wires up the callback that closes it whenever it is found.

Selector closeByText = (Selector)GPAL.Selector

.WithText("Close").CallIfFound(CloseCallIfFound).WithSelectorName("Close by Close");

Selector closeByButton = (Selector)GPAL.Selector

.WithCSS("#dismiss-button").CallIfFound(CloseCallIfFound).WithSelectorName("Close by X");


browser.WithPersistentSelector(closeByText).PersistentCallIfFound(CloseCallIfFound);

browser.WithPersistentSelector(closeByButton).PersistentCallIfFound(CloseCallIfFound);

NOTE

It's common to register more than one persistent selector for the same nag - one that matches by visible text ("Close") and one that matches by a stable CSS id (#dismiss-button). Whichever one actually appears on a given page load triggers the callback.

The Close Callback

CloseCallIfFound is a CallIfDelegate - the same callback shape used by CallIfFound and CallIfNotFound elsewhere in GPAL. It receives the matched elements and clicks the one that matched, as long as it isn't a stray