Skip to main content

scrapy-flaresolverr

PyPI Python Scrapy License Build Status Functional Tests Pre-commit Checks Codecov

A Scrapy downloader middleware for routing opt-in requests through one or more FlareSolverr backends.

scrapy-flaresolverr provides a small integration layer between Scrapy and the FlareSolverr v1 API, with support for multiple backends, round-robin selection, request-level options, bounded concurrency, response reconstruction, and Scrapy stats.

Features

  • Stateless FlareSolverr request.get integration
  • Multiple FlareSolverr backends with thread-safe round-robin selection
  • Request-level backend override
  • Optional Bearer authentication
  • Configurable request and FlareSolverr timeouts
  • Configurable concurrency limits
  • Request-level media disabling and wait time
  • Optional screenshot return
  • Reconstruction of complete Scrapy HtmlResponse objects
  • FlareSolverr response metadata exposed through response.meta
  • Scrapy stats for requests, responses, errors, and concurrency timeouts
  • Explicit package-specific exceptions for configuration, transport, response, concurrency, and unsupported-request failures

Requirements

  • Python 3.10+
  • Scrapy 2.12+
  • requests 2.31+

The package supports Scrapy 2.x and currently declares:

Python >=3.10
Scrapy >=2.12,<3
requests >=2.31,<3

CI compatibility matrix

The build and functional test workflows cover the following compatibility baseline:

Python Scrapy 2.12.x Latest supported Scrapy 2.x
3.10
3.11
3.12
3.13
3.14

The minimum Scrapy line is tested on Python versions supported by that combination, while current Scrapy 2.x is tested across all supported Python versions.

Installation

Install from PyPI:

pip install scrapy-flaresolverr

For local development:

git clone https://github.com/geeone/scrapy-flaresolverr.git
cd scrapy-flaresolverr
pip install -r requirements-dev.txt

Quick start

Enable the downloader middleware in your Scrapy settings:

DOWNLOADER_MIDDLEWARES = {
    "scrapy_flaresolverr.middleware.FlareSolverrMiddleware": 100,
}

FLARESOLVERR_URLS = [
    "http://127.0.0.1:8191",
]

FLARESOLVERR_MAX_CONCURRENT = 3

Then opt individual requests into FlareSolverr:

yield scrapy.Request(
    "https://example.com",
    meta={"flaresolverr": True},
)

Request-specific options can be passed as a dictionary:

yield scrapy.Request(
    "https://example.com",
    meta={
        "flaresolverr": {
            "disable_media": True,
            "wait_in_seconds": 2,
            "return_screenshot": True,
        },
    },
)

Requests without the flaresolverr opt-in continue through Scrapy's normal downloader middleware chain.

Configuration

Backend URLs

Configure one or more FlareSolverr backends:

FLARESOLVERR_URLS = [
    "http://127.0.0.1:8191",
    "http://127.0.0.1:8192",
]

Configured backend URLs are normalized to the FlareSolverr /v1 endpoint.

For example:

http://127.0.0.1:8191       -> http://127.0.0.1:8191/v1
http://127.0.0.1:8191/fs1/  -> http://127.0.0.1:8191/fs1/v1

A single backend can alternatively be configured with:

FLARESOLVERR_URL = "http://127.0.0.1:8191"

When multiple backends are configured, requests are distributed using round-robin selection.

Authentication

If the FlareSolverr endpoint or an upstream reverse proxy requires Bearer authentication:

FLARESOLVERR_AUTH_TOKEN = "your-token"

The token is sent as:

Authorization: Bearer <token>

Settings reference

Setting Default Description
FLARESOLVERR_URLS List of FlareSolverr backend URLs
FLARESOLVERR_URL Single-backend fallback when FLARESOLVERR_URLS is not set
FLARESOLVERR_AUTH_TOKEN None Optional Bearer token
FLARESOLVERR_MAX_CONCURRENT 3 Maximum number of concurrent FlareSolverr calls
FLARESOLVERR_CONCURRENCY_WAIT_TIMEOUT 120.0 Maximum seconds to wait for a concurrency slot
FLARESOLVERR_MAX_TIMEOUT 60000 FlareSolverr maxTimeout in milliseconds
FLARESOLVERR_REQUEST_TIMEOUT 75.0 HTTP timeout in seconds for the call to FlareSolverr
FLARESOLVERR_DISABLE_MEDIA False Disable media by default for FlareSolverr requests

FLARESOLVERR_REQUEST_TIMEOUT must be greater than FLARESOLVERR_MAX_TIMEOUT converted to seconds.

Request options

Per-request behavior is configured through request.meta["flaresolverr"].

yield scrapy.Request(
    "https://example.com",
    meta={
        "flaresolverr": {
            "backend": "http://127.0.0.1:8191",
            "max_timeout": 90_000,
            "request_timeout": 110,
            "wait_in_seconds": 2,
            "disable_media": True,
            "return_screenshot": False,
        },
    },
)
Option Type Description
backend str Use a specific configured backend for this request
max_timeout int Override FlareSolverr maxTimeout in milliseconds
request_timeout float Override the HTTP timeout for the FlareSolverr call
wait_in_seconds float Additional FlareSolverr wait time; may be zero
disable_media bool Override the global media-loading setting
return_screenshot bool Request a screenshot from FlareSolverr

