The shape of the workflow: configure GPAL and a persistent selector for a cookie popup, load a list page, pull rating info and titles into grids, then for each book that clears a rating bar, open a second site in a new tab, search for it, and scrape the result.
using System;
using System
using System
using GenerallyPositive;
using GenerallyPositive
using static GenerallyPositive
GPAL
IGPALGrid<string> outputGrid = GPAL
Selector cookiesPopup = GPAL
IBrowser browser = GPAL
Selector ratingsSelector = GPAL
Selector titleSelector = GPAL
IGPALGrid<string> resultsGrid = GPAL
browser
string bookTitle = resultsGrid[0][1];
Selector searchBar = GPAL
Selector searchButton = GPAL
Selector searchResults = GPAL
browser
IGPALGrid<string> priceGrid = GPAL
browser
browser
browser
CallIfStatus CloseCookiesPopup(IBrowser browser, List<IGPALElement> foundElements, List<IGPALElement> matchedElements, Selector selector, bool matchedAll)
{
foreach (IGPALElement element in foundElements)
element
selector
browser
return CallIfStatus
}
CallIfStatus SelectFirstResult(IBrowser browser, List<IGPALElement> foundElements, List<IGPALElement> matchedElements, Selector selector, bool matchedAll)
{
foundElements[0]
Selector priceSelector = GPAL
browser
if (0 < priceGrid?
outputGrid
return CallIfStatus
}
void ExceptionEventHandler(object sender, EventArgs e)
{
Debug
Debug
}
WithPersistentSelector attaches a selector to the browser itself, not to a single unit of work. GPAL checks for it at the start of every action and runs its CallIfFound handler whenever it is on the page - perfect for cookie banners or login popups that can pop up at any time. Once handled, the callback removes the selector and unregisters itself so it does not keep firing.
Selector cookiesPopup = GPAL
IBrowser browser = GPAL
CallIfStatus CloseCookiesPopup(IBrowser browser, List<IGPALElement> foundElements, List<IGPALElement> matchedElements, Selector selector, bool matchedAll)
{
foreach (IGPALElement element in foundElements)
element
selector
browser
return CallIfStatus
}
Calling Remove() on the selector and RemoveCallIfHandlerEverywhere() on the browser stops GPAL from re-checking for a popup that has already been dismissed. Skipping this means the same handler fires repeatedly for the rest of the run.
WithAllThatMatch() with no argument means 'every match, no limit'; a number caps it. GetGrid pulls every matched element from every WithSelector call into one in-memory grid - one column per selector, one row per matched element - so you can reason about results in plain C# afterward.
IGPALGrid<string> resultsGrid = GPAL
browser
string bookTitle = resultsGrid[0][1];
NewTab opens a fresh tab and navigates it, without losing the original tab's state. From there the workflow is the same shape as any other: fill in a search box, click search, and wait for results.
browser
If you open extra tabs with NewTab, call CloseTab() to return to the original tab before the final Close(true). Closing the driver while a non-original tab is active can leave the workflow in an inconsistent state on the next run.
CallIfFound runs a callback only when WithSelector actually matched something - here, SelectFirstResult clicks the first product tile. Inside that callback, a fresh chain reads the price from the product page the click opened and adds it to outputGrid.
IGPALGrid<string> priceGrid = GPAL
browser
CallIfStatus SelectFirstResult(IBrowser browser, List<IGPALElement> foundElements, List<IGPALElement> matchedElements, Selector selector, bool matchedAll)
{
foundElements[0]
Selector priceSelector = GPAL
browser
if (0 < priceGrid?
outputGrid
return CallIfStatus
}
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();