Skip to main content

Playwright-like async API for PhantomJS — pip install only, no apt, no npm, no Chrome.

Project description

Phasma

phasma

Headless browser automation that works with pip install alone.

No apt. No npm. No Chrome. No system dependencies.

PyPI Python License: MIT


Why phasma?

Most headless browser tools require installing Chrome, Chromium, or Node.js at the system level — which isn't always possible.

phasma was built for environments where apt is locked but pip is open: corporate servers, HPC clusters, minimal Docker images, restricted CI/CD pipelines. The PhantomJS binary ships inside the wheel. After pip install phasma, everything works immediately, no further setup required.


Installation

pip install phasma

Requirements: Python 3.10+
Platforms: Linux, macOS, Windows (x86 32-bit & 64-bit)


Quick start

import asyncio
import phasma

async def main():
    browser = await phasma.launch()
    try:
        page = await browser.new_page()
        await page.goto("https://example.com")

        title  = await page.evaluate("document.title")
        heading = await page.text_content("h1")
        print(title, heading)

        await page.screenshot(path="shot.png")
        await page.pdf(path="page.pdf")
    finally:
        await browser.close()

asyncio.run(main())

One persistent PhantomJS process handles every operation — no per-call restarts.


Browser API

The API mirrors Playwright so it feels familiar.

launch() / connect()

browser = await phasma.launch()

Browser

Method Returns Description
new_page() Page Open a new page
new_context(options?) BrowserContext Create an isolated context
close() Shut down the browser
is_connected() bool Whether the process is alive

Page

Navigation

await page.goto(url, timeout=30_000, wait_ms=0)
await page.set_viewport_size(1280, 720)

DOM / JavaScript

title   = await page.evaluate("document.title")
text    = await page.text_content("h1")
html    = await page.inner_html("#content")
result  = await page.eval_on_selector("a", "this.href")
element = await page.wait_for_selector(".loaded", timeout=5000)

Interaction

await page.click("#submit")
await page.fill("#email", "user@example.com")

Output

png_bytes = await page.screenshot("out.png")
pdf_bytes = await page.pdf("out.pdf", format="A4", landscape=False, margin="1cm")

ElementHandle

el = await page.wait_for_selector(".result")
await el.click()
await el.fill("value")
text = await el.text_content()
html = await el.inner_html()

Errors

phasma.Error        # base browser error
phasma.TimeoutError # operation exceeded timeout

SVG Rendering

Convert SVG to PNG, JPEG, or PDF — no Inkscape, no cairosvg, no extra installs.

from phasma.svg import SvgRenderer

async with SvgRenderer() as r:
    png = await r.to_png("<svg ...>...</svg>")
    jpg = await r.to_jpeg(Path("diagram.svg"), scale=2.0)
    pdf = await r.to_pdf("chart.svg", output="chart.pdf", pdf_landscape=True)

One SvgRenderer instance = one PhantomJS process reused across all conversions.

Method Options
to_png(source, output?, scale?, background?) PNG bytes
to_jpeg(source, output?, scale?, background?) JPEG bytes
to_pdf(source, output?, scale?, pdf_format?, pdf_landscape?, pdf_margin?) PDF bytes

source accepts an SVG string, a file path string, or a Path object.


Utility functions

For simple one-shot operations without managing a browser session:

# render HTML
html = await phasma.render_page_content("<h1>Hello</h1>")
html = await phasma.render_url_content("https://example.com")

# execute JavaScript
result = await phasma.execute_js_script("1 + 1")

# screenshot / PDF
await phasma.take_screenshot("https://example.com", "out.png")
await phasma.generate_pdf("https://example.com", "out.pdf")

# sync versions (no asyncio.run needed)
html = phasma.sync_render_page_content("<h1>Hello</h1>")
phasma.sync_take_screenshot("https://example.com", "out.png")

Examples

Scraping

async with phasma.launch() as browser:  # also works as context manager
    page = await browser.new_page()
    await page.goto("https://example.com")

    data = await page.evaluate("""({
        title: document.title,
        links: Array.from(document.querySelectorAll('a'))
                    .map(a => ({ text: a.textContent.trim(), href: a.href }))
    })""")

Form interaction

page = await browser.new_page()
await page.goto("https://example.com/login")
await page.fill("#username", "user@example.com")
await page.fill("#password", "secret")
await page.click("#submit")
await page.wait_for_selector(".dashboard")