A backend override must resolve to one of the configured backends.

Multiple backends

Multiple backends are selected in round-robin order:

FLARESOLVERR_URLS = [
    "http://127.0.0.1:8191/fs1/",
    "http://127.0.0.1:8191/fs2/",
]

The backend selected for a request is exposed as:

response.meta["flaresolverr_backend"]

A request can explicitly target one configured backend:

yield scrapy.Request(
    "https://example.com",
    meta={
        "flaresolverr": {
            "backend": "http://127.0.0.1:8191/fs2/",
        },
    },
)

Response metadata

Successful FlareSolverr requests are returned as Scrapy HtmlResponse instances.

The middleware marks the request with:

response.meta["flaresolverr_used"]
response.meta["flaresolverr_backend"]

Additional FlareSolverr response data is available under:

response.meta["flaresolverr_response"]

The dictionary contains:

{
    "cookies": ...,
    "user_agent": ...,
    "screenshot": ...,
    "start_timestamp": ...,
    "end_timestamp": ...,
    "version": ...,
}

The reconstructed response also includes the flaresolverr response flag.

Because FlareSolverr returns decoded HTML, transport-specific headers such as Content-Encoding, Content-Length, and Transfer-Encoding are not copied to the reconstructed Scrapy response. The response body is encoded as UTF-8 and the Content-Type charset is normalized accordingly.

Stats

The middleware records counters through Scrapy's stats collector:

flaresolverr/request_count
flaresolverr/response_count
flaresolverr/request_error
flaresolverr/concurrency_timeout
flaresolverr/unsupported_request

They can be inspected together with the rest of the spider's Scrapy stats.

Error handling

scrapy-flaresolverr does not silently fall back to Scrapy's normal downloader after a FlareSolverr failure. Errors are propagated through package-specific exceptions:

  • FlareSolverrConfigurationError
  • FlareSolverrConcurrencyError
  • FlareSolverrRequestError
  • FlareSolverrResponseError
  • FlareSolverrUnsupportedRequestError

This keeps FlareSolverr failures explicit and observable by the calling spider or Scrapy error handling.

Current limitations

Version 0.1.0 supports stateless GET requests only.

Current limitations include:

  • no FlareSolverr sessions or session affinity
  • no proxy configuration or proxy affinity
  • no automatic backend failover or health-based routing

See the roadmap for planned development.

Examples

The repository includes runnable examples:

  • Basic spider — middleware configuration, request options, and selected-backend metadata
  • Docker Compose — two FlareSolverr workers behind an authenticated Nginx reverse proxy

The Docker Compose example can be used together with the basic spider to exercise multiple-backend routing locally.

Development

Install the development dependencies:

pip install -r requirements-dev.txt

Run the test suite:

pytest --cov=scrapy_flaresolverr --cov-report=term-missing tests/

Run the configured pre-commit checks:

pre-commit run --all-files

Or install the hooks locally:

pre-commit install

The project uses Ruff for linting and formatting, mypy for static type checking, pytest for testing, and pytest-cov for coverage.

For an overview of the internal design, see the architecture documentation.

Contributing

Bug reports, feature requests, and pull requests are welcome.

Before contributing, please review:

Security-related issues should be reported according to the Security Policy, rather than through a public issue.

Release history is documented in the Changelog.

Support the project

If scrapy-flaresolverr is useful to you, consider giving the project a ⭐ on GitHub.

License

MIT. See LICENSE for details.

Release files for scrapy-flaresolverr 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for scrapy-flaresolverr 0.1.0
File Size Uploaded
scrapy_flaresolverr-0.1.0.tar.gz 29.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for scrapy-flaresolverr 0.1.0
File Interpreter ABI Platform
scrapy_flaresolverr-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 46.0 kB

Release files / scrapy_flaresolverr-0.1.0.tar.gz

Download URL scrapy_flaresolverr-0.1.0.tar.gz
Size 29.3 kB
Tags Source
SHA-256 checksum
How to use checksums
17d21dd5b5e378497f0fb7fcec7f835e717f2682adba06b99cd76565bb0510d2
BLAKE2b-256 checksum
How to use checksums
28abbc58ffa889a363b1b50cb3ea416fb5c2e0a93ea82dd4933a1adee8f87dc3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release files / scrapy_flaresolverr-0.1.0-py3-none-any.whl

Download URL scrapy_flaresolverr-0.1.0-py3-none-any.whl
Size 16.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
395dd761967317f5934735e086df901bb35e776c1a4c202cb590c45f8fadb969
BLAKE2b-256 checksum
How to use checksums
707d16a2b721b13f5cf86dfe05066411c97339067d576098fef626da19f99072
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page