Back to guides

Capture screenshots in parallel

Last updated january 25, 2023

ApiFlash can capture multiple screenshots in parallel. Our screenshot API is rate limited based on the number of requests per second and there is no limit on the number of concurrent requests. This means that you can make as many requests as you want in parallel as long as you don't exceed our requests rate limit.

Here are some examples of how to make concurrent requests to our API with various languages.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import concurrent.futures
from urllib.parse import urlencode
from urllib.request import urlopen

access_key = 'YOUR_ACCESS_KEY_HERE'


def capture(url):
    params = urlencode({'access_key': access_key, 'url': url})
    print(f'Capturing {url} ...')
    with urlopen(f"https://api.apiflash.com/v1/urltoimage?{params}") as response:
        if response.status != 200:
            raise Exception(f'Failed to capture screenshot of {url}: {response.read()}')
        print(f'Screenshot of {url} captured.')
        return response.read()


urls_to_capture = ['https://example.com',
                   'https://google.com',
                   'https://twitter.com']

with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    future_to_url = {executor.submit(capture, url): url for url in urls_to_capture}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            filename = url.replace('https://', '') + '.jpeg'
            with open(filename, 'wb') as screenshot_file:
                screenshot_file.write(future.result())
        except Exception as error:
            print(f'{url} generated an exception: {error}')
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
require 'net/http'
require 'uri'

def capture(url)
  access_key = 'YOUR_ACCESS_KEY_HERE'
  uri = URI.parse("https://api.apiflash.com/v1/urltoimage?access_key=#{access_key}&url=#{url}")
  puts "Capturing #{url} ..."
  response = Net::HTTP.get_response(uri)
  if response.code != '200'
    raise "Failed to capture screenshot of #{url}: #{response.body}"
  end
  puts "Screenshot of #{url} captured."
  response.body
end

urls_to_capture = ['https://example.com',
                   'https://google.com',
                   'https://twitter.com']

thread_count = 5
threads = []
urls_to_capture.each_slice(thread_count) do |urls|
  urls.each do |url|
    threads << Thread.new do
      filename = url.gsub('https://', '') + '.jpeg'
      File.open(filename, 'wb') do |file|
        file.write(capture(url))
      end
    end
  end
  threads.each(&:join)
  threads = []
end
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;

public class ApiFlashExample
{
    private const string ApiFlashEndpoint = "https://api.apiflash.com/v1/urltoimage";
    private const string AccessKey = "YOUR_ACCESS_KEY_HERE";

    public static void capture(string url){
        var client = new HttpClient();
        var parameters = new Dictionary<string, string>{
            {"access_key", AccessKey},
            {"url", url}};

        Console.WriteLine("Capturing " + url + " ...");

        var encodedParameters = new FormUrlEncodedContent(parameters).ReadAsStringAsync().Result;
        var response = client.GetAsync(ApiFlashEndpoint + "?" + encodedParameters).Result;
        var filename = url.Replace("https://", "") + ".jpeg";
        var file = System.IO.File.Create(filename);
        response.Content.CopyToAsync(file).Wait();
        file.Close();

        Console.WriteLine("Screenshot of " + url + " captured.");
    }

