Skip to content

Commit 9f2e763

Browse files
committed
feat: enhance proxy scraper with additional sources and improve logging system
1 parent 939e679 commit 9f2e763

5 files changed

Lines changed: 61 additions & 44 deletions

File tree

CLAUDE.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ docker-compose up
6565

6666
### Core Components
6767

68-
- **Scraper** (`pkg/scraper/`): Fetches proxy lists from multiple sources (ProxyScrape, FreeProxyList)
69-
- **Checker** (`pkg/checker/`): Validates proxy health with SQLite caching and intelligent check intervals
68+
- **Scraper** (`pkg/scraper/`): Fetches proxy lists from multiple sources (ProxyScrape, FreeProxyList, Geonode, ProxyListOrg, GitHub)
69+
- **Checker** (`pkg/checker/`): Validates proxy health with SQLite caching, intelligent check intervals, and unified logging
7070
- **Manager** (`pkg/manager/`): Manages proxy pool with database persistence, in-memory cache, and auto-refresh
7171
- **Database** (`internal/database/`): SQLite-based persistent storage with Jet ORM for type-safe queries
7272
- **Proxy Server** (`pkg/proxy/`): HTTP/HTTPS proxy server with privacy features
@@ -121,6 +121,13 @@ AProxy uses **Viper** for advanced configuration management with validation:
121121
3. **Config files**: YAML, JSON, TOML supported (searches `./`, `./config/`, `/etc/aproxy/`)
122122
4. **Defaults**: Sensible defaults for all settings
123123

124+
**Supported Scraper Sources:**
125+
- `proxyscrape`: ProxyScrape API
126+
- `freeproxylist`: FreeProxyList scraper
127+
- `geonode`: Geonode API scraper
128+
- `proxylistorg`: ProxyListOrg scraper
129+
- `github`: GitHub proxy list scraper (proxifly/free-proxy-list)
130+
124131
**Configuration Management:**
125132
```bash
126133
# Generate sample config file
@@ -172,6 +179,11 @@ curl -x http://localhost:8080 \
172179
- `checker.max_workers`: Concurrent health check workers (default: `50`)
173180
- `checker.test_url`: URL used to test proxy health (default: `http://icanhazip.com`)
174181

182+
**Scraper Configuration Options:**
183+
- `scraper.sources`: List of proxy sources to use (default: `["proxyscrape", "freeproxylist", "geonode", "github"]`)
184+
- `scraper.timeout`: Request timeout for scraping (default: `30s`)
185+
- `scraper.user_agent`: User agent string for scraper requests
186+
175187
**Logging Configuration:**
176188
- Currently logs to stdout only in JSON format
177189
- Log level can be controlled via command line or environment variables
@@ -205,6 +217,17 @@ The SQLite database includes:
205217

206218
## Recent Improvements
207219

220+
### GitHub Proxy Scraper (v1.2)
221+
- **New GitHub source**: Added scraper for proxifly/free-proxy-list GitHub repository
222+
- **Enhanced source variety**: Now supports 5 different proxy sources for better diversity
223+
- **Configuration validation**: Added `github` to allowed scraper sources in config validation
224+
225+
### Logging System Improvements (v1.2)
226+
- **Unified logging**: Standardized all checker logging to use internal logger package
227+
- **Reduced verbosity**: Removed verbose individual proxy failure debugging output
228+
- **Consistent log levels**: Proper use of InfoBg/WarnBg throughout checker components
229+
- **Better performance**: Less logging overhead during proxy health checks
230+
208231
### Configuration System (v1.1)
209232
- **Migrated to Viper**: Replaced manual config parsing with Viper library
210233
- **Added validation**: All config values validated using `go-playground/validator`

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ docker-compose logs -f
110110

111111
## How It Works
112112

113-
1. **Scraper** fetches proxy lists from multiple free sources (ProxyScrape, FreeProxyList)
113+
1. **Scraper** fetches proxy lists from multiple free sources (ProxyScrape, FreeProxyList, Geonode, ProxyListOrg, GitHub)
114114
2. **Health Checker** validates proxies using configurable test URLs
115115
3. **Database** caches proxy health status to avoid redundant checks
116116
4. **Manager** maintains pool of healthy proxies with automatic rotation
@@ -160,6 +160,12 @@ docker-compose logs -f
160160
- `checker.timeout` - Proxy test timeout (default: `15s`)
161161
- `checker.batch_size` - Proxies per batch (default: `50`)
162162
- `checker.batch_delay` - Delay between batches (default: `30s`)
163+
- `checker.background_enabled` - Enable background proxy checking (default: `true`)
164+
165+
### Scraper Sources
166+
- `scraper.sources` - Proxy sources to use: `proxyscrape`, `freeproxylist`, `geonode`, `proxylistorg`, `github`
167+
- `scraper.timeout` - Scraper request timeout (default: `30s`)
168+
- `scraper.user_agent` - User agent for scraping requests
163169

