Skip to content

v0.6.9

Choose a tag to compare

@fawadss1 fawadss1 released this 29 Jun 07:09
· 64 commits to master since this release
25c9a9d

[0.6.9] - 2026-06-29

Added

  • Proxy bypass list (BROWSER_PROXY_BYPASS_LIST)
    Route chosen domains around the proxy in the browser engine. The user-supplied list is passed to Chrome's --proxy-bypass-list
    launch flag, so requests to those domains connect to the origin directly instead of through the proxy relay. Supports the full Chrome
    bypass syntax — bare hostnames, wildcards (*.example.com), IP/CIDR ranges, ports, and the <local> token. Configured globally via
    config/settings; only takes effect when a proxy is in use.

Fixed

  • Browser engine — pending tasks destroyed on ban-triggered restart
    When one Scrapy thread triggered a browser restart after consecutive bans,
    other concurrent _run_fetch coroutines and their _smart_wait sleep()
    children were left running on the old event loop and destroyed during
    teardown. Restarts now block new fetches behind a restart barrier, drain
    all pending loop tasks before stopping Chrome, and retry transient
    connection errors once on the fresh browser.

  • Browser engine — wrong-tab / cannot call get() concurrently
    Replaced browser.get(url, new_tab=True) with direct cdp.target.create_target(url) to
    guarantee a 1:1 mapping between the created CDP target and the Tab object, eliminating the
    wrong-tab race and the duplicate _listener_task that caused the concurrency assertion.

  • Browser engine — _do_fetch tasks leaked on timeout
    Tasks continued running after future.result(timeout=...) raised TimeoutError, holding
    _tab_sem slots and producing "Task was destroyed but it is pending!" on teardown.
    The task is now cancelled directly via loop.call_soon_threadsafe(task.cancel) on timeout.

  • Browser engine — "Event loop is closed" log noise
    _chain_future callbacks and call_soon_threadsafe handles firing against a closed loop
    after _reset_browser are now suppressed by a teardown filter on the asyncio and
    concurrent.futures loggers.

  • Browser engine — AttributeError: 'NoneType' object has no attribute 'get'
    Snapshotting browser = self._browser at _do_fetch entry prevents _reset_browser
    nulling self._browser mid-execution from reaching browser.get().

  • Browser engine — Akamai 403 consuming full 30 s timeout
    _wait_for_status now fast-exits on error page titles (Access Denied, Forbidden, etc.)
    returning 403 immediately. _smart_wait exits early when body length stops growing for 3 s.

  • Browser engine — logo.png splash causing wrong-tab on startup
    _splash_url() now returns "about:blank" instead of a file:// URI.

  • Proxy relay — orphaned handle() tasks on restart / shutdown
    ProxyRelay.await_closed() now cancels and awaits all live handle() tasks before
    closing the server, replacing the bare server.close() that left tasks running.

  • Windows Proactor — InvalidStateError crashing the browser loop thread
    _run_loop wraps loop.run_forever() in try/except asyncio.InvalidStateError;
    the loop exception handler suppresses it as well.

  • Windows browser-restart log noise (WinError 995)
    Suppressed benign Windows Proactor teardown errors logged when the event loop and proxy relay are torn down during a browser restart.
    The loop exception handler now ignores WinError 995 (ERROR_OPERATION_ABORTED) and WinError 64 (ERROR_NETNAME_DELETED)
    alongside the existing 10054 (WSAECONNRESET); genuine errors are still surfaced. The restart itself was always succeeding — only
    the spurious ERROR tracebacks are gone.

  • Temp profiles — uc_* dirs accumulating in %TEMP%
    _cleanup_browser_profiles() removes stale nodriver temp dirs on every restart and shutdown.

Changed

  • Console — timestamp now styled Fore.YELLOW to match Scrapy's log format.