Skip to content

Commit 32f9fb3

Browse files
Add multithreading and Zyte proxy support for faster scraping
Co-authored-by: devinschumacher <45643901+devinschumacher@users.noreply.github.com>
1 parent efdc209 commit 32f9fb3

7 files changed

Lines changed: 499 additions & 50 deletions

File tree

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
# Multithreading and Zyte Proxy Support
2+
3+
This document explains the new concurrency and Zyte proxy features added to the scraper system.
4+
5+
## Overview
6+
7+
The scraper now supports:
8+
1. **Multithreading (Concurrency)**: Process multiple extensions simultaneously
9+
2. **Zyte Rotating Proxies**: Use Zyte's Smart Proxy Manager for faster, more reliable scraping
10+
11+
These features significantly speed up bulk scraping operations while maintaining respectful rate limiting practices.
12+
13+
## Performance Comparison
14+
15+
### Without Concurrency/Proxy (Original)
16+
- **Rate**: ~6-10 seconds per extension (sequential with rate limiting)
17+
- **10,477 extensions**: ~17-29 hours
18+
19+
### With Concurrency (5 workers)
20+
- **Rate**: ~5x faster (5 extensions processed simultaneously)
21+
- **10,477 extensions**: ~3.5-6 hours
22+
23+
### With Concurrency + Zyte Proxy (10 workers)
24+
- **Rate**: ~10x faster (no rate limiting, rotating IPs)
25+
- **10,477 extensions**: ~1.7-3 hours
26+
27+
## Usage
28+
29+
### Enable Concurrency
30+
31+
```bash
32+
# Process 5 extensions at a time
33+
npm run scrape -- -u -c 5
34+
35+
# Maximum parallelism (10 workers)
36+
npm run scrape -- -u -c 10
37+
```
38+
39+
### Enable Zyte Proxy
40+
41+
1. **Get your Zyte API key** from https://www.zyte.com/
42+
2. **Set the environment variable:**
43+
```bash
44+
export ZYTE_API_KEY=your_api_key_here
45+
```
46+
3. **Run with proxy enabled:**
47+
```bash
48+
npm run scrape -- -u -z
49+
```
50+
51+
### Combined: Maximum Speed
52+
53+
```bash
54+
# Set API key
55+
export ZYTE_API_KEY=your_api_key_here
56+
57+
# Run with 10 workers + Zyte proxy
58+
npm run scrape -- -u -c 10 -z
59+
60+
# Or inline:
61+
ZYTE_API_KEY=your_key npm run scrape -- -u -c 10 -z
62+
```
63+
64+
## Command Line Options
65+
66+
```bash
67+
npm run scrape -- [options]
68+
69+
Options:
70+
-c, --concurrency <n> Number of parallel workers (default: 1, max: 10)
71+
-z, --zyte-proxy Enable Zyte rotating proxy
72+
-b, --batch-size <n> Number of extensions per batch (default: 10)
73+
-e, --extensions <list> Comma-separated list of extensions
74+
-u, --update Update existing files
75+
-s, --sources <list> Sources to use
76+
-o, --output <dir> Output directory
77+
```
78+
79+
## How It Works
80+
81+
### Concurrency
82+
83+
- Processes multiple extensions in parallel using `Promise.allSettled()`
84+
- Divides batch into chunks of N extensions (concurrency level)
85+
- Each worker independently scrapes from all 3 sources
86+
- Results are collected and saved as they complete
87+
88+
### Zyte Proxy
89+
90+
- Uses Zyte's Smart Proxy Manager API
91+
- Automatically rotates residential IPs
92+
- Handles CAPTCHAs and bot detection
93+
- Falls back to direct requests if Zyte fails
94+
- No rate limiting needed (proxies handle this)
95+
96+
## Technical Details
97+
98+
### Concurrency Implementation
99+
100+
```typescript
101+
// Sequential (original)
102+
for (const ext of extensions) {
103+
await processSingleExtension(ext, sources);
104+
}
105+
106+
// Parallel (new)
107+
const chunks = chunkArray(extensions, concurrency);
108+
for (const chunk of chunks) {
109+
await Promise.allSettled(
110+
chunk.map(ext => processSingleExtension(ext, sources))
111+
);
112+
}
113+
```
114+
115+
### Zyte Integration
116+
117+
```typescript
118+
// Proxy configuration
119+
interface ProxyConfig {
120+
useProxy: boolean;
121+
apiKey?: string;
122+
}
123+
124+
// Enhanced fetch
125+
async function fetchWithProxy(url, options, proxyConfig) {
126+
if (proxyConfig?.useProxy) {
127+
// Use Zyte API
128+
return await zyteExtract(url, proxyConfig.apiKey);
129+
}
130+
// Direct fetch
131+
return await fetch(url, options);
132+
}
133+
```
134+
135+
## Configuration
136+
137+
Settings in `scripts/config.ts`:
138+
139+
```typescript
140+
export const scraperConfig = {
141+
// Concurrency settings
142+
concurrency: {
143+
enabled: false,
144+
maxWorkers: 5,
145+
useProxy: false,
146+
},
147+
148+
// Zyte proxy configuration
149+
zyte: {
150+
enabled: false,
151+
apiKey: process.env.ZYTE_API_KEY || '',
152+
apiUrl: 'https://api.zyte.com/v1/extract',
153+
},
154+
155+
// ... other settings
156+
};
157+
```
158+
159+
## Best Practices
160+
161+
### For Testing
162+
```bash
163+
# Start small
164+
npm run scrape -- -e pdf,txt,jpg -c 3 -z
165+
```
166+
167+
### For Bulk Scraping
168+
```bash
169+
# Use moderate concurrency
170+
npm run scrape -- -u -c 5 -z -b 50
171+
```
172+
173+
### For Maximum Speed
174+
```bash
175+
# Max workers + Zyte
176+
ZYTE_API_KEY=your_key npm run scrape -- -u -c 10 -z -b 100
177+
```
178+
179+
## Safety Features
180+
181+
1. **Concurrency Cap**: Maximum 10 workers to avoid overwhelming servers
182+
2. **Rate Limiting**: Still applied when not using proxies
183+
3. **Error Handling**: Failed requests don't block others
184+
4. **Graceful Degradation**: Falls back to direct requests if Zyte fails
185+
5. **API Key Validation**: Checks for ZYTE_API_KEY before enabling proxy
186+
187+
## Cost Considerations
188+
189+
### Zyte Pricing
190+
- Pay per successful request
191+
- Residential proxies are more expensive
192+
- Check your Zyte plan limits
193+
- Monitor usage in Zyte dashboard
194+
195+
### Recommendations
196+
- Use concurrency without proxy for moderate speedup (free)
197+
- Add Zyte proxy for maximum speed when needed
198+
- Test with small batches first
199+
- Set batch size based on your Zyte plan
200+
201+
## Troubleshooting
202+
203+
### "Concurrency capped at 10"
204+
This is intentional to prevent overwhelming servers. Adjust if needed in config.
205+
206+
### "ZYTE_API_KEY environment variable is required"
207+
Set your API key:
208+
```bash
209+
export ZYTE_API_KEY=your_actual_api_key
210+
```
211+
212+
### "Zyte API failed, falling back to direct request"
213+
Your Zyte quota might be exceeded or there's an API issue. The scraper continues with direct requests.
214+
215+
### Slow Performance with Concurrency
216+
- Increase batch size: `-b 50` or `-b 100`
217+
- Check network bandwidth
218+
- Verify Zyte proxy is working: `-z` flag
219+
220+
### Rate Limiting Errors
221+
- Reduce concurrency: `-c 3` instead of `-c 10`
222+
- Enable Zyte proxy: `-z`
223+
- Increase batch size to process fewer batches
224+
225+
## Examples
226+
227+
### Scenario 1: Update Popular Formats Quickly
228+
```bash
229+
npm run scrape -- -e pdf,docx,xlsx,jpg,png,mp3,mp4 -c 5 -u
230+
```
231+
232+
### Scenario 2: Full A-Z with Maximum Speed
233+
```bash
234+
export ZYTE_API_KEY=your_key
235+
npm run scrape -- -u -c 10 -z -b 100
236+
```
237+
238+
### Scenario 3: Test New Extensions
239+
```bash
240+
npm run scrape -- -e wav,ogg,flac -c 3
241+
```
242+
243+
### Scenario 4: Scrape Specific Category
244+
```bash
245+
npm run scrape -- -e mp3,wav,ogg,flac,aac,m4a,wma -c 5 -z
246+
```
247+
248+
## Migration from Sequential
249+
250+
**Before:**
251+
```bash
252+
npm run scrape -- -u -b 5 # ~17-29 hours
253+
```
254+
255+
**After (with concurrency):**
256+
```bash
257+
npm run scrape -- -u -c 5 -b 10 # ~3.5-6 hours
258+
```
259+
260+
**After (with Zyte):**
261+
```bash
262+
ZYTE_API_KEY=key npm run scrape -- -u -c 10 -z -b 50 # ~1.7-3 hours
263+
```
264+
265+
## Monitoring
266+
267+
Watch for:
268+
- Success rate in console output
269+
- Zyte dashboard for API usage
270+
- Network bandwidth
271+
- Disk I/O for saving files
272+
273+
## Future Enhancements
274+
275+
Possible improvements:
276+
- Dynamic concurrency adjustment based on success rate
277+
- Multiple Zyte accounts for load distribution
278+
- Request queueing with priority
279+
- Resume from checkpoint on failure
280+
- Real-time progress dashboard
281+
282+
## Support
283+
284+
For issues:
285+
1. Check Zyte dashboard for API errors
286+
2. Verify API key is correct
287+
3. Test with lower concurrency first
288+
4. Review console logs for errors
289+
5. Open GitHub issue with details

apps/files/scripts/config.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,21 @@ export const scraperConfig = {
1717
// Batch processing
1818
defaultBatchSize: 10,
1919

20+
// Concurrency settings
21+
concurrency: {
22+
enabled: false, // Enable parallel scraping
23+
maxWorkers: 5, // Number of concurrent requests per source
24+
useProxy: false, // Use proxy rotation
25+
},
26+
27+
// Zyte proxy configuration
28+
zyte: {
29+
enabled: false, // Enable Zyte proxy
30+
apiKey: process.env.ZYTE_API_KEY || '',
31+
apiUrl: 'https://api.zyte.com/v1/extract',
32+
proxyUrl: `http://${process.env.ZYTE_API_KEY}:@proxy.zyte.com:8011`,
33+
},
34+
2035
// Data directories
2136
dataDir: './public/data/files',
2237
individualDir: './public/data/files/individual',

0 commit comments

Comments
 (0)