164170
### Database
165171
- `database.path` - SQLite file location (default: `./data/aproxy.db`)

internal/config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func setDefaults() {
8787
// Scraper defaults
8888
viper.SetDefault("scraper.timeout", "30s")
8989
viper.SetDefault("scraper.user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
90-
viper.SetDefault("scraper.sources", []string{"proxyscrape", "freeproxylist", "geonode"})
90+
viper.SetDefault("scraper.sources", []string{"proxyscrape", "freeproxylist", "geonode", "github"})
9191

9292
// Checker defaults
9393
viper.SetDefault("checker.test_url", "http://icanhazip.com")

pkg/checker/checker.go

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"sync"
1212
"time"
1313

14+
"aproxy/internal/logger"
1415
"aproxy/pkg/scraper"
1516
netproxy "golang.org/x/net/proxy"
1617
)
@@ -53,6 +54,7 @@ type Checker struct {
5354
timeout time.Duration
5455
maxWorkers int
5556
userAgent string
57+
logger *logger.Logger
5658
}
5759

5860
type CheckerConfig struct {
@@ -68,6 +70,7 @@ func NewChecker() *Checker {
6870
timeout: 20 * time.Second,
6971
maxWorkers: 20,
7072
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
73+
logger: logger.New("checker"),
7174
}
7275
}
7376

@@ -77,6 +80,7 @@ func NewCheckerWithConfig(config CheckerConfig) *Checker {
7780
timeout: config.Timeout,
7881
maxWorkers: config.MaxWorkers,
7982
userAgent: config.UserAgent,
83+
logger: logger.New("checker"),
8084
}
8185
}
8286

@@ -150,35 +154,16 @@ func (c *Checker) CheckProxies(ctx context.Context, proxies []scraper.Proxy) []C
150154

151155
var results []CheckResult
152156
healthyCount := 0
153-
failureCounts := make(map[string]int)
154157

155158
for result := range resultQueue {
156159
results = append(results, result)
157160
if result.Status == StatusHealthy {
158161
healthyCount++
159-
} else {
160-
// Count failures by type
161-
errType := result.Status.String()
162-
if result.Error != nil && strings.Contains(result.Error.Error(), "SOCKS proxy not supported") {
163-
errType = "socks_skipped"
164-
}
165-
failureCounts[errType]++
166-
167-
// Log first few failures for debugging (but not SOCKS)
168-
if errType != "socks_skipped" && failureCounts[errType] <= 3 {
169-
fmt.Printf("DEBUG: Proxy %s (%s) failed: %s (error: %v)\n",
170-
result.Proxy.Address(), result.Proxy.Type, result.Status.String(), result.Error)
171-
}
172162
}
173163
}
174164

175-
// Summary of results
176165
if len(results) > 0 {
177-
fmt.Printf("DEBUG: Results - Healthy: %d", healthyCount)
178-
for errType, count := range failureCounts {
179-
fmt.Printf(", %s: %d", errType, count)
180-
}
181-
fmt.Printf(" (total: %d)\n", len(results))
166+
c.logger.InfoBg("Proxy check completed: %d healthy out of %d total", healthyCount, len(results))
182167
}
183168

184169
return results
@@ -471,11 +456,11 @@ func TestSingleProxy(host string, port int) {
471456
checker := NewChecker()
472457
ctx := context.Background()
473458

474-
fmt.Printf("Testing proxy %s:%d...\n", host, port)
459+
checker.logger.InfoBg("Testing proxy %s:%d", host, port)
475460
result := checker.CheckProxy(ctx, proxy)
476461

477-
fmt.Printf("Result: %s (took %v)\n", result.Status.String(), result.ResponseTime)
462+
checker.logger.InfoBg("Result: %s (took %v)", result.Status.String(), result.ResponseTime)
478463
if result.Error != nil {
479-
fmt.Printf("Error: %v\n", result.Error)
464+
checker.logger.WarnBg("Error: %v", result.Error)
480465
}
481466
}