Batch screenshots

browser = await phasma.launch()
try:
    for url in urls:
        page = await browser.new_page()
        await page.goto(url, timeout=15_000)
        name = url.replace("https://", "").replace("/", "_") + ".png"
        await page.screenshot(name)
finally:
    await browser.close()

Batch SVG export

svgs = Path("assets").glob("*.svg")

async with SvgRenderer() as r:
    for svg in svgs:
        await r.to_png(svg, output=svg.with_suffix(".png"), scale=2.0)

CLI

# driver management
python -m phasma driver --version
python -m phasma driver --path
python -m phasma driver download --force

# run a PhantomJS script
python -m phasma driver exec script.js

# render
python -m phasma render-page file.html --output out.html --viewport 1920x1080
python -m phasma render-url https://example.com --output page.html --wait 2000

# screenshot
python -m phasma screenshot https://example.com shot.png --viewport 1280x720

# PDF
python -m phasma pdf https://example.com doc.pdf --format A4 --landscape

# execute JS
python -m phasma execjs "document.title"

Troubleshooting

Installing from source — binary is not bundled when cloning the repo. Run once:

python -m phasma driver download

Timeout errors — increase the timeout parameter in goto() or wait_for_selector().

SSL errors — set OPENSSL_CONF="" in your environment, or pass --ssl-protocol=any via CLI.

Check binary path:

python -m phasma driver --path

Testing

pip install -e ".[dev]"
pytest tests/ -v

Contributing

  1. Fork and create a feature branch
  2. Add tests for new functionality
  3. Run pytest tests/ — all must pass
  4. Open a pull request

License

MIT — see LICENSE.


phasma — headless browser automation, batteries included.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

phasma-0.7.0-py3-none-win_amd64.whl (18.2 MB view details)

Uploaded Python 3Windows x86-64

phasma-0.7.0-py3-none-manylinux_2_17_x86_64.whl (26.2 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

phasma-0.7.0-py3-none-manylinux_2_17_i686.whl (27.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ i686

phasma-0.7.0-py3-none-macosx_10_9_universal2.whl (17.2 MB view details)

Uploaded Python 3macOS 10.9+ universal2 (ARM64, x86-64)

File details

Details for the file phasma-0.7.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: phasma-0.7.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 18.2 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for phasma-0.7.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 4aee20eeceeb7f19d2f9ab725dd57ad2c0573dae6e43609966fc2d35e2dcaaca
MD5 62a1361555693524ee056ae5be257b06
BLAKE2b-256 f372c46d7321c05a90e40d7efc6c940183000c0c817facc2dc68fb11fc7beea5

See more details on using hashes here.

File details

Details for the file phasma-0.7.0-py3-none-manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for phasma-0.7.0-py3-none-manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 401ef243050ae71e4c82ea9b6417c3bb771957342366f327e8760dd639724336
MD5 e89633a2182bf42cc0e7c99d415abd38
BLAKE2b-256 f30b59c34fcb77e012c71cd5157b0b5208e0dc2790c7306ba4c63a77a67c34f6

See more details on using hashes here.

File details

Details for the file phasma-0.7.0-py3-none-manylinux_2_17_i686.whl.

File metadata

  • Download URL: phasma-0.7.0-py3-none-manylinux_2_17_i686.whl
  • Upload date:
  • Size: 27.3 MB
  • Tags: Python 3, manylinux: glibc 2.17+ i686
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for phasma-0.7.0-py3-none-manylinux_2_17_i686.whl
Algorithm Hash digest
SHA256 22c6298a512ccda22ceedda08c4c30ae17e8ff20a6bfa2d7208bc135aa1d7319
MD5 24aa25368a69f4dbd5e4239e6d16a4f0
BLAKE2b-256 eb779aabcb43ae8153c73afacf4535aa541e21193a601ea409e8397b2a1f0a0e

See more details on using hashes here.

File details

Details for the file phasma-0.7.0-py3-none-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for phasma-0.7.0-py3-none-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 e9a0571051ea6f5220f1c42bcf2541c6cbac93f522edfd7dd8a22544cc2bbc6a
MD5 aee3d0c5bcda90e9604762667b02dcb2
BLAKE2b-256 a71a7d91ad9eacd06fcbe845ffff9edc4a4e51eab519eb3fa33ed323f47147fa

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page