Skip to main content

scrapy-ingest

Scrapy Ingest

PyPI version Python versions Downloads Documentation License: MIT Changelog

One pipeline. Full crawl observability in SQL or Elasticsearch.

Set DB_URL, SEARCH_URL, or both — items, requests, logs, stats, parent URLs, and errors are captured automatically.

Install

pip install scrapy-ingest

This installs all runtime dependencies, including psycopg2-binary, PyMySQL, and opensearch-py.

Minimal setup (settings.py)

Only the item pipeline is required — requests, logs, stats, parent_url, and error logging are enabled automatically:

ITEM_PIPELINES = {
    "scrapy_ingest.pipelines.IngestPipeline": 300,
}

DB_URL = "postgresql://user:password@localhost:5432/database"

Run your spider:

scrapy crawl your_spider

Log level follows Scrapy LOG_LEVEL.

Choose your destination

Set DB_URL (or DB_* fields) for Postgres/MySQL, SEARCH_URL for Elasticsearch/OpenSearch, or both. At least one must be configured.

Mode Settings Result
Database only DB_URL or DB_* SQL only
Elasticsearch / OpenSearch only SEARCH_URL Indexes only
Both DB_URL + SEARCH_URL SQL first, then Elasticsearch/OpenSearch
# Database only
DB_URL = "postgresql://user:password@localhost:5432/database"

# Elasticsearch / OpenSearch only
SEARCH_URL = "http://localhost:9200"

# Both
DB_URL = "postgresql://user:password@localhost:5432/database"
SEARCH_URL = "http://localhost:9200"

When both are configured, SQL is written first, then Elasticsearch/OpenSearch indexes. An indexing failure after a successful SQL write is logged but does not roll back database rows.

Database configuration

PostgreSQL or MySQL — pick one connection style.

Single URL:

DB_URL = "postgresql://user:password@localhost:5432/database"
# DB_URL = "mysql://user:password@localhost:3306/database"

Discrete fields (no URL encoding for special characters in passwords):

DB_TYPE = "postgres"   # or "mysql" / "mariadb"
DB_HOST = "localhost"
DB_PORT = 5432         # MySQL: 3306
DB_USER = "user"
DB_PASSWORD = "password"
DB_NAME = "database"

Tables are created automatically when CREATE_TABLES = True (default).

Elasticsearch / OpenSearch configuration

Elasticsearch and OpenSearch use the same REST bulk API. The package connects via opensearch-py, which works with both.

Minimum:

SEARCH_URL = "http://localhost:9200"

With authentication (optional):

SEARCH_URL = "https://search.example.com:9200"
SEARCH_USER = "elastic"
SEARCH_PASSWORD = "secret"
SEARCH_SSL_VERIFY = True   # set False only for self-signed certs in dev

Index names match SQL table names by default:

Table / index Contents
ingest_jobs Job metadata: status, counts, elapsed time, stats
ingest_items Scraped items as JSON documents
ingest_requests Requests: url, fingerprint, parent_url, status, error
ingest_logs Log lines: level, logger, message, exception

Override table/index names with JOBS_TABLE, ITEMS_TABLE, REQUESTS_TABLE, and LOGS_TABLE (same setting for SQL and Elasticsearch/OpenSearch).

Indexes are created on first write if they do not exist.

What is stored

Relational database (Postgres / MySQL)

Table Contents
ingest_jobs One row per crawl: id, unique job_id string, spider, status, start/finish, counts, items/min, stats. errors_count = failed requests + standalone ERROR/CRITICAL logs (not double-counted from scrapy.core.scraper when the request is already failed)
ingest_items JSON items (crawled_at added). job_id = ingest_jobs.id (CASCADE)
ingest_requests url, parent_url, parent_id, status, response_time_secs, fingerprint, error, success (download errors, HTTP 4xx/5xx, spider callback tracebacks)
ingest_logs time, logger, level, message, exception

Request parent_url is the page that scheduled the request (e.g. sitemap → product). Start URLs are null. The request fingerprint is a SHA1 hash of method + canonical URL for parent lookup.

Elasticsearch / OpenSearch

Same crawl data as JSON documents in the indexes listed above. Documents include the string job_id (not the integer SQL primary key). Elasticsearch/OpenSearch mode does not link parent_id; parent_url is stored on each request document.

Batch flush and crawl summary

Data flushes on batch size, every 10 seconds, and on engine/process stop.

When the spider closes, a crawl summary is printed to stderr (visible even when LOG_LEVEL is ERROR) with job id, spider, database URL, Elasticsearch/OpenSearch URL, table/index names, counts, and elapsed time. Set INGEST_SHOW_SUMMARY = False to hide it.

CLI

Run from your Scrapy project directory (loads settings.py via Scrapy).

check-config

Validate settings and ping configured destinations before running a spider:

scrapy-ingest check-config
scrapy-ingest check-config --db-url "postgresql://user:pass@localhost:5432/db"
scrapy-ingest check-config --search-url "http://localhost:9200"

Shows a spinner per step, prints a summary table to stderr, and exits 0 when all configured destinations are reachable.

jobs show

List recent jobs or print one job summary from SQL or Elasticsearch/OpenSearch (requires DB_URL and/or SEARCH_URL). When both are configured, queries use SQL; crawls still dual-write to both.

scrapy-ingest jobs show                                    # list recent jobs
scrapy-ingest jobs show --limit 20                         # list up to 20 jobs
scrapy-ingest jobs show --status running                   # filter by status (list mode)
scrapy-ingest jobs show --spider Rs_Spider                 # filter by spider (list mode)
scrapy-ingest jobs show Rs_Spider-178826754-a1b2            # one job (Field | Value table)
scrapy-ingest jobs show --search-url "http://localhost:9200"

List mode (no job id): table of recent jobs — job id, spider, status, timestamps, counts. Detail mode (with job id): Field | Value table from the jobs row. --status and --spider apply in list mode only.

The job id is the string shown in the end-of-crawl summary (or your JOB_ID setting). Exit 0 on success (including an empty list); exit 1 if a specific job id is missing or the destination is unreachable.

Typical workflow:

scrapy-ingest check-config
scrapy crawl your_spider
scrapy-ingest jobs show
scrapy-ingest jobs show --status finished --spider your_spider
scrapy-ingest jobs show <job_id>

See CLI docs for details.

Useful settings

Setting Default Description
DB_URL / DB_* — Database connection (enables SQL ingest)
SEARCH_URL — Elasticsearch or OpenSearch URL (enables indexing)
SEARCH_USER / SEARCH_PASSWORD — HTTP basic auth for Elasticsearch/OpenSearch (optional)
SEARCH_SSL_VERIFY True Verify HTTPS certificates
CREATE_TABLES True Auto-create SQL tables on startup
INGEST_BATCH_SIZE 50 Flush when this many rows are buffered
INGEST_FLUSH_INTERVAL 10 Periodic flush in seconds
INGEST_SHOW_SUMMARY True Print crawl summary when the spider closes
DB_TYPE postgres postgres / mysql / mariadb for discrete DB_* fields
ITEMS_TABLE, REQUESTS_TABLE, LOGS_TABLE, JOBS_TABLE see defaults Override SQL table and index names (same value for both)
TIMEZONE Asia/Karachi Timezone for created_at
JOB_ID auto Omit to auto-generate (Rs_Spider-178826754-a1b2)

Troubleshooting

  • Password has @ or $ in DB_URL? Encode them: @ → %40, $ → %24. Or use discrete DB_* fields.
  • Yield items from callbacks (not only return inside a generator).
  • Elasticsearch / OpenSearch connection refused? Check SEARCH_URL, firewall, and that the cluster is running. Test with curl http://localhost:9200.
  • HTTPS / self-signed cert? Set SEARCH_SSL_VERIFY = False in development only.

Standalone components

If you only want part of the collection:

# Items only
ITEM_PIPELINES = {"scrapy_ingest.pipelines.ItemsPipeline": 300}

# Requests only (parent_url + errors)
ITEM_PIPELINES = {"scrapy_ingest.pipelines.RequestsPipeline": 300}

# Logs only
EXTENSIONS = {"scrapy_ingest.extensions.LoggingExtension": 500}

License

MIT License. See LICENSE.

Metadata

Release files for scrapy-ingest 1.5.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-ingest 1.5.0
File Size Uploaded
scrapy_ingest-1.5.0.tar.gz 227.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for scrapy-ingest 1.5.0
File Interpreter ABI Platform
scrapy_ingest-1.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 275.2 kB

Release files / scrapy_ingest-1.5.0.tar.gz

Download URL scrapy_ingest-1.5.0.tar.gz
Size 227.0 kB
Tags Source
SHA-256 checksum
How to use checksums
7f3642491533eedb889a1366daf9edc0d4248e6785bf7f7b3b2065845943e549
BLAKE2b-256 checksum
How to use checksums
8aab0fe181927c75b4bf3fc30a2cafe2dc3c779efce4a2786397ac37a9d2d257
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / scrapy_ingest-1.5.0-py3-none-any.whl

Download URL scrapy_ingest-1.5.0-py3-none-any.whl
Size 48.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1b2852f2f401f9deca78448ca0212bf4166cf472fef5a6851cbff8f489e4c21e
BLAKE2b-256 checksum
How to use checksums
ddf2e7067745b49c2a59b2a9c9da12e9a2d8a3b2a4beb46b32aa32c9210f1d4f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release history Release notifications | RSS feed

1.8.0

2 release files

1.7.0

2 release files

1.6.0

2 release files

This release

1.5.0 This release

2 release files

1.4.0

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

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