|
| 1 | +# Rate Limit / CAPTCHA Page Detection |
| 2 | + |
| 3 | +When crawling, it is often possible to encounter rate limits, CAPTCHAs, or auth pages that are shown instead of valid content that the crawler is intending to capture. |
| 4 | +These 'auth-walled' pages are often implemented for good reason, and bypassing such limits is outside of the scope of the crawler. |
| 5 | + |
| 6 | +However, the crawler can *detect* such pages and avoid archiving 'bad'/undesirable data. |
| 7 | + |
| 8 | +The crawler includes several options to help with this. |
| 9 | + |
| 10 | +When pages are flagged as rate limited, the pages are still loaded in the browser, but the content is not archived. |
| 11 | +Instead, the pages may be queued to be retried at a later time or skipped altogether. |
| 12 | + |
| 13 | +## Flagging Rate Limited / Auth-walled pages |
| 14 | + |
| 15 | +The simplest mechanism for detection is by checking the status code. By default, the crawler now skips all pages that have a 403, 429, or 503 status code. This list can be customized with the `--rateLimitStatusCodes` setting, which accepts a list of status codes to always skip and retry. |
| 16 | + |
| 17 | +The crawler also includes a custom option `--rateLimitOnMatch`, which can take additional values in the form of `<regex>` or `<regex>:<status>`, e.g. `--rateLimitOnMatch <regex-1> --rateLimitOnMatch <regex-2>:<status>`. This setting allows for custom detection of CAPTCHAs and rate-limited pages based on page text content (HTML, JS, etc...), and optionally status code, so even 200 pages can be flagged as rate limited. |
| 18 | + |
| 19 | +## Rate Limit Counters |
| 20 | + |
| 21 | +The crawler also keeps track of how many pages have been flagged as limited during the duration of the crawl, |
| 22 | +by combination of status code and direct fetch/browser-based indicator. These stats are stored in Redis as part of the crawl stats. |
| 23 | + |
| 24 | +The crawler also keeps track of how many pages have been rate limited *within the last N seconds*, set by the `--rateLimitTimeout` and defaulting to 300 seconds (5 minutes). |
| 25 | + |
| 26 | +If a site provides a `Retry-After` header, for example with a 429 response, the header value is used instead of the global default set in `--rateLimitTimeout`. |
| 27 | + |
| 28 | +## Rate Limit Retry Count |
| 29 | + |
| 30 | +By default, rate limited pages are retried indefinitely, allowing the crawl to possibly complete but at a much slower pace. If the pages are blocked due to auth requirements it may be possible to add a browser profile and restart the crawl, allowing for previously flagged pages to be captured successfully. |
| 31 | + |
| 32 | +However, it may be desirable to set a total number of retries for pages flagged as rate limited, which can be done |
| 33 | +by setting `--rateLimitMaxRetries` to a value >= 0, where 0 implies no retries at all. |
| 34 | + |
| 35 | +## Interrupting Crawl on Rate Limit Threshold |
| 36 | + |
| 37 | +By default, the crawler will continue, skipping rate limited pages and retrying them indefinitely, to match existing behavior. |
| 38 | + |
| 39 | +If the `--rateLimitInterruptCount M` flag is set, the crawler will exit with a rate limit exit code (exit code 21) after M rate limited pages within the N seconds, configured via `--rateLimitTimeout`. |
| 40 | + |
| 41 | +This can allow a job runner or other system that starts and monitors the crawler container to implement an exponential backoff system if the crawler repeatedly exits due to being rate limited. |
| 42 | +The Browsertrix application provides this through built-in exponential backoff available in Kubernetes, where the system |
| 43 | +will restart the crawler in increasing intervals if continuously rate limited, up to once every 5 minutes. |
| 44 | + |
| 45 | +Additionally, if direct fetch reaches this threshold, further direct fetches will also be skipped until the timeout expires. |
| 46 | + |
| 47 | +If any page loads successfully, the rate limit counter is cleared. |
| 48 | + |
| 49 | +## Caveats and Multi-Domain Crawling |
| 50 | + |
| 51 | +It should be noted that the rate limits are applied globally and not per seed or per domain, and it may not always be desirable to interrupt a crawl containing many seeds across different domains when a rate limit is reached. |
| 52 | +The rate limit interrupt threshold is disabled by default for this reason. |
| 53 | + |
| 54 | +For multi-domain crawling the threshold could be set to a large number so that if multiple domains are flagged as rate limited the crawl is still interrupted, while for a single domain crawl the number may be set lower. |
| 55 | +It may make sense to set `--rateLimitMaxRetries` to a fixed value so that larger crawls do eventually finish with certain pages skipped as rate limited. |
| 56 | + |
| 57 | +Finally, depending on the reason for the 'auth-wall' on each domain, the crawler may or may not be able to complete the crawl on each domain. |
| 58 | +- For 429 errors and 503 errors, waiting and retrying may be successful. |
| 59 | +- For 403 errors, logging in with a browser profile may provide additional access. |
| 60 | +- Other sites and custom CAPTCHA pages may require additional permission to be allowed to crawl the sites. |
| 61 | + |
| 62 | +If facing repeated errors, requesting permission may be the best approach to successfully crawl a domain. |
0 commit comments