Using a Local Browser

Create an Extraction

In this guide, you will extract content from a webpage. Extracting content is particularly common for web scraping and testing. This tutorial will be using a local browser; if you are looking to accomplish this using a Bytebot-managed remote browser, click here.

Extract Schema Functions

Extract schema functions comprise a small set of helper functions that detail the structure and type of extracted data. Bytebot features four extract schema functions. These are split into two primary functions:

  • Attribute(prompt: string): This defines a natural language prompt that specifies an element’s attribute (e.g., src or value).
  • Text(prompt: string): This defines a natural language prompt that specifies an element’s innerText.

And two structure-based functions, specific to tables:

  • Table(columns: Column[]): This defines a table of contents, itemized across columns. Table requires an array of Column function calls.
  • Column(name: string, value: Attribute | Text): This defines a named table column, where the value is an Attribute or Text function call.

Extract schema functions do not extract data. Instead, they define the extracted data’s structure to Bytebot’s extract function.

Bytebot’s Extract Function

To extract data, you need to use the .extract(schema: ExtractSchemaFunction, page: Page, options: Object) function. Like act, the function is async and accepts the following options:

AttributeRequiredDescription
useCacheOptionalA Boolean that dictates whether Bytebot should cache previous BrowserActions generated by act on the same prompt and Page
parametersOptionalAn Object where each string key is removed from the prompt, anonymized, and swapped in after the Bytebot run. This can be used to protect sensitive data.

Extracting an element’s attribute

To extract an element’s attribute, we will also need to import Attribute from Bytebot’s SDK:

1import { Attribute, BytebotClient } from '@bytebot/sdk';

Attribute is another extract schema function and takes a natural language prompt as a string. This prompt does not need actions words like “Get” or “Extract”. Instead, the prompt should strictly define what attribute is to be extracted from where:

1const prompt = "The link from the 'Sign in' button";

Next, call extract , using Attribute to wrap the prompt:

1import { Attribute, BytebotClient } from '@bytebot/sdk';
2import puppeteer from "puppeteer";
3import "dotenv/config";
4
5async function run() {
6 const browser = await puppeteer.launch();
7 const page = await browser.newPage();
8 await page.goto("https://developer.chrome.com/", {
9 waitUntil: "networkidle0",
10 });
11
12 const bytebot = new BytebotClient({
13 apiKey: process.env.BYTEBOT_API_KEY,
14 });
15
16 bytebot.puppeteer.startSession();
17
18 const prompt = "The link from the 'Sign in' button";
19 const extractActions = await bytebot.puppeteer.extract({
20 schema: Attribute(prompt),
21 page: page,
22 });
23 console.log("Actions", extractActions);
24
25 //execute the actions
26 await bytebot.puppeteer.execute({ actions: extractActions, page: page });
27 await browser.close();
28
29 bytebot.puppeteer.endSession();
30}
31
32run().catch(console.error);

When you run this code, you will console something similar to:

1Data https://developer.chrome.com/_d/signin?continue=https%3A%2F%2Fdeveloper.chrome.com%2F&prompt=select_account
2Actions [
3 {
4 type: 'CopyAttribute',
5 xpath: '/html/body/section/devsite-header/div/div[1]/div/div/devsite-user/div/a',
6 attribute: 'href'
7 }
8]

This BrowserAction translates to Puppeteer or Playwright code that will copy the button’s link.

Extracting an element’s text

Extracting text is similar to extracting an attribute. Instead of Attribute, you will use Text. First, import Text from Bytebot’s SDK:

1import { Text, BytebotClient } from "./src/index.ts";

Text is also an extract schema function and takes a natural language prompt as a string. Like Attribute, the prompt does not need actions words like “Get” or “Extract”. Instead, the prompt should strictly define what element’s text is to be extracted:

1import { Text, BytebotClient } from '@bytebot/sdk';
2import puppeteer from "puppeteer";
3import "dotenv/config";
4
5async function run() {
6 const browser = await puppeteer.launch();
7 const page = await browser.newPage();
8 await page.goto("https://developer.chrome.com/", {
9 waitUntil: "networkidle0",
10 });
11
12 const bytebot = new BytebotClient({
13 apiKey: process.env.BYTEBOT_API_KEY,
14 });
15
16 bytebot.puppeteer.startSession();
17
18 const prompt = "The header text";
19 const extractActions = await bytebot.puppeteer.extract({
20 schema: Text(prompt),
21 page: page,
22 });
23 console.log("Actions", extractActions);
24
25 //execute the actions
26 await bytebot.puppeteer.execute({ actions: extractActions, page: page });
27 await browser.close();
28
29 bytebot.puppeteer.endSession();
30}
31
32run().catch(console.error);

When you run this query, you will console something similar to:

1[
2 {
3 type: 'CopyText',
4 xpath: '/html/body/section/section/main/devsite-content/article/div[3]/section[5]/div/header/div/h2/text()'
5 }
6]

You can only extract the entire text block from an element. Any additional text manipulation (e.g., “Only the first sentence”) must be handled after the entire element’s text has been extracted.

Extracting tabular data

To extract tabular data, you will need to leverage both Column and Table extract schema functions, as well as Attribute and/or Text depending on what you are extracting.

💡 Bytebot does not require that tabular data be encapsulated in an HTML <table>. Instead, so long as data is visually presented in some tabular or list-like format, Bytebot can extract the data as a table.

First, import Column and Table from Bytebot’s SDK. You should also import Attribute and/or Text depending on what you are extracting:

1import { Table, Column, Attribute, Text, BytebotClient } from "./src/index.ts";

To create an extract schema, call Table on an array of Column function calls, where each Column function call has a name and a value set to a Text or Attribute function call. Finally, call extract on that schema:

1import { Table, Column, Attribute, Text, BytebotClient } from '@bytebot/sdk';
2import puppeteer from "puppeteer";
3import "dotenv/config";
4
5async function run() {
6 const browser = await puppeteer.launch();
7 const page = await browser.newPage();
8 await page.goto("https://www.ycombinator.com/companies", {
9 waitUntil: "networkidle0",
10 });
11
12 const bytebot = new BytebotClient({
13 apiKey: process.env.BYTEBOT_API_KEY,
14 });
15
16 bytebot.puppeteer.startSession();
17
18 const extractActions = await bytebot.puppeteer.extract({
19 sessionId: browser.sessionId,
20 schema: Table([
21 Column("Name", Text("The name of the company")),
22 Column("Description", Text("The description of the company")),
23 Column("Profile Page", Attribute("The link to the company's profile")),
24 ]),
25 });
26 console.log("Extract Actions", extractActions);
27
28 //execute the actions
29 await bytebot.puppeteer.execute({ actions: extractActions, page: page });
30 await browser.close();
31
32 bytebot.puppeteer.endSession();
33}
34
35run().catch(console.error);

When executed, this snippet will print a full table of scraped companies:

1[
2 {
3 Name: 'Honeylove',
4 Description: 'Honeylove makes functional undergarments for women',
5 'Profile Page': '/companies/honeylove'
6 },
7 {
8 Name: 'Meesho',
9 Description: 'Democratizing internet commerce for everyone in India',
10 'Profile Page': '/companies/meesho'
11 },
12 ...
13 {
14 Name: 'Mixpanel',
15 Description: 'Mixpanel is event analytics for builders that need answers.',
16 'Profile Page': '/companies/mixpanel'
17 }
18]

Next Steps

After creating one-off actions or extractions, you may want to arbitrarily check the status of the browser, especially if the browser actions are handled by a separate, asynchronous loop. You can accomplish that with the status function.