pkg/checker/db_checker.go

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package checker
33
import (
44
"context"
55
"fmt"
6-
"log"
76
"time"
87

98
"aproxy/internal/database"
109
"aproxy/internal/database/models/model"
10+
"aproxy/internal/logger"
1111
"aproxy/pkg/scraper"
1212
)
1313

@@ -18,6 +18,7 @@ type DBChecker struct {
1818
checkInterval time.Duration
1919
batchSize int
2020
batchDelay time.Duration
21+
logger *logger.Logger
2122
}
2223

2324
// NewDBChecker creates a new database-backed checker
@@ -28,6 +29,7 @@ func NewDBChecker(dbService *database.Service, checkInterval time.Duration, batc
2829
checkInterval: checkInterval,
2930
batchSize: batchSize,
3031
batchDelay: batchDelay,
32+
logger: logger.New("db-checker"),
3133
}
3234
}
3335

@@ -39,6 +41,7 @@ func NewDBCheckerWithConfig(dbService *database.Service, checkerConfig CheckerCo
3941
checkInterval: checkInterval,
4042
batchSize: batchSize,
4143
batchDelay: batchDelay,
44+
logger: logger.New("db-checker"),
4245
}
4346
}
4447

@@ -48,7 +51,7 @@ func (c *DBChecker) CheckProxiesWithCaching(ctx context.Context, proxies []scrap
4851
return nil
4952
}
5053

51-
log.Printf("Checking %d proxies with caching (skip if checked within %v)", len(proxies), c.checkInterval)
54+
c.logger.InfoBg("Checking %d proxies with caching (skip if checked within %v)", len(proxies), c.checkInterval)
5255

