Create a Session
Start a remote browser session and get the CDP connection URL:
from tinyfish import TinyFish
client = TinyFish()
session = client.browser.sessions.create( url = "https://example.com" )
print ( f "Session: { session.session_id } " )
print ( f "CDP URL: { session.cdp_url } " )
print ( f "Base URL: { session.base_url } " )
Output:
{
"session_id" : "tf-84ac6714-0f08-4592-b626-e51105a079f9" ,
"cdp_url" : "wss://ip-52-53-175-49.tetra-data.tinyfish.io/tf-84ac6714-..." ,
"base_url" : "https://ip-52-53-175-49.tetra-data.tinyfish.io/tf-84ac6714-..."
}
Connect with Playwright
Create a session and control it with Playwright via CDP:
import asyncio
from playwright.async_api import async_playwright
from tinyfish import TinyFish
async def main ():
client = TinyFish()
session = client.browser.sessions.create( url = "https://scrapeme.live/shop" )
async with async_playwright() as p:
browser = await p.chromium.connect_over_cdp(session.cdp_url)
page = browser.contexts[ 0 ].pages[ 0 ]
await asyncio.sleep( 2 )
await page.wait_for_load_state( "domcontentloaded" )
title = await page.title()
print ( f "Page title: { title } " )
await page.screenshot( path = "shop.png" )
print ( "Screenshot saved to shop.png" )
asyncio.run(main())
Session creation takes 10-30 seconds. Set your HTTP client timeout to at least 60 seconds. The browser navigates to the URL asynchronously — wait for domcontentloaded before interacting.
Scrape with Playwright
Extract structured data from a page using Playwright selectors:
import asyncio, json
from playwright.async_api import async_playwright
from tinyfish import TinyFish
async def main ():
client = TinyFish()
session = client.browser.sessions.create( url = "https://scrapeme.live/shop" )
async with async_playwright() as p:
browser = await p.chromium.connect_over_cdp(session.cdp_url)
page = browser.contexts[ 0 ].pages[ 0 ]
await asyncio.sleep( 2 )
await page.wait_for_load_state( "domcontentloaded" )
products = await page.evaluate( """
() => [...document.querySelectorAll('.product')].slice(0, 5).map(el => ({
name: el.querySelector('.woocommerce-loop-product__title')?.textContent,
price: el.querySelector('.price .amount')?.textContent,
}))
""" )
print (json.dumps(products, indent = 2 ))
asyncio.run(main())
Output:
[
{ "name" : "Bulbasaur" , "price" : "£63.00" },
{ "name" : "Ivysaur" , "price" : "£87.00" },
{ "name" : "Venusaur" , "price" : "£105.00" },
{ "name" : "Charmander" , "price" : "£48.00" },
{ "name" : "Charmeleon" , "price" : "£165.00" }
]
Browser Reference Session parameters, lifecycle, and debugging
Browser Profiles Standard and stealth browser modes