|
| 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 |
0 commit comments