Nothing is shared between workflows, so parallel browsers are simply parallel workflows that each build one. Browser type and automation engine are chosen per browser rather than globally, which is why one workflow can drive Chrome on OttoMagic while the next drives Edge on Puppeteer and a third drives FireFox on Selenium, all in the same process and all at the same time. Give each one a window rectangle if you intend to read them afterwards, because three maximised windows are one window you can see and two you cannot.
Rectangle SlotFor(int row, int rows)
{
Rectangle screen = Screen
int gap = 8;
int width = (screen
return new Rectangle(screen
screen
}
GPAL
Worth knowing before you set MaxAtOnce high. An OttoMagic browser learns where its GPALRestAPI is by listening on a fixed local port for the announcement, and the announcement is a bare port number with nothing in it to say which browser sent it. So one launch owns that port at a time, and the next waits for the whole of the one before it: start the browser, load the extension, hear the port back. Measured on a three browser run, that was around seventeen seconds each. The throttle and the stagger do not change this, and neither does raising MaxAtOnce. Three OttoMagic browsers take three times as long to reach the page as one, however many you allow in flight. Selenium and Puppeteer browsers have no such handshake and do start together, so a mixed run is only as serial as its OttoMagic rows.
A browser profile belongs to one browser at a time, and this is the single most common reason a parallel run fails. Note what the collision is actually about: it is the profile, not the browser type. Two Chrome browsers run side by side quite happily so long as they are on different profiles, and two on temporary profiles never collide at all. If a browser is already open on the profile you named, Chrome and Edge hand the new launch straight to the running instance and the new process exits, so there is no remote debugging port to connect to and no OttoMagic extension in the process you thought you started. FireFox fails differently and more visibly: geckodriver cannot take a profile that is still locked, so the browser starts and closes immediately and the driver reports that the process closed unexpectedly. Watch for this when a program keeps one profile per browser type, because then two workflows naming the same type are naming the same profile without saying so.
// each browser gets a profile of its own, one per type
static readonly Dictionary<BrowserType, string> profiles = new Dictionary<BrowserType, string>
{
[BrowserType
[BrowserType
[BrowserType
};
IBrowser browser = GPAL
browser
A supplied profile is what makes a run resemble a person rather than a fresh install, and it is worth having. It is also the thing that cannot be shared. Before a parallel run, close any browser already open on the profiles you are about to name, and check for orphans left behind by an earlier run that was killed rather than closed. When you do not need a real profile, name none: each browser then starts on a temporary profile of its own, which cannot collide with anything.
Ports are not something you have to allocate. Puppeteer browsers take a free debugging port found for them at launch, and GPALRestAPI picks its own port for OttoMagic, trying 3000 first and incrementing until it finds a free one, then announces it while starting. GPAL reads that announcement, so browser.RestApiBaseUrl tells you where a given browser ended up. What this means for parallel work is that two OttoMagic browsers in one process are on two different ports and neither had to be told, and that the port in a log line identifies which browser produced it.
GPAL
{
IBrowser one = GPAL
// where this browser ended up, not where it was told to go
GPAL
one
})
The default quarter second between starts is there because finding a free port and starting a process is what a browser does first. A dozen browsers doing that in the same instant are a dozen asking the machine the same question before any of them has answered it.
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();