ergane 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,70 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ id-token: write
11
+
12
+ jobs:
13
+ build:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.12"
22
+
23
+ - name: Install build dependencies
24
+ run: |
25
+ python -m pip install --upgrade pip
26
+ pip install build twine
27
+
28
+ - name: Build package
29
+ run: python -m build
30
+
31
+ - name: Check package
32
+ run: twine check dist/*
33
+
34
+ - name: Upload build artifacts
35
+ uses: actions/upload-artifact@v4
36
+ with:
37
+ name: dist
38
+ path: dist/
39
+
40
+ publish-testpypi:
41
+ needs: build
42
+ runs-on: ubuntu-latest
43
+ environment: testpypi
44
+
45
+ steps:
46
+ - name: Download build artifacts
47
+ uses: actions/download-artifact@v4
48
+ with:
49
+ name: dist
50
+ path: dist/
51
+
52
+ - name: Publish to TestPyPI
53
+ uses: pypa/gh-action-pypi-publish@release/v1
54
+ with:
55
+ repository-url: https://test.pypi.org/legacy/
56
+
57
+ publish-pypi:
58
+ needs: build
59
+ runs-on: ubuntu-latest
60
+ environment: pypi
61
+
62
+ steps:
63
+ - name: Download build artifacts
64
+ uses: actions/download-artifact@v4
65
+ with:
66
+ name: dist
67
+ path: dist/
68
+
69
+ - name: Publish to PyPI
70
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,47 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.10", "3.11", "3.12"]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Set up Python ${{ matrix.python-version }}
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ - name: Install dependencies
26
+ run: |
27
+ python -m pip install --upgrade pip
28
+ pip install -e .[dev]
29
+
30
+ - name: Run ruff linter
31
+ run: ruff check src/ tests/
32
+
33
+ - name: Run ruff formatter check
34
+ run: ruff format --check src/ tests/
35
+
36
+ - name: Run mypy
37
+ run: mypy src/
38
+
39
+ - name: Run tests with coverage
40
+ run: pytest tests/ -v --cov=src --cov-report=term-missing --cov-report=xml
41
+
42
+ - name: Upload coverage to Codecov
43
+ uses: codecov/codecov-action@v4
44
+ if: matrix.python-version == '3.12'
45
+ with:
46
+ files: ./coverage.xml
47
+ fail_ci_if_error: false
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .eggs/
7
+ *.parquet
8
+ *.egg
9
+ .venv/
10
+ venv/
11
+ .cache/
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2025-01-24
9
+
10
+ ### Added
11
+
12
+ - Initial release of Ergane web crawler
13
+ - Async HTTP/2 client using httpx for fast concurrent connections
14
+ - Per-domain rate limiting with token bucket algorithm
15
+ - Exponential backoff retry logic (max 3 attempts)
16
+ - robots.txt compliance (enabled by default)
17
+ - Fast HTML parsing with selectolax (16x faster than BeautifulSoup)
18
+ - Priority queue scheduler with URL deduplication
19
+ - Parquet output format via polars for efficient storage
20
+ - Graceful shutdown handling for SIGINT/SIGTERM
21
+ - CLI interface with configurable options:
22
+ - Multiple start URLs support
23
+ - Configurable concurrency and rate limits
24
+ - Depth limiting
25
+ - Same-domain or cross-domain crawling
26
+ - Custom output paths
ergane-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 pyamin1878
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
ergane-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,143 @@
1
+ Metadata-Version: 2.4
2
+ Name: ergane
3
+ Version: 0.1.0
4
+ Summary: High-performance async web scraper with selectolax parsing
5
+ Project-URL: Homepage, https://github.com/pyamin1878/ergane
6
+ Project-URL: Repository, https://github.com/pyamin1878/ergane
7
+ Project-URL: Issues, https://github.com/pyamin1878/ergane/issues
8
+ Author: pyamin1878
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: async,crawler,httpx,selectolax,spider,web-scraper
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Framework :: AsyncIO
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Internet :: WWW/HTTP
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: click>=8.1.0
23
+ Requires-Dist: httpx[http2]>=0.27.0
24
+ Requires-Dist: polars>=1.0.0
25
+ Requires-Dist: pydantic>=2.0.0
26
+ Requires-Dist: selectolax>=0.3.21
27
+ Provides-Extra: dev
28
+ Requires-Dist: beautifulsoup4>=4.12.0; extra == 'dev'
29
+ Requires-Dist: lxml>=5.0.0; extra == 'dev'
30
+ Requires-Dist: mypy>=1.8.0; extra == 'dev'
31
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
32
+ Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
33
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
34
+ Requires-Dist: ruff>=0.2.0; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # Ergane
38
+
39
+ [![PyPI version](https://badge.fury.io/py/ergane.svg)](https://badge.fury.io/py/ergane)
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
41
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
42
+
43
+ High-performance async web scraper with HTTP/2 support, built with Python.
44
+
45
+ *Named after Ergane, Athena's title as goddess of crafts and weaving in Greek mythology.*
46
+
47
+ ## Features
48
+
49
+ - **HTTP/2 Support** - Fast concurrent connections via httpx
50
+ - **Rate Limiting** - Per-domain token bucket throttling
51
+ - **Retry Logic** - Exponential backoff (max 3 attempts)
52
+ - **robots.txt Compliance** - Respects crawler directives by default
53
+ - **Fast HTML Parsing** - Selectolax with CSS selector extraction (16x faster than BeautifulSoup)
54
+ - **Smart Scheduling** - Priority queue with URL deduplication
55
+ - **Parquet Output** - Efficient columnar storage via polars
56
+ - **Graceful Shutdown** - Clean termination on SIGINT/SIGTERM
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ pip install ergane
62
+ ```
63
+
64
+ For development:
65
+
66
+ ```bash
67
+ pip install ergane[dev]
68
+ ```
69
+
70
+ ## Quick Start
71
+
72
+ ```bash
73
+ # Crawl a single site
74
+ ergane -u https://example.com -n 100
75
+
76
+ # Crawl multiple start URLs
77
+ ergane -u https://site1.com -u https://site2.com -n 500
78
+
79
+ # Custom output and settings
80
+ ergane -u https://docs.python.org -n 50 -c 20 -r 5 -o python_docs.parquet
81
+ ```
82
+
83
+ ## CLI Options
84
+
85
+ | Option | Short | Default | Description |
86
+ |--------|-------|---------|-------------|
87
+ | `--url` | `-u` | required | Start URL(s), can specify multiple |
88
+ | `--output` | `-o` | `output.parquet` | Output file path |
89
+ | `--max-pages` | `-n` | `100` | Maximum pages to crawl |
90
+ | `--max-depth` | `-d` | `3` | Maximum crawl depth from start URLs |
91
+ | `--concurrency` | `-c` | `10` | Concurrent requests |
92
+ | `--rate-limit` | `-r` | `10.0` | Requests per second per domain |
93
+ | `--timeout` | `-t` | `30.0` | Request timeout in seconds |
94
+ | `--same-domain` | | `true` | Stay on same domain as start URLs |
95
+ | `--any-domain` | | `false` | Follow links to any domain |
96
+ | `--ignore-robots` | | `false` | Ignore robots.txt restrictions |
97
+
98
+ ## Output Format
99
+
100
+ Results are saved as a Parquet file with the following schema:
101
+
102
+ | Column | Type | Description |
103
+ |--------|------|-------------|
104
+ | `url` | string | Page URL |
105
+ | `title` | string | Page title |
106
+ | `text` | string | Extracted text content (max 10k chars) |
107
+ | `links` | string | JSON array of extracted links |
108
+ | `extracted_data` | string | JSON object of custom extractions |
109
+ | `crawled_at` | string | ISO timestamp |
110
+
111
+ Read results with polars:
112
+
113
+ ```python
114
+ import polars as pl
115
+
116
+ df = pl.read_parquet("output.parquet")
117
+ print(df.head())
118
+ ```
119
+
120
+ ## Benchmarks
121
+
122
+ Ergane uses selectolax for HTML parsing, which is significantly faster than BeautifulSoup:
123
+
124
+ | Operation | Selectolax | BS4 + lxml | Speedup |
125
+ |-------------------|------------|------------|---------|
126
+ | Parse (small) | 0.05ms | 0.11ms | 2.0x |
127
+ | Parse (large) | 0.19ms | 6.05ms | 31.1x |
128
+ | Extract title | 0.20ms | 6.06ms | 30.7x |
129
+ | Extract links | 0.25ms | 6.73ms | 27.3x |
130
+ | Extract text | 0.29ms | 7.03ms | 24.5x |
131
+ | CSS selector | 0.20ms | 7.25ms | 35.7x |
132
+
133
+ **Average: 16x faster** (1000 iterations, 34KB HTML)
134
+
135
+ Run the benchmark:
136
+ ```bash
137
+ pip install beautifulsoup4 lxml
138
+ python benchmarks/parse_benchmark.py
139
+ ```
140
+
141
+ ## License
142
+
143
+ MIT
ergane-0.1.0/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # Ergane
2
+
3
+ [![PyPI version](https://badge.fury.io/py/ergane.svg)](https://badge.fury.io/py/ergane)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
6
+
7
+ High-performance async web scraper with HTTP/2 support, built with Python.
8
+
9
+ *Named after Ergane, Athena's title as goddess of crafts and weaving in Greek mythology.*
10
+
11
+ ## Features
12
+
13
+ - **HTTP/2 Support** - Fast concurrent connections via httpx
14
+ - **Rate Limiting** - Per-domain token bucket throttling
15
+ - **Retry Logic** - Exponential backoff (max 3 attempts)
16
+ - **robots.txt Compliance** - Respects crawler directives by default
17
+ - **Fast HTML Parsing** - Selectolax with CSS selector extraction (16x faster than BeautifulSoup)
18
+ - **Smart Scheduling** - Priority queue with URL deduplication
19
+ - **Parquet Output** - Efficient columnar storage via polars
20
+ - **Graceful Shutdown** - Clean termination on SIGINT/SIGTERM
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ pip install ergane
26
+ ```
27
+
28
+ For development:
29
+
30
+ ```bash
31
+ pip install ergane[dev]
32
+ ```
33
+
34
+ ## Quick Start
35
+
36
+ ```bash
37
+ # Crawl a single site
38
+ ergane -u https://example.com -n 100
39
+
40
+ # Crawl multiple start URLs
41
+ ergane -u https://site1.com -u https://site2.com -n 500
42
+
43
+ # Custom output and settings
44
+ ergane -u https://docs.python.org -n 50 -c 20 -r 5 -o python_docs.parquet
45
+ ```
46
+
47
+ ## CLI Options
48
+
49
+ | Option | Short | Default | Description |
50
+ |--------|-------|---------|-------------|
51
+ | `--url` | `-u` | required | Start URL(s), can specify multiple |
52
+ | `--output` | `-o` | `output.parquet` | Output file path |
53
+ | `--max-pages` | `-n` | `100` | Maximum pages to crawl |
54
+ | `--max-depth` | `-d` | `3` | Maximum crawl depth from start URLs |
55
+ | `--concurrency` | `-c` | `10` | Concurrent requests |
56
+ | `--rate-limit` | `-r` | `10.0` | Requests per second per domain |
57
+ | `--timeout` | `-t` | `30.0` | Request timeout in seconds |
58
+ | `--same-domain` | | `true` | Stay on same domain as start URLs |
59
+ | `--any-domain` | | `false` | Follow links to any domain |
60
+ | `--ignore-robots` | | `false` | Ignore robots.txt restrictions |
61
+
62
+ ## Output Format
63
+
64
+ Results are saved as a Parquet file with the following schema:
65
+
66
+ | Column | Type | Description |
67
+ |--------|------|-------------|
68
+ | `url` | string | Page URL |
69
+ | `title` | string | Page title |
70
+ | `text` | string | Extracted text content (max 10k chars) |
71
+ | `links` | string | JSON array of extracted links |
72
+ | `extracted_data` | string | JSON object of custom extractions |
73
+ | `crawled_at` | string | ISO timestamp |
74
+
75
+ Read results with polars:
76
+
77
+ ```python
78
+ import polars as pl
79
+
80
+ df = pl.read_parquet("output.parquet")
81
+ print(df.head())
82
+ ```
83
+
84
+ ## Benchmarks
85
+
86
+ Ergane uses selectolax for HTML parsing, which is significantly faster than BeautifulSoup:
87
+
88
+ | Operation | Selectolax | BS4 + lxml | Speedup |
89
+ |-------------------|------------|------------|---------|
90
+ | Parse (small) | 0.05ms | 0.11ms | 2.0x |
91
+ | Parse (large) | 0.19ms | 6.05ms | 31.1x |
92
+ | Extract title | 0.20ms | 6.06ms | 30.7x |
93
+ | Extract links | 0.25ms | 6.73ms | 27.3x |
94
+ | Extract text | 0.29ms | 7.03ms | 24.5x |
95
+ | CSS selector | 0.20ms | 7.25ms | 35.7x |
96
+
97
+ **Average: 16x faster** (1000 iterations, 34KB HTML)
98
+
99
+ Run the benchmark:
100
+ ```bash
101
+ pip install beautifulsoup4 lxml
102
+ python benchmarks/parse_benchmark.py
103
+ ```
104
+
105
+ ## License
106
+
107
+ MIT