5356
// Get addresses of all scraped proxies
5457
addresses := make([]string, len(proxies))
@@ -62,12 +65,12 @@ func (c *DBChecker) CheckProxiesWithCaching(ctx context.Context, proxies []scrap
6265
// Get existing proxies from database
6366
existingProxies, err := c.dbService.GetProxiesByAddresses(ctx, addresses)
6467
if err != nil {
65-
log.Printf("Failed to get existing proxies: %v", err)
68+
c.logger.WarnBg("Failed to get existing proxies: %v", err)
6669
// Fall back to checking all proxies
6770
return c.Checker.CheckProxies(ctx, proxies)
6871
}
6972

70-
log.Printf("Found %d existing proxies in database", len(existingProxies))
73+
c.logger.InfoBg("Found %d existing proxies in database", len(existingProxies))
7174

7275
// Separate new proxies that need to be inserted vs existing ones
7376
var newProxies []scraper.Proxy
@@ -88,7 +91,7 @@ func (c *DBChecker) CheckProxiesWithCaching(ctx context.Context, proxies []scrap
8891
for _, proxy := range newProxies {
8992
dbProxy, err := c.dbService.UpsertProxy(ctx, proxy)
9093
if err != nil {
91-
log.Printf("Failed to upsert new proxy %s: %v", proxy.Address(), err)
94+
c.logger.WarnBg("Failed to upsert new proxy %s: %v", proxy.Address(), err)
9295
continue
9396
}
9497
dbProxies = append(dbProxies, dbProxy)
@@ -123,7 +126,7 @@ func (c *DBChecker) CheckProxiesWithCaching(ctx context.Context, proxies []scrap
123126
}
124127
}
125128

126-
log.Printf("Found %d proxies that need checking (out of %d total)", len(proxiesToCheck), len(dbProxies))
129+
c.logger.InfoBg("Found %d proxies that need checking (out of %d total)", len(proxiesToCheck), len(dbProxies))
127130

128131
if len(proxiesToCheck) == 0 {
129132
// All proxies have been checked recently, return cached results
@@ -146,7 +149,7 @@ func (c *DBChecker) CheckProxiesWithCaching(ctx context.Context, proxies []scrap
146149
proxyAddr := result.Proxy.Address()
147150
dbProxy, exists := proxyMap[proxyAddr]
148151
if !exists {
149-
log.Printf("No database proxy found for %s", proxyAddr)
152+
c.logger.WarnBg("No database proxy found for %s", proxyAddr)
150153
continue
151154
}
152155

@@ -188,9 +191,9 @@ func (c *DBChecker) CheckProxiesWithCaching(ctx context.Context, proxies []scrap
188191
// Use longer timeout for database operations
189192
updateCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
190193
if err := c.dbService.BatchUpdateProxyHealth(updateCtx, batchUpdates); err != nil {
191-
log.Printf("Failed to batch update proxy health (batch %d-%d): %v", i, end-1, err)
194+
c.logger.WarnBg("Failed to batch update proxy health (batch %d-%d): %v", i, end-1, err)
192195
} else {
193-
log.Printf("Successfully updated %d proxy health records to database", len(batchUpdates))
196+
c.logger.InfoBg("Successfully updated %d proxy health records to database", len(batchUpdates))
194197
}
195198
cancel()
196199
}
@@ -348,14 +351,14 @@ func (c *DBChecker) checkProxiesProgressive(ctx context.Context, proxies []scrap
348351
var allResults []CheckResult
349352
totalBatches := (len(proxies) + c.batchSize - 1) / c.batchSize
350353

351-
log.Printf("Checking %d proxies in %d batches (batch size: %d, delay: %v)",
354+
c.logger.InfoBg("Checking %d proxies in %d batches (batch size: %d, delay: %v)",
352355
len(proxies), totalBatches, c.batchSize, c.batchDelay)
353356

354357
for i := 0; i < len(proxies); i += c.batchSize {
355358
// Check for cancellation before starting each batch
356359
select {
357360
case <-ctx.Done():
358-
log.Printf("Context cancelled before batch %d/%d, stopping progressive checking", i/c.batchSize+1, totalBatches)
361+
c.logger.WarnBg("Context cancelled before batch %d/%d, stopping progressive checking", i/c.batchSize+1, totalBatches)
359362
return allResults
360363
default:
361364
// Continue with batch
@@ -369,7 +372,7 @@ func (c *DBChecker) checkProxiesProgressive(ctx context.Context, proxies []scrap
369372
batch := proxies[i:end]
370373
batchNum := i/c.batchSize + 1
371374

372-
log.Printf("Checking batch %d/%d (%d proxies)", batchNum, totalBatches, len(batch))
375+
c.logger.InfoBg("Checking batch %d/%d (%d proxies)", batchNum, totalBatches, len(batch))
373376

374377
// Check batch using original checker
375378
batchResults := c.Checker.CheckProxies(ctx, batch)
@@ -380,7 +383,7 @@ func (c *DBChecker) checkProxiesProgressive(ctx context.Context, proxies []scrap
380383
select {
381384
case <-ctx.Done():
382385
// Context cancelled, skip background save
383-
log.Printf("Context cancelled, skipping database save for batch %d", batchNum)
386+
c.logger.WarnBg("Context cancelled, skipping database save for batch %d", batchNum)
384387
default:
385388
// Context still active, save in background
386389
go func(results []CheckResult, batchNumber int) {
@@ -409,7 +412,7 @@ func (c *DBChecker) checkProxiesProgressive(ctx context.Context, proxies []scrap
409412
}
410413
if len(updates) > 0 {
411414
if err := c.dbService.BatchUpdateProxyHealth(saveCtx, updates); err == nil {
412-
log.Printf("Saved batch %d results to database (%d records)", batchNumber, len(updates))
415+
c.logger.InfoBg("Saved batch %d results to database (%d records)", batchNumber, len(updates))
413416
}
414417
}
415418
}
@@ -424,13 +427,13 @@ func (c *DBChecker) checkProxiesProgressive(ctx context.Context, proxies []scrap
424427
healthyCount++
425428
}
426429
}
427-
log.Printf("Batch %d/%d complete. Total healthy so far: %d", batchNum, totalBatches, healthyCount)
430+
c.logger.InfoBg("Batch %d/%d complete. Total healthy so far: %d", batchNum, totalBatches, healthyCount)
428431

429432
// Add delay between batches (except for the last one)
430433
if end < len(proxies) {
431434
select {
432435
case <-ctx.Done():
433-
log.Printf("Context cancelled, stopping progressive checking at batch %d/%d with %d healthy proxies found", batchNum, totalBatches, healthyCount)
436+
c.logger.WarnBg("Context cancelled, stopping progressive checking at batch %d/%d with %d healthy proxies found", batchNum, totalBatches, healthyCount)
434437
return allResults
435438
case <-time.After(c.batchDelay):
436439
// Continue to next batch
@@ -444,7 +447,7 @@ func (c *DBChecker) checkProxiesProgressive(ctx context.Context, proxies []scrap
444447
healthyCount++
445448
}
446449
}
447-
log.Printf("Progressive checking completed: checked %d proxies in %d batches, found %d healthy", len(proxies), totalBatches, healthyCount)
450+
c.logger.InfoBg("Progressive checking completed: checked %d proxies in %d batches, found %d healthy", len(proxies), totalBatches, healthyCount)
448451
return allResults
449452
}
450453

0 commit comments

Comments
 (0)