    public static void Main(string[] args)
    {
        var urls = new List<string>{
            "https://example.com",
            "https://google.com",
            "https://twitter.com"};

        var tasks = new List<Task>();
        foreach (var url in urls)
        {
            tasks.Add(Task.Run(() => capture(url)));
        }

        Task.WaitAll(tasks.ToArray());
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"sync"
)

const accessKey = "YOUR_ACCESS_KEY_HERE"

func capture(url string, wg *sync.WaitGroup, imageCh chan []byte) {
	defer wg.Done()

	request, _ := http.NewRequest("GET", "https://api.apiflash.com/v1/urltoimage", nil)
	query := request.URL.Query()
	query.Add("access_key", accessKey)
	query.Add("url", url)
	request.URL.RawQuery = query.Encode()

	fmt.Printf("Capturing %s ...\n", url)

	client := &http.Client{}
	resp, err := client.Do(request)
	defer resp.Body.Close()

	if err != nil {
		fmt.Printf("Failed to capture screenshot of %s: %s\n", url, err)
		return
	}
	if resp.StatusCode != 200 {
		fmt.Printf("Failed to capture screenshot of %s: %s\n", url, resp.Status)
		return
	}

	fmt.Printf("Screenshot of %s captured.\n", url)
	image, _ := ioutil.ReadAll(resp.Body)
	imageCh <- image
}

func main() {
	var wg sync.WaitGroup
	urlsToCapture := []string{
		"https://example.com",
		"https://google.com",
		"https://twitter.com",
	}
	imageCh := make(chan []byte, len(urlsToCapture))
	for _, url := range urlsToCapture {
		wg.Add(1)
		go capture(url, &wg, imageCh)
	}
	wg.Wait()
	for i := 0; i < len(urlsToCapture); i++ {
		image := <-imageCh
		filename := strings.ReplaceAll(urlsToCapture[i], "https://", "") + ".jpeg"
		f, err := os.Create(filename)
		if err != nil {
			fmt.Printf("Failed to create file %s: %s\n", filename, err)
			continue
		}
		defer f.Close()
		f.Write(image)
	}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import java.io.FileOutputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Paths;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

class Main {

    private static final String ACCESS_KEY = "YOUR_ACCESS_KEY_HERE";
    private static final String APIFLASH_ENDPOINT = "https://api.apiflash.com/v1/urltoimage";

    public static void capture(String url) throws Exception {

        String params = String.format("?access_key=%s&url=%s", ACCESS_KEY, url);
        URL apiUrl = new URL(APIFLASH_ENDPOINT + params);

        System.out.println(String.format("Capturing %s ...", url));

        ReadableByteChannel channel = Channels.newChannel(apiUrl.openStream());
        String fileName = url.replace("https://", "") + ".jpeg";
        FileOutputStream stream = new FileOutputStream(fileName);
        stream.getChannel().transferFrom(channel, 0, Long.MAX_VALUE);
        stream.close();

        System.out.println(String.format("Screenshot of %s captured", url));
    }

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        String[] urlsToCapture = {"https://example.com", "https://google.com", "https://twitter.com"};
        Future[] futures = new Future[urlsToCapture.length];
        for (int i = 0; i < urlsToCapture.length; i++) {
            String url = urlsToCapture[i];
            futures[i] = executor.submit(() -> {
                try {
                    capture(url);
                } catch (Exception e) {
                    System.out.println(url + " generated an exception: " + e.getMessage());
                }
            });
        }
        executor.shutdown();
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const https = require('https');
const fs = require('fs');

const access_key = 'YOUR_ACCESS_KEY_HERE';

async function capture(url) {
    const params = new URLSearchParams({access_key: access_key, url: url}).toString();
    console.log(`Capturing ${url} ...`);
    return new Promise((resolve, reject) => {
        https.get(`https://api.apiflash.com/v1/urltoimage?${params}`, (response) => {
            if (response.statusCode !== 200) {
                reject(`Failed to capture screenshot of ${url}: ${response.statusMessage}`);
            } else {
                console.log(`Screenshot of ${url} captured.`);
                let screenshotData = [];
                response.on('data', (chunk) => {
                    screenshotData.push(chunk);
                });
                response.on('end', () => {
                    resolve(Buffer.concat(screenshotData));
                });
            }
        });
    });
}

const urls_to_capture = [
    'https://example.com',
    'https://google.com',
    'https://twitter.com',
];

(async () => {
    const screenshots = await Promise.all(urls_to_capture.map(url => capture(url)));
    screenshots.forEach((screenshot, index) => {
        const filename = urls_to_capture[index].replace('https://', '') + '.jpeg';
        fs.writeFileSync(filename, screenshot);
    });
})();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php

$access_key = 'YOUR_ACCESS_KEY_HERE';
$urls_to_capture = array(
    'https://example.com',
    'https://google.com',
    'https://twitter.com');

$mh = curl_multi_init();
$handles = array();

foreach ($urls_to_capture as $url) {
    echo "Capturing $url ...\n";
    $handles[$url] = curl_init();
    $params = http_build_query(array('access_key' => $access_key, 'url' => $url));
    curl_setopt($handles[$url], CURLOPT_URL, "https://api.apiflash.com/v1/urltoimage?$params");
    curl_setopt($handles[$url], CURLOPT_RETURNTRANSFER, 1);
    curl_multi_add_handle($mh, $handles[$url]);
}

$running = null;
do {
    curl_multi_exec($mh, $running);
} while ($running > 0);

foreach ($handles as $url => $handle) {
    try {
        $response = curl_multi_getcontent($handle);
        echo "Screenshot of $url captured.\n";
        $filename = str_replace('https://', '', $url) . '.jpeg';
        file_put_contents($filename, $response);
    } catch (Exception $e) {
        echo "$url generated an exception: " . $e->getMessage() . "\n";
    }
    curl_multi_remove_handle($mh, $handle);
}

curl_multi_close($mh);

?>