Some of the ways that you could do it outside of the solutions proposed in other answers are following:
- With a templating tool like 
Helm where you would template the exact specification of your workload and then iterate over it with different values (see the example) 
- Use the Kubernetes official documentation on work queue topics:
 
Helm example:
Helm in short is a templating tool that will allow you to template your manifests (YAML files). By that you could have multiple instances of Jobs with different name and a different command.
Assuming that you've installed Helm by following guide:
You can create an example Chart that you will modify to run your Jobs:
You will need to delete everything that is in the chart-name/templates/ and clear the chart-name/values.yaml file.
After that you can create your values.yaml file which you will iterate upon:
jobs:
  - name: job1
    command: ['"perl",  "-Mbignum=bpi", "-wle", "print bpi(3)"']
    image: perl
  - name: job2
    command: ['"perl",  "-Mbignum=bpi", "-wle", "print bpi(20)"']
    image: perl
{{- range $jobs := .Values.jobs }}
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ $jobs.name }}
  namespace: default # <-- FOR EXAMPLE PURPOSES ONLY!
spec:
  template:
    spec:
      containers:
      - name: my-container
        image: {{ $jobs.image }}
        command: {{ $jobs.command }}
        securityContext:
          privileged: true
          allowPrivilegeEscalation: true
      restartPolicy: Never
---
{{- end }}
If you have above files created you can run following command on what will be applied to the cluster beforehand:
$ helm template . (inside the chart-name folder) 
---
# Source: chart-name/templates/job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: job1
  namespace: default
spec:
  template:
    spec:
      containers:
      - name: my-container
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(3)"]
        securityContext:
          privileged: true
          allowPrivilegeEscalation: true
      restartPolicy: Never
---
# Source: chart-name/templates/job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: job2
  namespace: default
spec:
  template:
    spec:
      containers:
      - name: my-container
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(20)"]
        securityContext:
          privileged: true
          allowPrivilegeEscalation: true
      restartPolicy: Never
A side note #1!
This example will create X amount of Jobs where each one will be separate from the other. Please refer to the documentation on data persistency if the files that are downloaded are needed to be stored persistently (example: GKE).
A side note #2!
You can also add your namespace definition in the templates (templates/namespace.yaml) so it will be created before running your Jobs.
You can also run above Chart by:
$ helm install chart-name . (inside the chart-name folder) 
After that you should be seeing 2 Jobs that are completed:
NAME         READY   STATUS      RESTARTS   AGE
job1-2dcw5   0/1     Completed   0          82s
job2-9cv9k   0/1     Completed   0          82s
And the output that they've created:
$ echo "one:"; kubectl logs job1-2dcw5; echo "two:"; kubectl logs job2-9cv9k 
one:
3.14
two:
3.1415926535897932385
Additional resources: