perf: reuse browser across chart scrapes
This commit is contained in:
+39
-22
@@ -2,6 +2,7 @@
|
||||
|
||||
import logging
|
||||
import traceback
|
||||
from contextlib import contextmanager
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -51,31 +52,42 @@ CHARTS = {
|
||||
}
|
||||
|
||||
|
||||
def scrape_chart(chart_path, timeout=25000):
|
||||
"""Scrape a single chart from LookIntoBitcoin. Returns list of trace dicts or None."""
|
||||
@contextmanager
|
||||
def browser_page():
|
||||
"""Open one headless browser page for a batch of chart requests."""
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
with sync_playwright() as playwright:
|
||||
browser = playwright.chromium.launch(headless=True)
|
||||
try:
|
||||
yield browser.new_page()
|
||||
finally:
|
||||
browser.close()
|
||||
|
||||
|
||||
def scrape_chart(chart_path, timeout=25000, page=None):
|
||||
"""Scrape one chart, optionally reusing a caller-owned browser page."""
|
||||
if page is None:
|
||||
with browser_page() as owned_page:
|
||||
return scrape_chart(chart_path, timeout=timeout, page=owned_page)
|
||||
|
||||
store = {"data": None}
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
page = browser.new_page()
|
||||
def handle_response(response):
|
||||
if "_dash-update-component" in response.url:
|
||||
try:
|
||||
store["data"] = response.json()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def handle_response(response):
|
||||
if "_dash-update-component" in response.url:
|
||||
try:
|
||||
store["data"] = response.json()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
page.on("response", handle_response)
|
||||
try:
|
||||
page.goto(f"{BASE_URL}{chart_path}", timeout=timeout)
|
||||
page.wait_for_timeout(6000)
|
||||
except Exception as e:
|
||||
log.warning("Navigation error for %s: %s", chart_path, e)
|
||||
finally:
|
||||
browser.close()
|
||||
page.on("response", handle_response)
|
||||
try:
|
||||
page.goto(f"{BASE_URL}{chart_path}", timeout=timeout)
|
||||
page.wait_for_timeout(6000)
|
||||
except Exception as exc:
|
||||
log.warning("Navigation error for %s: %s", chart_path, exc)
|
||||
finally:
|
||||
page.remove_listener("response", handle_response)
|
||||
|
||||
if store["data"]:
|
||||
try:
|
||||
@@ -172,13 +184,18 @@ def _get_recent_values(trace, n=30):
|
||||
|
||||
|
||||
def scrape_all():
|
||||
"""Scrape all charts and return parsed metric values."""
|
||||
"""Scrape all charts while reusing one browser process and page."""
|
||||
with browser_page() as page:
|
||||
return _scrape_all_with_page(page)
|
||||
|
||||
|
||||
def _scrape_all_with_page(page):
|
||||
results = {}
|
||||
|
||||
for metric_key, chart_info in CHARTS.items():
|
||||
log.info("Scraping %s ...", metric_key)
|
||||
try:
|
||||
traces = scrape_chart(chart_info["path"])
|
||||
traces = scrape_chart(chart_info["path"], page=page)
|
||||
if not traces:
|
||||
log.warning("No data for %s", metric_key)
|
||||
results[metric_key] = {"value": None, "error": "No data returned"}
|
||||
|
||||
Reference in New Issue
Block a user