├── modules ├── __init__.py ├── colors.py ├── results.py ├── malshare.py ├── malcode.py ├── google.py └── cymon.py ├── README.md └── ddom.py /modules/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /modules/colors.py: -------------------------------------------------------------------------------- 1 | class bcolors: 2 | HEADER = '\033[95m' 3 | OKBLUE = '\033[94m' 4 | OKGREEN = '\033[92m' 5 | WARNING = '\033[93m' 6 | FAIL = '\033[91m' 7 | ENDC = '\033[0m' 8 | BOLD = '\033[1m' 9 | UNDERLINE = '\033[4m' 10 | -------------------------------------------------------------------------------- /modules/results.py: -------------------------------------------------------------------------------- 1 | from urllib.parse import urlparse 2 | import urllib 3 | 4 | 5 | def download(url, directory): 6 | try: 7 | path = urlparse(url).path # parse url 8 | filename = path.split("/") # split it to list 9 | if filename[-1] == "": # if there is no file and extension, it's html site 10 | print(url + "is not executable file, may be phishing site") 11 | else: # else download 12 | urllib.request.urlretrieve(url, directory + "/" + filename[-1]) 13 | print("Downloaded " + directory + "/" + filename[-1]) 14 | except IOError as e: 15 | print(e) 16 | 17 | 18 | def output(dictionary): 19 | print("------------------") 20 | for key, value in dictionary.items(): 21 | if isinstance(value, list): 22 | 23 | # if list as a value in dictionary 24 | for j in value: 25 | print(j) 26 | print(key) 27 | else: 28 | print(value) 29 | print(key) 30 | 31 | print("-----------------") 32 | 33 | 34 | def export(directory, dictionary): 35 | with open(directory + '.txt', "w") as out: # create and open fiel with write permissions 36 | for key, value in dictionary.iteritems(): 37 | out.write(key + "|") 38 | if isinstance(value, list): # if list as a value in dictionary 39 | for j in value: 40 | out.write(j + "|") 41 | else: 42 | out.write(value) 43 | out.write("\n") 44 | -------------------------------------------------------------------------------- /modules/malshare.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import os 3 | import datetime 4 | from .results import download 5 | from .colors import bcolors 6 | 7 | timestamp_now = datetime.datetime.now().strftime('%Y-%m-%d') 8 | 9 | headers = { 10 | 'User-Agent': "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36" 11 | } 12 | 13 | 14 | def malshare(export_bool=False, download_bool=False, output_bool=False): 15 | print("++++++++++++++++++++++++++++++++++++") 16 | print(bcolors.OKBLUE + "Brought to you by Malshare\n" \ 17 | "A free Malware repository providing researchers access to samples, malicous feeds, and Yara results.\n" \ 18 | "http://malshare.com" + bcolors.ENDC) 19 | print("++++++++++++++++++++++++++++++++++++") 20 | 21 | api = "" 22 | 23 | req = requests.get("http://www.malshare.com/api.php?api_key=" + api + "&action=getsourcesraw", 24 | headers=headers) # make api request 25 | directory = "malshare" + timestamp_now 26 | 27 | content = req.content.split() # split response to array by \n 28 | 29 | if download_bool: 30 | try: 31 | os.mkdir(directory) 32 | except OSError: 33 | pass 34 | finally: 35 | for i in content: 36 | print("Downloading file " + i) 37 | 38 | download(i, directory) 39 | print("---------------------------") 40 | 41 | elif export_bool: 42 | try: 43 | with open(directory + ".txt", "w") as out: 44 | for i in content: 45 | out.write(i + "|") 46 | print("Exported to " + directory + '.txt') 47 | except OSError as e: 48 | print(e.strerror) 49 | 50 | elif output_bool: 51 | 52 | print(req.content) 53 | 54 | else: 55 | print("Please specify: --download or --export or --output") 56 | -------------------------------------------------------------------------------- /modules/malcode.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from bs4 import BeautifulSoup 3 | import datetime 4 | import os 5 | from .results import * 6 | from .colors import bcolors 7 | 8 | timestamp_now = datetime.datetime.now().strftime('%Y-%m-%d') 9 | 10 | headers = { 11 | 'User-Agent': "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36" 12 | } 13 | 14 | 15 | def malcode(export_bool=False, download_bool=False, output_bool=False): 16 | print(bcolors.OKBLUE + "++++++++++++++++++++++++++++++++++++") 17 | print("Brought to you by Malc0de\n" \ 18 | "https://twitter.com/malc0de\n" \ 19 | "http://malc0de.com") 20 | print("++++++++++++++++++++++++++++++++++++" + bcolors.ENDC) 21 | info = dict() 22 | req = requests.get("http://malc0de.com/database/", headers=headers) # make request to malcode database 23 | soup = BeautifulSoup(req.text, "lxml") 24 | table = soup.find("table", {"class": "prettytable"}) # find table responsible for keeping information 25 | guard = 0 26 | directory = "malcode" + timestamp_now 27 | 28 | for row in table.findAll("tr"): # for every row in table 29 | if guard > 0: # first row is empty 30 | cells = row.findAll("td") # for every cell in table 31 | 32 | url = cells[1].text # get url 33 | info.update({url: [cells[0].find(text=True), cells[6].find(text=True)]}) # update dict {url: [date,md5] } 34 | 35 | guard = +1 # row is 1++ 36 | 37 | if export_bool: 38 | try: 39 | export(directory, info) 40 | print("Exported to " + directory + '.txt') 41 | except OSError as e: 42 | print("Error " + e.strerror) 43 | 44 | elif download_bool: 45 | try: 46 | os.mkdir(directory) 47 | except OSError as e: 48 | print(e) 49 | finally: 50 | for i in info.keys(): 51 | print("Downloading file " + i) 52 | download("http://" + i, directory) 53 | print("---------------------------") 54 | 55 | elif output_bool: 56 | output(info) 57 | 58 | else: 59 | print("Please specify: --download or --export or --output") 60 | -------------------------------------------------------------------------------- /modules/google.py: -------------------------------------------------------------------------------- 1 | import pyvirtualdisplay 2 | from selenium import webdriver 3 | import datetime 4 | from .results import export 5 | from .colors import bcolors 6 | 7 | timestamp_now = datetime.datetime.now().strftime('%Y-%m-%d') 8 | 9 | 10 | def google(export_bool=False, output_bool=False): 11 | dorks = {"Pony": ["intitle:Authorization inurl:panel*/admin.php intext:Authorization. Sign in.", 12 | "intitle:Authorization inurl:panel*/*admin.php", 13 | "intitle:Authorization inurl:*admin.php Authorization. User Password Save password. Login. TF."], 14 | "WannaCry": "intitle:\"index of\" \"@Please_Read_Me@.txt", 15 | "Stealer": "intitle:\"(c) Bilal Ghouri\"", 16 | "LokiBot": "inurl:PvqDq929BSx_A_D_M1n_a.php intitle:Auth", 17 | "1ms0rry": "intitle:1ms0rry MINERPANEL", 18 | "SpyEye": "intitle:FRMCP intext:Please, enter password"} 19 | 20 | print(bcolors.OKBLUE + "++++++++++++++++++++++++++++++++++") 21 | print("Google dorks") 22 | print("++++++++++++++++++++++++++++++++++" + bcolors.ENDC) 23 | 24 | info = {} 25 | links_list = [] 26 | 27 | display = pyvirtualdisplay.Display(visible=0, size=(800, 600)) 28 | display.start() 29 | 30 | directory = "google" + timestamp_now 31 | # now Firefox will run in a virtual display. 32 | # you will not see the browser. 33 | browser = webdriver.Firefox() 34 | for i in dorks.keys(): # for every dork in dictionary 35 | if i == "Pony": # for Pony is more than one dork 36 | for j in dorks[i]: 37 | browser.get('http://www.google.com/search?q=' + j + "&t=h_&ia=web") 38 | links = browser.find_elements_by_xpath("//h3//a[@href]") 39 | for elem in links: 40 | link = elem.get_attribute("href") 41 | links_list.append(link) 42 | info.update({i: links_list}) 43 | links_list = [] 44 | 45 | else: 46 | browser.get('http://www.google.com/search?q=' + dorks[i] + "&t=h_&ia=web") 47 | links = browser.find_elements_by_xpath("//h3//a[@href]") 48 | for elem in links: 49 | link = elem.get_attribute("href") 50 | links_list.append(link) 51 | 52 | info.update({i: links_list}) 53 | links_list = [] 54 | 55 | if export_bool: 56 | try: 57 | export(directory, info) 58 | print("Exported to " + directory + '.txt') 59 | except OSError as e: 60 | print("Error " + e.strerror) 61 | 62 | elif output_bool: 63 | for i in info: 64 | print("-----------------------------") 65 | print(i) 66 | for j in info[i]: 67 | print(j) 68 | print("-----------------------------") 69 | 70 | else: 71 | print("Please add --output or --export") 72 | 73 | browser.quit() 74 | 75 | display.stop() 76 | -------------------------------------------------------------------------------- /modules/cymon.py: -------------------------------------------------------------------------------- 1 | from .results import * 2 | import requests 3 | import json 4 | import datetime 5 | import os 6 | from .colors import bcolors 7 | 8 | timestamp_now = datetime.datetime.now().strftime('%Y-%m-%d') 9 | 10 | headers = { 11 | 'User-Agent': "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36" 12 | } 13 | 14 | 15 | def cymon(params=None, export_bool=False, download_bool=False, output_bool=False): 16 | # Params must be list 17 | if params is None: 18 | params = [] 19 | 20 | # Dict with source and feed's id 21 | feeds = {"malcode": "AVsGX4iNVjrVcoBZyoiH", "ponyc2": "AVy8uj-LEb4shFlhGDGG", "cct": "AVsIOKQlVjrVcoBZyojw", 22 | "vxvault": "AVsGgHxAVjrVcoBZyoiX"} 23 | 24 | # Dict with source and description 25 | desc = { 26 | "malcode": bcolors.OKBLUE + "Brought to you by Malc0de\n""https://twitter.com/malc0de\n""http://malc0de.com" + bcolors.ENDC, 27 | "ponyc2": bcolors.OKBLUE + "Cybercrime Tracker for Pony malware" + bcolors.ENDC, 28 | "cct": bcolors.OKBLUE + "cybercrime-tracker.net\n""Officially active from 2012, Cyber Crime Tracker monitors and tracks various malware families that are used to perpetrate cyber crimes, such as banking trojans and ransomware." + bcolors.ENDC, 29 | "vxvault": bcolors.OKBLUE + "http://vxvault.net" + bcolors.ENDC} 30 | 31 | info = {} # output dictionary 32 | 33 | # c=0, source = malcode 34 | print(bcolors.OKBLUE + "Cymon is the largest open tracker of malware, phishing, botnets, spam, and more. Brought to you by eSentire." + bcolors.ENDC) 35 | for counter, source in enumerate(params): 36 | 37 | if source not in feeds.keys(): 38 | print("Unrecognized parameter: " + source) 39 | break 40 | directory = source + timestamp_now # making directory (source) with timestamp 41 | 42 | # if there is "source" (passed args.cs) in feeds dictionary, first - source = malcode 43 | if source in feeds: 44 | req = requests.get("https://api.cymon.io/v2/ioc/search/feed/" + feeds[ 45 | source] + "?startDate=1990-01-01&endDate=" + timestamp_now + "&from=0&size=10", 46 | headers=headers) # Make request to api 47 | 48 | content = json.loads(req.text) # load response 10 LAST RESULTS!!!!! 49 | 50 | hits = content["hits"] 51 | 52 | for i in hits: # for i in all data from source 53 | 54 | date = i['timestamp'][0:10] # take date in format %YYYY-%MM-%%DD 55 | 56 | url = i["ioc"]["url"] # take url 57 | info.update({url: date}) # add to dict 58 | if 'md5' in i["ioc"].keys(): # if there is associated md5 hash, add it to dict as well 59 | md5 = i["ioc"]["md5"] 60 | info.update({url: [date, md5]}) # update dict in format {dict:[date, md5]} 61 | else: # if not md5 is present, continue 62 | continue 63 | 64 | if export_bool: # if -e or --export 65 | try: 66 | export(directory, info) # call function 67 | print("Exported to " + directory) 68 | except OSError as e: # in case of error 69 | print("Error " + e.strerror) 70 | 71 | elif download_bool and source == "vxvault" or source =="malcode": # if -d or --download and only source with files is vxvault 72 | try: 73 | os.mkdir(directory) # make directory with source + timestamp 74 | except OSError as e: # in case of error like file exists 75 | print("Problem with file: " + directory + e.strerror) 76 | print("If exists continue") 77 | finally: # if exist we continue and do not make another one 78 | for i in info.keys(): # for i in urls 79 | print("Downloading file " + i) 80 | download(i, directory) # call function 81 | print("---------------------------") 82 | 83 | elif output_bool: 84 | print("++++++++++++++++++++++++++++++") 85 | print(desc[source]) 86 | print("++++++++++++++++++++++++++++++") 87 | output(info) 88 | 89 | else: 90 | print("Please specify: --download or --export or --output") 91 | 92 | info = {} 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Daily dose of malware 2 | DDOM or Daily Dose of Malware allows you to gather malware and c&c from open source intelligence.\ 3 | It can display info, export results to text file or download malicious software.\ 4 | I want to make it as fresh as possible, that's why all malwares are dated on few days back.\ 5 | Cymon displays last ten records, Google shows only first page and Malcode only main page.\ 6 | Malshare API is updated, if new sample appears. 7 | 8 | Supported platforms:\ 9 | [Malcode](http://malc0de.com/)\ 10 | [Malshare](https://malshare.com/) (You need to get api key)\ 11 | Google dorks\ 12 | [Cymon](https://cymon.io/)\ 13 | -[Vx vault](http://vxvault.net/)\ 14 | -[CyberCrime tracker](http://cybercrime-tracker.net/)\ 15 | -CybeCrime tracker for Pony malware (mostly c2 servers)\ 16 | -Malcode 17 | 18 | ## Installation 19 | First clone this repo\ 20 | `git clone`\ 21 | For google dorks:\ 22 | `pip install selenium`\ 23 | `pip install pyvirtualdisplay` 24 | 25 | **and you need Mozilla Geckodriver https://github.com/mozilla/geckodriver/releases** 26 | 27 | for Malcode: 28 | 29 | `pip install bs4` 30 | 31 | You can run the tool with `python ddom.py` 32 | 33 | ``` 34 | usage: ddom.py [-h] [-s [[...]]] [-cs [[...]]] [-d | -o | -e] 35 | 36 | Daily dose of malware 37 | 38 | optional arguments: 39 | 40 | -h, --help show this help message and exit 41 | -s [ [ ...]], --source [ [ ...]] 42 | source of feed. Allowed values are cymon, malshare, 43 | malcode, google 44 | -cs [ [ ...]], --cymonsource [ [ ...]] 45 | Additional source for Cymon. Allowed values are 46 | vxvault,malcode,cct,ponyc2 47 | -d, --download download malware 48 | -o, --output print to console 49 | -e, --export export to text file 50 | ``` 51 | ## Examples 52 | 53 | Display info from malcode and malshare\ 54 | `dom.py -s malcode malshare --output` 55 | 56 | ``` 57 | ++++++++++++++++++++++++++++++++++++ 58 | Brought to you by Malc0de 59 | https://twitter.com/malc0de 60 | http://malc0de.com 61 | ++++++++++++++++++++++++++++++++++++ 62 | ------------------ 63 | 2018-01-10 64 | aba2d86ed17f587eb6d57e6c75f64f05 65 | xxx.xxx.xxx.xxx/Photo.scr 66 | ----------------- 67 | 2018-01-10 68 | 6c29b80a61ff5ca7f5d8db8b002e9631 69 | xxx.xxx/32nP30h187Z 70 | [...] 71 | ++++++++++++++++++++++++++++++++++++ 72 | Brought to you by Malshare 73 | A free Malware repository providing researchers access to samples, malicous feeds, and Yara results. 74 | http://malshare.com 75 | ++++++++++++++++++++++++++++++++++++ 76 | http://xxx.xxx/kjdfhg874 77 | http://xxx.xxx/error/error/tc.exe 78 | http://xxx.xxx/images/rn.php 79 | http://xxx.xxx.xxx.xxx/bprocess.exe 80 | http://xxx.xxx.xxx.xxx/64Kilences.exe 81 | [..] 82 | ``` 83 | 84 | 85 | Download files from vxvault and malcode (--download works for malshare, malcode and vxvault) (**it connects to malicious, be careful**)\ 86 | `ddom.py -s cymon -cs vxvault malcode --download` 87 | ``` 88 | Cymon is the largest open tracker of malware, phishing, botnets, spam, and more. Brought to you by eSentire. 89 | Downloading file http://xxx.xxx/rn.php 90 | Downloaded malcode2018-01-13/rn.php 91 | --------------------------- 92 | Downloading file http://xxx.xxx.xxx.xxx/32Kilences.exe 93 | Downloaded malcode2018-01-13/32Kilences.exe 94 | --------------------------- 95 | Downloading file http://xxx.xxx/dfjkgy7 96 | Downloaded malcode2018-01-13/dfjkgy7 97 | ``` 98 | It creates directory named 'source + timestamp' and then download malware into it. 99 | 100 | 101 | 102 | 103 | Export results from google dorks: 104 | `ddom.py -s google --export` 105 | ``` 106 | ++++++++++++++++++++++++++++++++++ 107 | Google dorks 108 | ++++++++++++++++++++++++++++++++++ 109 | Exported to google2018-01-13.txt 110 | ``` 111 | 112 | It creates text file named 'source + timestamp' with information inside. 113 | 114 | ## IMPORTANT 115 | 1. **You are dealing with real malware, which may harm your computer badly. I'm not responsible for any caused damages. Be careful and think.** 116 | 2. For Google dorks please make sure to use newest firefox and geckodriver. It simulates browser, so it may not working sometimes because of google captcha. My advice is to connect and reconnect your vpn. 117 | 3. To use Malshare, you have to register and obtain api key. Then paste it to modules/malshare.py - line 21 118 | 4. If you know more public and open source platforms for retrieving malware, let me know. 119 | 5. **If this script violates terms of service from any used service, let me know and I will delete it.** 120 | 6. Not all of google dorks are perfect, you may encounter on some false positives. 121 | 122 | ## Licence 123 | Do whatever you want to do with this tool.\ 124 | If you know how to develop or have any idea, let me know. 125 | -------------------------------------------------------------------------------- /ddom.py: -------------------------------------------------------------------------------- 1 | # from torrequest import TorRequest 2 | import argparse 3 | from modules.malshare import malshare 4 | from modules.malcode import malcode 5 | from modules.cymon import cymon 6 | from modules.google import google 7 | from modules.colors import bcolors 8 | 9 | # User-Agent 10 | headers = { 11 | 'User-Agent': "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36" 12 | } 13 | 14 | choices = ["cymon", "malshare", "malcode", "google"] 15 | choices_cymon = ["vxvault", "malcode", "cct", "ponyc2"] 16 | 17 | parser = argparse.ArgumentParser(description='Daily dose of malware') 18 | group = parser.add_mutually_exclusive_group() 19 | parser.add_argument('-s', '--source', type=str, default="", choices=choices, nargs="*", 20 | help='source of feed. Allowed values are ' + ', '.join(choices), metavar='') 21 | 22 | parser.add_argument('-cs', '--cymonsource', type=str, metavar="", default=[], 23 | help='Additional source for Cymon. Allowed values are ' + ",".join(choices_cymon), nargs="*") 24 | 25 | group.add_argument('-d', '--download', help='download malware', action='store_true') 26 | group.add_argument('-o', '--output', help='print to console', action='store_true') 27 | group.add_argument('-e', '--export', help='export to text file', action='store_true') 28 | 29 | args = parser.parse_args() 30 | 31 | 32 | # def tor_req(): 33 | # with TorRequest() as tr: 34 | # response = tr.get('http://ipecho.net/plain') 35 | # print(response.text) # not your IP address 36 | # 37 | # tr.reset_identity() 38 | # 39 | # response = tr.get('http://ipecho.net/plain') 40 | # print(response.text) # another IP address, not yours 41 | 42 | # def minotr(): 43 | # req = requests.get("https://minotr.net/data/recentsamples", headers=headers) 44 | # soup = BeautifulSoup(req.text) 45 | # table = soup.findAll("div", {"class": "col-lg-12 col-md-12 col-sm-12 col-xs-12", "style": "word-break:break-word;"}) 46 | # 47 | # print "Brought to you by The Minotaur Project\n" \ 48 | # "The Minotaur Project is an ongoing research project by the team at NovCon Solutions.\n" \ 49 | # "It is being built as a hub for security professionals, researchers and enthusiasts to discover new threats and discuss mitigations.\n" \ 50 | # "It is a combination of 3rd-party opensource software, local datasets, new analysis tools, and more." \ 51 | # "http://minotr.net" 52 | # print "++++++++++++++++++++++++++++++++++++" 53 | # 54 | # for i in table: 55 | # print i.contents[2].strip() 56 | # print i.contents[4].strip() 57 | # print i.contents[6].strip() 58 | # 59 | # print "-----------------------------------" 60 | 61 | def help(): 62 | print(bcolors.OKGREEN + """. . Daily dose of malware. . . . 63 | . . : . .. :. .___---------___. 64 | Script lets you gather:.. ._".^ .^ ^. '.. :"-_. .+..:. 65 | malicious software ...:/ . .^ :.:\. 66 | and c&c servers .:. :: /: . . . . . .:\:.. 67 | from Open Source :: /: . ^ . . .:\:. 68 | platforms like: :.:. /. . .:\. 69 | Malshare, Malcode,..|: . . ^. .:| 70 | Google,. : ..::... | . . . !:| 71 | Cymon - vxvault:. ::\( . :)/ 72 | cybercrime tracker,.|. ###### .#######::| 73 | and pony c2 : . ::|.####### ..########:| 74 | .. ::. :.... ... :\ ######## :######## :/ 75 | You are dealing :. -.:\ ######## . ########.:/: 76 | with real malware,. :.:\. ####### #######..:/.. 77 | BE CAREFUL! . . : .:..:.\ . . ..:/..:: 78 | . . . .. : -::::.\. | | . .:/::... 79 | ++..: :::. ... :.":. + ::.\ ..:/...::+. 80 | github.com/woj-ciech: .:::.:.\. .:/::..+... 81 | . . . : : ....::_:..:\ ___ :/..:: ..::. 82 | python ddom.py -h for help :.:.:\ :/.:.:...:::: 83 | Detailed usage on github .. .:.|\ .:/|asciiworld.com 84 | . + . . ...:: ..| --.:|:::..+:...:: 85 | example: . . . . . ... :..:.."(....)"..:..: ...:. 86 | python ddom.py -s cymon -cs vxvault ponyc2 --output 87 | python ddom.py -s malshare malcode google --export""" +bcolors.ENDC) 88 | 89 | help() 90 | 91 | calldict = {"malcode": malcode, "cymon": cymon, "malshare": malshare, "google": google} 92 | 93 | if "cymon" in args.source and len(args.cymonsource) > 0: 94 | if args.download: 95 | calldict["cymon"](args.cymonsource, download_bool=True) 96 | elif args.output: 97 | calldict["cymon"](args.cymonsource, output_bool=True) 98 | elif args.export: 99 | calldict["cymon"](args.cymonsource, export_bool=True) 100 | else: 101 | print("\nError Please specify: --download or --export or --output") 102 | 103 | 104 | elif "cymon" in args.source and len(args.cymonsource) == 0: 105 | print("Provide additional feed for Cymon source -cs. Choose from c2 CCPM malcode vxvault") 106 | elif args.source == "": 107 | "Provide source. Choose from cymon google malshare malcode" 108 | else: 109 | try: 110 | for i in args.source: 111 | if args.download: 112 | calldict[i](download_bool=True) 113 | elif args.export: 114 | calldict[i](export_bool=True) 115 | elif args.output: 116 | calldict[i](output_bool=True) 117 | else: 118 | print("\nError Please specify: --download or --export or --output") 119 | 120 | except TypeError as e: 121 | print(e) 122 | --------------------------------------------------------------------------------