In this blog article I will introduce my most recent project: The distributed crawling infrastructure which allows to crawl any website with a low-level Http library or a fully fledged chrome browser configured to evade bot detection attempts.
This introduction is divided into three distinct blog articles, because one blog article would be too large to cover this huge topic.
<meta> tags found in the <head> section of the documents.You most likely do not need a distributed crawling infrastructure. If your requirements are to scrape a single website, you can create a simple script that uses lxml and beautifulsoup in the case you program with Python. Alternatively, you could write a Nodejs program that uses puppeteer if you need to orchestrate a real browser. That approach is sufficient for most cases.
However, if you are already an experienced scraping script author, you might have encountered the following limitations:
Summarized, if you want to create multiple, long running and computationally expensive crawling jobs in a concurrent fashion, the distributed crawling infrastructure presented in this article might be for you.
In the following sections, I outline some of the problems and hurdles the crawling infrastructure tackles.
The crawling infrastructure stores crawled data in compressed form in the cloud. Currently, the most used storage solution is AWS S3. But you can store the crawled data in any cloud storage of your choice.
That way you don't have to worry about local storage restrictions.
The crawling infrastructure gives you full choice over the computational resource that executes the crawling code. By default, the crawling worker is executed on AWS Lambda instances, but you could use any other backend such as
A huge contribution of the distributed crawling software is the attempt to obfuscate the automated crawling from bot detection approaches. For that reason, the crawling infrastructure uses the puppeteer controlled chromium browser and configures the browser in such a way that makes it hard for anti-bot techniques and fingerprinting scripts to detect the browser.
A wide array of techniques are used, such as user agent obfuscation, changing of http headers such as Accept-Language, proxy support, setting of chrome command line parameters and much more.
Due to it's design into five distinct components, it is straightforward to debug the crawling infrastructure. Distributed system are complicated by design, therefore, separating such a software in individual components reduces this complexity.
Running your own scaleable crawling infrastructure is only possible if you have access to the following resources:
In order to follow this tutorial, you will at least require an AWS account. We will make use of the following AWS services:
The whole codebase is written in Typescript, which eliminates some of the problems that large nodejs projects inevitably have when they begin to grow. The architecture of the crawling infrastructure is divided into five parts.
The architecture of the crawling infrastructure is quite complex and is summarized in the diagram below:

Now that we have introduced the crawling infrastructure from a theoretical point of view, it's time to start with something practical: We will test the crawler and then create the first simple crawl tasks locally.
Therefore, we won't create a distributed infrastructure just yet. That is saved for the two other parts of this tutorial.
In order to follow this excursion, you will need to have installed the following software:
typescript, installed globally with sudo npm install -g typescriptnpm and yarnIf that is the case, go to cozy place on your local file system and download the crawling infrastructure project with the command:
git clone https://github.com/NikolaiT/Crawling-Infrastructure.git
cd Crawling-Infrastructure/
In order to test the crawler, we use the following commands to create the docker crawler image.
cd crawler/ npm install # install & compile lib cd ../lib npm install tsc cd ../crawler ./build.sh
After the image was successfully built, you can run the integration test with the following command:
mocha --timeout 300000 -r ts-node/register test/integration_tests.ts
The mocha tests should run successfully. If that is the case, we may proceed with running some local crawl tasks against the running docker image.
Now that we have successfully tested the crawler locally, let's see if we can actually crawl a simple url with it.
First launch the docker crawler image in one terminal window with the following command:
docker run -p 4444:4444 --env PORT=4444 tschachn/crawl_worker:latest [DOCKER] Starting X virtual framebuffer using: Xvfb :99 -ac -screen 0 1280x720x16 -nolisten tcp [DOCKER] Starting worker server CrawlWorker[6c279a53f03d] with pid 9 listening on port 4444
And now on a second terminal window, confirm that the crawler docker image is running by issuing the following command:
curl http://localhost:4444/ { "status": 200, "message": "Welcome to CrawlWorker running on 6c279a53f03d", "version": "1.1.5", "author": "Nikolai Tschacher <[email protected]> (https://scrapeulous.com)" }
Everything works fine! Now it's time to crawl a simple website that reflects our IP address. As you can see we pass an empty aws configuration.
curl http://localhost:4444/invokeRequestResponse \ -H "Content-Type: application/json" \ -d '{"API_KEY": "kfTP6E7GgDTtIBZnUQq4skrHGWcuPe1Z", "aws_config": { "AWS_ACCESS_KEY": "", "AWS_SECRET_KEY": "", "AWS_REGION": "", "AWS_BUCKET": "" }, "local_test": true, "function_code": "class Get extends HttpWorker { async crawl(url) { let result = await this.Got(encodeURI(url)); return result.body; } }", "items": ["https://ipinfo.io/json"]}'