Repository: HobnobMancer/cazy_webscraper (language: python)

Issue:
Add rapid scraping
The Kingdom HTML tables only contain 100 proteins per table. As a consequence, the time required to scrape all of CAZy is significantly increased.

To avoid this, if no Kingdoms are specified proteins are retrieved from the HTML tables stored under the 'all' tab for each CAZy family.


Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index 4b0f984f..c42505ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
 # Distribution files
 build/
 dist/
-pyani.egg-info/
+cazy_webscraper.egg-info/
 distribute*
 
 # Compiled Python modules
diff --git a/README.md b/README.md
index 79e3c7fb..85336961 100644
--- a/README.md
+++ b/README.md
@@ -10,12 +10,16 @@
 
 The `cazy_webscraper` is a Python3 package for the automated retrieval of protein data from the [CAZy](http://wwww.cazy.org/) database. This program is free to use under the MIT license when proper recognition is given.
 
-The cazy_webscraper retrieves protein data from CAZy, writing out the data to a dataframe in the same manner as the data is presented in the CAZy website. If enabled, the webscraper will also retrieve the protein sequence of the scraped CAZymes from GenBank, writing out the sequences in FASTA format. Additionally, if enabled the webscraper will retrieve all protein structures for each scraped CAZyme from the Research Collaboratory for Structural Bioinformatics (RCSB) Protein Data Bank [(PDB)](https://www.rcsb.org/).
+The cazy_webscraper retrieves protein data from CAZy, producing a local SQL database which enables uses to throughly interrogate the data in a manner unachievable through the CAZy website.
 
-The cazy_webscraper can be configured to scrape the entire database, selected Classes and/or selected CAZy families. Additionally, the retrieved data can be separated/split by CAZy class, CAZy family or not at all, thus gathering all data into a single dataframe.
+The program additionally, includes an `expand` module, which can retrieve the protein sequences from GenBank and protein structure files from the Research Collaboratory for Structural Bioinformatics (RCSB) Protein Data Bank [(PDB)](https://www.rcsb.org/).
+
+The cazy_webscraper can be configured to scrape the entire database, selected Classes and/or selected CAZy families. An additional taxonomy filter can be applied to restrict the scraping of CAZymes to specific genera, species and/or strains.
 
 _For detailed documentation see the [full documentation](https://cazy-webscraper.readthedocs.io/en/latest/?badge=latest)._
 
+_An ER model can be found in the root of the `cazy_webscraper` GitHub repo, demonstrating the structure of the SQL database create by `cazy_webscraper`._
+
 ## Requirements
 
 POISx or Mac OS, or a Linux emulator  
@@ -53,7 +57,7 @@ Then change directory to the repository root, and use Python's setup tools to in
 
 ```bash
 cd cazy_webscraper
-python setup.py install
+python3 setup.py install
 ```
 
 ## Best practise
@@ -84,20 +88,10 @@ The scraped CAZymes can be written to a single dataframe, or separated out into
 
 The dataframes can be written out to a specified directory or written to STDOUT to facilitate piping to a subsequent program. If the dataframes are written to the disk they are saved as .csv files.
 
-**GenBank synonyms:**  
-Often multiple GenBank accession numbers are listed for a given CAZyme within CAZy. However, only the first listed accession number is hyperlinked to the GenBank database. Examination of the other listed synonyms (referred to as genbank synonyms in the webscraper) shows that these GenBank synonyms are the result of submission of identical protein sequences, splice site and protein isoforms. It has been interpreted that it is the first GenBank accession that is listed and hyperlinked to GenBank is the accession number of protein sequence which was used by CAZy to catalogue the CAZyme and the GenBank synonyms were identified and listed by having extremely high sequence identity to the catalogued CAZyme.
-
-Therefore, the webscraper writes only the first GenBank accession listed for each CAZyme in the resulting dataframe. The remaining GenBank synonyms are written out to a JSON file, keyed by the first GenBank accession given for each CAZyme, and valued by a list of GenBank synonyms. If no GenBank synonyms are retrieved for a CAZyme then the CAZyme’s GenBank accession is not written out to the JSON GenBank synonyms file.
-
-The GenBank synonyms file is written out to the same directory as specificed for the dataframes. Additionally, the data is split as is specified for the dataframes.
-
-**Protein sequences:**  
-
-If enabled, the protein sequence of the scraped CAZymes are retrieved from GenBank are retrieved in the FASTA format and can be written to STDOUT to facilitate piping to a subsequent program or written out to disk, within a specified directory.
-
-**Protein structures:**  
+**Primary and non-primary GenBank accessions:**  
+Often multiple GenBank accession numbers are listed for a given CAZyme within CAZy. However, only the first listed accession number is hyperlinked to the GenBank database. Examination of the other listed synonyms (referred to as genbank synonyms in the webscraper) shows that these GenBank synonyms are the result of submission of identical protein sequences, splice site and protein isoforms. It has been interpreted that it is the first GenBank accession that is listed and hyperlinked to GenBank is the accession number of protein sequence which was used by CAZy to catalogue the CAZyme, and is referred to as the **primary GenBank accession**. The other GenBank accessions are **non-primary GenBank accessions**, and represent protein records in GenBank that have high sequence identity to the catalogued CAZyme.
 
-If enabled, the protein structures will be written out to the disk, to a specified directory. The protein structures cannot be written to STDOUT due to using the BioPython module PDB, which currently does not facilitate writing out the protein structures to STDOUT. The format of the the structure file is specified at the command line.
+CAZy retrieves protein records from GenBank in order to make its own (Lombard _et al_., 2013), therefore, in the local CAZy database created by `cazy_webscraper` each unique CAZyme is identified by its unique **primary GenBank accession**.
 
 
 ## Configuration
@@ -107,28 +101,30 @@ The operation of the `cazy_webscraper` is configured by command-line arguments a
 For the basic invoking of the `cazy_webscraper` use:  
 `python3 cazy_webscraper.py`
 
+
 ### Command line arguments and operation
 
 - `-c` `--config` Path to configuration yaml file
-- `--classes` Define classes to be scraped. Separate classes with a single comma
-- `-d` `--data_split` Split data by CAZy class, CAZy family or not at all
+- `--classes` Define classes to be scraped. Separate classes with a single comma and **no spaces**
+- `-d` `--database` Path to an existing database to add data to
 - `-f` `--force` Force writing out in output directory that already exists
-- `-families` Define families to be scraped. Separate families with a single comma (e.g. GH1,GH2)
+- `-families` Define families to be scraped. Separate families with a single comma (e.g. GH1,GH2) and **no spaces**
+- `genera` Genera to restrict the scrape to. Pass a string of generas separated by a comman and **no spaces**, e.g. `--genera "Trichoderma,Acidianus"`
 - `-g` `--genbank` Entable retrieval of FASTA files, also pass user email
-- `-genbank_output` Specify output directory for FASTA files
-- `-h` `--help` Print option help descriptions
+- `-h` `--help` Print option descriptions
 - `l` `--log` Write a log file, pass file to output log file
 - `n` `--nodelete` Do not delete content present in already existent output directory
 - `o` `--output` Specify output directory for CAZy dataframes
-- `p` `--pdb` Enable retrieval of protein structures from PDB, also pass desired file format of structure files
-- `-pdb_output` Specify output directory for protein structure files
+- `r` `--retries` Number of times to attempt rescraping CAZy families if an error is raised. Default is 0, meaning no reattempted scrapes will be performed. Pass an interger
 - `-s` `--subfamilies` Enable retrieval of subfamilies
+- `--species` Species to restrict the scrape to, this will scrape CAZymes from all strains under the specified species. Pass as a string of species separated by a comma and **no spaces**
+- `--strains` Specific strains of species to limit the scrape to.Pass as a string of species separated by a comma and **no spaces**
 - `-v` `--verbose` Enable verbose logging
 
 
 ### Configuration files
 
-The configuration file is for specifying specific CAZy classes and families to be scraped.
+For shareable documentation of the scraping CAZy a configuration file can by used to specify CAZy classes and families to be scraped.
 
 Under the **classes** heading list any classes to be scrapped. For classes listed under 'classes', all proteins catalogued under that class will be retrieved, unless specific families have been listed under the respective classes heading in the configuration file. Then scraping only the specific classes takes precident and the entire class is not scraped. _If you believe this should be changed please raise an issue. It is invisioned that very few users would want to scrape an entire class an also scrape only specific families from that class simultanious._
 
@@ -153,6 +149,59 @@ Please find more information on writing lists in Yaml files [here](https://docs.
 
 A blank configuration file is packaged within `cazy_webscraper`, within the `scraper` directory, called `scraper_config.yaml`. This configuration file contains comments to assit filling in the file correctly. If a new configuration file is created it **must** be a Yaml file and it **must** use the same headings as used in the configuration file `scraper_config.yaml`.
 
+## Retrieving protein sequences and structure files
+
+The `expand` module in `cazy_webscraper` manages the retrieval of CAZyme protein sequences from GenBank and protein structure files from PDB.
+The `expand` module is invoked to act upon a local CAZy database, not invoked while scraping CAZy.
+
+**Protein Sequences**
+`get_genbank_sequences.py` retrieves protein sequences of CAZymes from GenBank.
+
+To invoke the script use the following command:  
+`python3 <path to get_genbank_sequences.py> <path to local CAZy database> <user email address>`  
+A user email address is not stored by `cazy_webscraper`, it is a requirement of NCBI to use the Entrez server for automating the retrieval of protein sequences from GenBank. For more information about Entrez and NCBI please refer to their documentation...
+
+Optional arguments are: _The format to pass arguments to the script is the same format use to pass the same argument to `cazy_webscraper`_
+- `c` `--config` Define path to a configuration yaml file to define CAZy classes and/or families to retrieve the protein sequences for
+- `--classes` Define CAZy classes to retrieve protein sequences for
+- `-e` `--epost` (Interget) Define the number of accessions to post to NCBI in each batch call. Default is 150. Adviced maximum is 200.
+- `--families` Define CAZy families to retrieve protein sequences for
+- `--genera` Genera of species to retrieve sequences for
+- `l` `--log` Path to write out a log file to
+- `p` `--primary` Default False. If enabled only retrieve protein sequences for **primary** GenBank accessions
+- `--species` Species to retrieve sequences for
+- `--strains` Specific species strains to retrieve sequences for
+- `u` `--update` Default False. Enables overwriting sequences in the database only if the sequence in GenBank has been updated since the sequence was added to the local database. It still retrieves protein sequences for proteins that do not have a sequence stored in the local database.
+- `w` `--write` Write out the protein sequences to FASTA file, one protein per FASTA file
+- `v` `--verbose` Default False. Enables verbose logging, changing the logger level from `WARNING` to `INFO`.
+
+**Protein Structures**
+`get_pdb_structures.py` retrieves protein structure files from PDB. The downloading of the structure files is handled by the `BioPython` `PDB` module, further information on the module can be found [here](https://biopython.org/docs/1.75/api/Bio.PDB.html).
+
+to invoke the script, use the following command:  
+`python3 <path to get_pdb_structures.py> <path to local CAZy database> <file format of downloaded files>`  
+The file formats and descriptions are taken straight from the `BioPython` documentation [found here](https://biopython.org/docs/1.75/api/Bio.PDB.PDBList.html?highlight=pdblist#Bio.PDB.PDBList.PDBList.retrieve_pdb_file).
+- "mmCif" (default, PDBx/mmCif file),
+- "pdb" (format PDB),
+- "xml" (PDBML/XML format),
+- "mmtf" (highly compressed),
+- "bundle" (PDB formatted archive for large structure}
+
+Optional arguments: _The format to pass arguments to the script is the same format use to pass the same argument to `cazy_webscraper`_
+- `c` `--config` Define path to a configuration yaml file to define CAZy classes and/or families to retrieve the protein sequences for
+- `--classes` Define CAZy classes to retrieve protein structures for
+- `--families` Define CAZy families to retrieve protein structures for
+- `--genera` Genera of species to retrieve sequences for
+- `f` `--force` Force writing to directory that already exists
+- `l` `--log` Path to write out a log file to
+- `n` `--nodelete` Default False. If enables it stops content in the existing output directory being deleted, else the contents in the existing output directory are deleted first before proceeding
+- `o` `--outdir` Default is the current working directory. Define path to output directory. If the output directory does not exist the program will create it.
+- `p` `--primary` Default False. If enabled only retrieve protein structures for **primary** GenBank accessions
+- `--species` Species to retrieve sequences for
+- `--strains` Specific species strains to retrieve sequences for
+- `v` `--verbose` Default False. Enables verbose logging, changing the logger level from `WARNING` to `INFO`.
+
+
 ## Directories
 
 Below is a directory plan of this repository, followed by a brief overview of each directories role , to facilitate navigation through the repository. This structure is the same structre found within the `cazy_webscraper` program.
@@ -167,20 +216,21 @@ This directory houses all modules and Python scripts of the webscraper.
 
 `cazy_webscraper.py` is the entry point of the program.
 
+`crawler` is the module that coordinates crawling through the CAZy website and parsing retrived data.
+
 `utilties` contains functions for building cmd-line args parsers and loggers.
 
 `file_io` contains all functions related to handingling input/ouput files and directories, this includes creating the output directory, parsing configuraiton files and writing the output dataframes.
 
 `parse` contains functions related to parsing the protein data retrieved from CAZy into Pandas dataframes.
 
+`expand` is the module for expanding the retrieved CAZyme data from CAZy beyond what can be retrieved directly from CAZy.
+Specifically, the module enables retrieving protein sequences from GenBank and protein structure files from RSCB/PDB.
+
 ### tests
 
 This directory contains all the unit tests for the webscraper. These tests are designed to be invoked from the root directory of the repository.
 
 ## Development and issues
 
-This webscraper is still in early development and is not fully opperational yet. Furthermore, additional features may be added later, such as ability to configure the webscraper to only scrape the data for a single CAZy class instead of scraping the entire database.
-
-For more information on planning/development please see the Wiki.
-
-If you have additional features wish to be added or any other issues please raise and issue in this repoistory.
+If you have any issues or wish to see an additional feature added to `cazy_webscraper` please raise an _issue_ on GitHub.
diff --git a/requirements-dev.txt b/requirements-dev.txt
index afc96388..fc9ca60d 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -3,7 +3,6 @@ bandit
 black
 coverage
 flake8
-lxml
 mypy
 pydocstyle
 pycodestyle
@@ -12,4 +11,3 @@ pytest
 pytest-cov
 pytest-ordering
 sphinx
-sqlalchemy==1.3.20
diff --git a/scraper/__init__.py b/scraper/__init__.py
index 7252861c..5d3cc0e4 100644
--- a/scraper/__init__.py
+++ b/scraper/__init__.py
@@ -1,5 +1,7 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
 # Author:
 # Emma E. M. Hobbs
 
@@ -16,4 +18,22 @@
 # UK
 
 # The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
 """Web scraper to scrape the CAZy website."""
diff --git a/scraper/cazy_webscraper.py b/scraper/cazy_webscraper.py
index c49fb052..d8630e04 100644
--- a/scraper/cazy_webscraper.py
+++ b/scraper/cazy_webscraper.py
@@ -1,5 +1,7 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
 # Author:
 # Emma E. M. Hobbs
 
@@ -16,28 +18,48 @@
 # UK
 
 # The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
 """
 Web scraper to scrape CAZy website and retrieve all protein data.
 
 :cmd_args --config: path to configruration file
-:cmd args --data_split: [None, class, family] how data is to be split/separated into dataframes
+:cmd_args --classes: specify CAZy classes to scrape
+:cmd_args --database: provide path to a local SQL database to add additional data to
+:cmd_args --families: specify CAZy families to retrieve CAZymes from
 :cmd_args --force: force overwriting content in exisiting output directory
+:cmd_args --genera: specify Genera to retrieve CAZymes from
+:cmd_args --kingdoms: specify taxonomy Kingdoms to scrape proteins from
 :cmd_args --log: path to log file, enables writing out log messages to a log file
 :cmd_args --nodelete: if true does not delete content in pre-existing output directory
 :cmd_args --output: path to output directory
-:cmd_args --subfamily: enable retrieval of subfamilies from CAZy
+:cmd_args --retries: specify the number of times to try scraping a page if connection fails
+:cmd_args --subfamilies: enable retrieval of subfamilies from CAZy
+:cmd_args --species: specify species to retrieve CAZymes from
+:cmd_args --strains: specify specific strains of species to retrieve CAZymes from
+:cmd_args --timeout: specify the maximum time (in seconds) before determining connection timed out
 :cmd_args --verbose: change logger level from warning to info, verbose logging
-
-:func main: coordinate scraping of CAZy database
-:func get_class_urls: retrieve URLs to CAZy class summary pages from CAZy homepage
-:func browser_decorator: decorator for get_page() to coordinate retrying failed connections
-:func get_page: connect to webpage and retrieval page as BeautifulSoup4 object
-
-:class Protein: A single protein from CAZy database
-:class Family: A single family from CAZy containing proteins
 """
 
+
 import logging
+import os
 import sys
 
 import pandas as pd
@@ -47,7 +69,9 @@
 
 from tqdm import tqdm
 
-from scraper import crawler, file_io, sql, utilities
+from scraper import crawler
+from scraper.sql import sql_orm
+from scraper.utilities import config_logger, file_io, parsers, parse_configuration
 
 
 def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = None):
@@ -64,46 +88,60 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
     start_time = pd.to_datetime(start_time)
 
     if argv is None:
-        parser = utilities.build_parser()
+        parser = parsers.build_parser()
         args = parser.parse_args()
     else:
-        args = utilities.build_parser(argv).parse_args()
+        parser = parsers.build_parser(argv)
+        args = parser.parse_args()
 
     if logger is None:
-        logger = utilities.build_logger("cazy_webscraper", args)
+        logger = logging.getLogger(__name__)
+        config_logger(args)
+
     logger.info("Run initiated")
 
     if args.output is not sys.stdout:
-        file_io.make_output_directory(args.output, logger, args.force, args.nodelete)
-
-    if args.genbank is not None:
-        # create directory to write FASTA files to
-        if (args.genbank_output is not sys.stdout) and (args.genbank_output != args.output):
-            file_io.make_output_directory(args.genbank_output, logger, args.force, args.nodelete)
-
-    if (args.pdb is not None) and (args.pdb_output != args.output):
-        # create directory to write structure files to
-        file_io.make_output_directory(args.pdb_output, logger, args.force, args.nodelete)
+        file_io.make_output_directory(args.output, args.force, args.nodelete)
 
     if args.subfamilies is True:
         logger.warning("Enabled to retrieve subfamilies")
 
-    max_tries = args.retries + 1  # maximum number of times to try scraping a CAZy
-
     # build database and return open database session
-    try:
-        session = sql.build_db(time_stamp, args, logger)
-    except Exception:
-        logger.error("Failed to build SQL database. Terminating program", exc_info=1)
-        sys.exit(1)
+    if args.database is not None:  # open session for existing local database
+        # check the path exists
+        if os.path.isfile(args.database) is False:
+            logger.error(
+                "Could not find local CAZy database. Check path is correct. Terminating programme."
+            )
+            sys.exit(1)
+        try:
+            session = sql_orm.get_db_session(args)
+        except Exception:
+            logger.error("Failed to build SQL database. Terminating program", exc_info=True)
+            sys.exit(1)
+
+    else:  # create a new empty database to populate
+        try:
+            session = sql_orm.build_db(time_stamp, args)
+        except Exception:
+            logger.error("Failed to build SQL database. Terminating program", exc_info=True)
+            sys.exit(1)
 
     # retrieve configuration data
-    file_io_path = file_io.__file__
-    excluded_classes, config_dict, cazy_dict = file_io.parse_configuration(
-        file_io_path,
-        args,
-        logger,
-    )
+    parse_configuration_path = parse_configuration.__file__
+    (
+        excluded_classes,
+        config_dict,
+        cazy_dict,
+        taxonomy_filters,
+        kingdoms,
+    ) = parse_configuration.parse_configuration(parse_configuration_path, args)
+
+    # log scraping of CAZy in local db
+    log_scrape_in_db(time_stamp, config_dict, taxonomy_filters, kingdoms, session, args)
+
+    # convert taxonomy_filters to a set for quicker identification of species to scrape
+    taxonomy_filters = get_filter_set(taxonomy_filters)
 
     logger.info(
         "Finished program preparation. Starting retrieval of data from CAZy"
@@ -116,10 +154,10 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
         excluded_classes,
         config_dict,
         cazy_dict,
-        max_tries,
+        taxonomy_filters,
+        kingdoms,
         time_stamp,
         session,
-        logger,
         args,
     )
 
@@ -148,10 +186,10 @@ def get_cazy_data(
     excluded_classes,
     config_dict,
     cazy_dict,
-    max_tries,
+    taxonomy_filters,
+    kingdoms,
     time_stamp,
     session,
-    logger,
     args,
 ):
     """Coordinate retrieval of data from the CAZy website.
@@ -163,14 +201,16 @@ def get_cazy_data(
     :param excluded_classes: list, list of classes to not scrape from CAZy
     :param config_dict: dict, user defined configuration of the scraper
     :param cazy_dict: dict, dictionary of excepct CAZy synonyms for CAZy classes
-    :param max_tries: int, maximum number of times to scrape CAZy if errors are encountered
+    :param taxonomy_filters: set of genera, species and strains to restrict the scrape to
+    :param kingdoms: list of taxonomy kingdoms to restrict the scrape to
     :param time_stamp: str, data and time scrape was initiated
     :param session: session, open database session
-    :param logger: logger object
     :param args: cmd args parser
 
     Return nothing.
     """
+    logger = logging.getLogger(__name__)
+
     # List of urls that were failed to be scraped
     failed_url_scrapes = []
 
@@ -178,12 +218,11 @@ def get_cazy_data(
     sql_failures = []
 
     # retrieve links to CAZy class pages, return list of CazyClass objects
-    cazy_classes = crawler.get_cazy_class_urls(
+    cazy_classes = crawler.get_cazy_classes(
         cazy_home,
         excluded_classes,
-        max_tries,
         cazy_dict,
-        logger,
+        args,
     )
 
     logger.info("Starting retrieval of CAZy families")
@@ -194,13 +233,12 @@ def get_cazy_data(
         # first attempt of scraping, retrieve URLs to CAZy families
         if len(list(cazy_class.failed_families.keys())) == 0:
 
-            # retrieve URLs to families for the current CAZy class, return as Family class objects
+            # retrieve Family class instances, containing the Family page URL
             class_families, error_message, incorrect_urls = crawler.get_cazy_family_urls(
                 cazy_class.url,
                 cazy_class.name,
                 cazy_home,
                 args,
-                logger,
             )
 
             if incorrect_urls is not None:
@@ -211,7 +249,7 @@ def get_cazy_data(
                 cazy_class.tries += 1
 
                 # check if maximum number of attempts to connect have been met
-                if cazy_class.tries == max_tries:
+                if cazy_class.tries == (args.retries + 1):
                     failed_url_scrapes += (
                         f"{cazy_class.url}\t"
                         f"{cazy_class.name}\t"
@@ -221,7 +259,7 @@ def get_cazy_data(
                     continue
 
                 else:
-                    cazy_classes += cazy_class  # retry scraping Class page after the other Classes
+                    cazy_classes.append(cazy_class)  # retry scraping Class page later Classes
                     continue
 
         # Not first try, scrape only the families for which a connections to CAZy previously failed
@@ -234,17 +272,18 @@ def get_cazy_data(
             # No (sub)families were specified, therefore, scraping all families of the CAZy class
 
             for family in tqdm(class_families, desc=f"Parsing {cazy_class.name} families"):
-                # Populate family with Proteins catalogued under the CAZy family
-                family, failed_family_page_scrapes, family_sql_failures = crawler.parse_family(
+                # Scrape the family and add proteins to the local database
+                family, retry_scrape, failed_fam_pages, family_sql_failures = crawler.parse_family(
                     family,
                     cazy_home,
-                    max_tries,
-                    logger,
+                    taxonomy_filters,
+                    kingdoms,
+                    args,
                     session,
                 )
 
-                # if failed to scrape some pages for CAZy family
-                if failed_family_page_scrapes is not None:
+                # check if there are pages that were unsuccessfully scraped and have retries left
+                if retry_scrape is True:
                     # add one to the number of attempted scrapes for CAZy family
                     try:
                         cazy_class.failed_families[family] += 1
@@ -252,16 +291,16 @@ def get_cazy_data(
                         cazy_class.failed_families[family] = 1  # first attempt
 
                     # check if max number of attempts to connect family pages has been met
-                    if cazy_class.failed_families[family] == max_tries:
-                        failed_url_scrapes += failed_family_page_scrapes  # store urls
+                    if cazy_class.failed_families[family] == (args.retries + 1):
                         del cazy_class.failed_families[family]  # do not try another scrape
                         continue
 
                 if len(list(cazy_class.failed_families.keys())) != 0:
                     # if there are families with previously failed connection attempts
                     # and remaining tries, retry connection after working through other classes
-                    cazy_classes += cazy_class
+                    cazy_classes.append(cazy_class)
 
+                failed_url_scrapes += failed_fam_pages  # urls with no attempts left for retrying
                 sql_failures += family_sql_failures
 
         else:
@@ -279,17 +318,18 @@ def get_cazy_data(
                 if name_check not in config_dict[cazy_class.name]:
                     continue
 
-                # Populate family with Proteins catalogued under the CAZy family
-                family, failed_family_page_scrapes, family_sql_failures = crawler.parse_family(
+                # Scrape the family and add proteins to the local database
+                family, retry_scrape, failed_fam_pages, family_sql_failures = crawler.parse_family(
                     family,
                     cazy_home,
-                    max_tries,
-                    logger,
+                    taxonomy_filters,
+                    kingdoms,
+                    args,
                     session,
                 )
 
-                # if failed to scrape some pages for CAZy family
-                if failed_family_page_scrapes is not None:
+                # check if there are pages that were unsuccessfully scraped and have retries left
+                if retry_scrape is True:
                     # add one to the number of attempted scrapes for CAZy family
                     try:
                         cazy_class.failed_families[family] += 1
@@ -297,28 +337,145 @@ def get_cazy_data(
                         cazy_class.failed_families[family] = 1  # first attempt
 
                     # check if max number of attempts to connect family pages has been met
-                    if cazy_class.failed_families[family] == max_tries:
-                        failed_url_scrapes += failed_family_page_scrapes  # store urls
+                    if cazy_class.failed_families[family] == (args.retries + 1):
                         del cazy_class.failed_families[family]  # do not try another scrape
                         continue
 
                 if len(list(cazy_class.failed_families.keys())) != 0:
                     # if there are families with previously failed connection attempts
                     # and remaining tries, retry connection after working through other classes
-                    cazy_classes += cazy_class
+                    cazy_classes.append(cazy_class)
 
+                failed_url_scrapes += failed_fam_pages  # urls with no attempts left for retrying
                 sql_failures += family_sql_failures
 
     # write out URLs which failed to be scaped
     if len(failed_url_scrapes) != 0:
-        file_io.write_out_failed_scrapes(failed_url_scrapes, time_stamp, args, logger)
+        file_io.write_out_failed_scrapes(failed_url_scrapes, time_stamp, args)
 
     # write out Proteins which failed to be be added to the database
     if len(sql_failures) != 0:
-        file_io.write_out_failed_proteins(sql_failures, time_stamp, args, logger)
+        file_io.write_out_failed_proteins(sql_failures, time_stamp, args)
+
+    return
+
+
+def log_scrape_in_db(time_stamp, config_dict, taxonomy_filters, kingdoms, session, args):
+    """Add a log of scraping CAZy to the local database.
+
+    :param time_stamp: str, date and time cazy_webscraper was invoked
+    :param config_dict: dict of CAZy classes and families to be scraped
+    :param taxonomy_filters: dict of genera, species and strains to restrict the scrape to
+    :param kingdoms: list of taxonomy Kingdoms to restrict scrape to
+    :param session: open SQL database session
+    :param args: cmd arguments
+
+    Return nothing."""
+    date = time_stamp[:time_stamp.find("--")]
+    time = time_stamp[((time_stamp.find("--")) + 2):].replace("-", ":")
+
+    new_log = sql_orm.Log(date=date, time=time)
+
+    if config_dict is not None:
+        # get classes that user named to be scraped
+        try:
+            classes = config_dict["classes"]
+            if classes is not None:
+                classes = str(classes).replace("[", "").replace("]", "").replace("'", "")
+                new_log.classes = classes
+        except KeyError:
+            pass
+
+        # create a list of families instructed to be scraped
+        families = []
+        for key in config_dict:
+            if key == "classes":
+                continue
+            if config_dict[key] is not None:
+                families.append(config_dict[key])
+
+        if len(families) != 0:
+            families = str(families).replace("[", "").replace("]", "").replace("'", "")
+            new_log.families = families
+
+    try:
+        if len(taxonomy_filters["genera"]) != 0:
+            genera = str(taxonomy_filters["genera"]).replace("[", "").\
+                replace("]", "").replace("'", "")
+            new_log.genera = genera
+    except TypeError:
+        pass
+
+    try:
+        if len(taxonomy_filters["species"]) != 0:
+            species = str(taxonomy_filters["species"])
+            species = species.replace("[", "").replace("]", "").replace("'", "")
+            new_log.species = species
+    except TypeError:
+        pass
+
+    try:
+        if len(taxonomy_filters["strains"]) != 0:
+            strains = str(taxonomy_filters["strains"])
+            strains = strains.replace("[", "").replace("]", "").replace("'", "")
+            new_log.strains = strains
+    except TypeError:
+        pass
+
+    if kingdoms is not None:
+        new_log.kingdoms = str(kingdoms).replace("[", "").replace("]", "").replace("'", "")
+    else:
+        new_log.kingdoms = "ALL (Archaea, Bacteria, Eukaryota, Viruses, Unclassified"
+
+    # retrieve commands from the command line
+    cmd_line = ""
+    for cmd in [
+        [args.classes, " --classes '"],
+        [args.families, " --families '"],
+        [args.kingdoms, " --kingdoms"],
+        [args.genera, " --genera '"],
+        [args.species, " --species '"],
+        [args.strains, " --strains '"],
+    ]:
+        try:
+            cmd_line = cmd_line + cmd[1] + cmd[0] + "'"
+        except TypeError:
+            pass
+
+    if len(cmd_line) != 0:
+        cmd_line = cmd_line.strip()
+        new_log.cmd_line = cmd_line
+
+    session.add(new_log)
+    session.commit()
 
     return
 
 
+def get_filter_set(taxonomy_filters_dict):
+    """Create a set of all taxonomy filters from a dictionary.
+
+    :param taxonomy_filers: dict of taxonomy filters
+
+    Return a set.
+    """
+    taxonomy_filters = []
+
+    for key in taxonomy_filters_dict:
+        try:
+            if len(taxonomy_filters_dict[key]) != 0:
+                taxonomy_filters += taxonomy_filters_dict[key]
+        except TypeError:
+            pass
+
+    if len(taxonomy_filters) == 0:
+        taxonomy_filters = None
+
+    else:
+        taxonomy_filters = set(taxonomy_filters)
+
+    return taxonomy_filters
+
+
 if __name__ == "__main__":
     main()
diff --git a/scraper/crawler/__init__.py b/scraper/crawler/__init__.py
index f429f392..a1b0383d 100644
--- a/scraper/crawler/__init__.py
+++ b/scraper/crawler/__init__.py
@@ -1,5 +1,7 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
 # Author:
 # Emma E. M. Hobbs
 
@@ -16,41 +18,55 @@
 # UK
 
 # The MIT License
-"""Module for crawling through the CAZy website and parsing HTML from the CAZy website.
-
-:func get_cazy_family_urls: retrieve URLs to families on CAZy class summary page
-:func get_subfamily_links: retrieve URLs to subfamilies on CAZy class summary page
-:func parse_family: build Family class object to represent CAZy family
-:func parse_family_pages: retrieve all URLs to pages containing protein records for CAZy family
-:func parse_proteins: retrieve protein records from protein table page
-:func row_to_protein: parse the protein record to build a Protein class object
-"""
-
-
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+"""Module for crawling through the CAZy website and parsing HTML from the CAZy website."""
+
+
+import logging
 import re
 import sys
 import time
 
-from collections import defaultdict
 from tqdm import tqdm
 from requests.exceptions import ConnectionError, MissingSchema
 from urllib3.exceptions import HTTPError, RequestError
 
-import bs4
 import mechanicalsoup
 
-from scraper import sql
+from scraper.sql import sql_interface
 
 
 class CazyClass:
-    """A single CAZy class."""
+    """A single CAZy class.
+
+    Used to keep track of if specific families need to be scraped again.
+    """
 
     def __init__(self, name, url, tries, failed_families=None):
         self.name = name
         self.url = url
         self.tries = tries
         if failed_families is None:
-            self.failed_families = {}  # keyed by URL, valued by number of attempted scrapes
+            self.failed_families = {}  # keyed by Family instance, valued by attempted scrapes (int)
+        else:
+            self.failed_families = failed_families
 
     def __str__(self):
         return f"<CAZy class: {self.name} id={id(self)}>"
@@ -63,79 +79,39 @@ def __repr__(self):
 
 
 class Family:
-    """A single CAZy family."""
+    """A single CAZy family.
 
-    members = set()  # holds Protein instances
+    Used to keep track if family needs to be scraped again.
+    """
 
     def __init__(self, name, cazy_class, url, failed_pages=None):
         self.name = name
         self.cazy_class = cazy_class
         self.url = url
         if failed_pages is None:
-            self.failed_pages = {}  # keyed by URL, valued by number of attempted scrapes
-
-    def __str__(self):
-        return f"CAZy family {self.name}: {len(self.members)} protein members"
-
-    def __repr__(self):
-        return f"<Family: {id(self)}: {self.name}, {len(self.members)} protein members"
-
-    def get_proteins(self):
-        """Return a list of all protein members of the CAZy family."""
-        return self.members
-
-    def get_family_name(self):
-        """Return family name"""
-        return self.name
-
-
-class Protein:
-    """A single protein.
-
-    Each protein has a name, source organism (source), and links to external databases. The links to
-    external databases are stored in a dictionary, keyed by the external database name ('str') with
-    'list' values becuase there may be multiple links per database.
-
-    Multiple 'synonym' GenBank accession numbers maybe listed for a single protein. CAZy only
-    hyperlinks the first listed accession number. This accession is the one listed for the protein,
-    because is presumed to be the accession used by CAZy in their classification. All other listed
-    GenBank accessions are regarded as synonyms, including for example splice variants and identical
-    protein sequence submissions.
-    """
-
-    def __init__(self, name, family, ec, source, links=None):
-        self.name = name
-        self.family = family
-        self.ec = ec
-        self.source = source
-        if links is None:
-            self.links = defaultdict(list)
+            # {kingdom: {paginiation_page_url: number of tries}}
+            self.failed_pages = {}
         else:
-            self.links = links
+            self.failed_pages = failed_pages
 
     def __str__(self):
-        """Create representative string of class object"""
-        return f"{self.name} ({self.family} {self.source}): links to {self.links.keys()}"
+        return f"CAZy family {self.name}"
 
     def __repr__(self):
-        """Create representative object"""
-        return (
-            f"<Protein: {id(self)}: {self.name}, {self.family} "
-            f"({self.source}), {len(self.links)} to external databases>"
-        )
+        return f"<Family: {id(self)}: {self.name}>"
 
 
-def get_cazy_class_urls(cazy_home, excluded_classes, max_tries, cazy_dict, logger):
+def get_cazy_classes(cazy_home, excluded_classes, cazy_dict, args):
     """Returns a list of CAZy class main/home page URLs for each specified class as the CAZy site.
 
     :param cazy_url: str, URL to the CAZy home page.
     :param excluded_classes: list, list of CAZy classes not to be scraped
-    :param max_tries: int, maximum number of times to try scrape if errors are encountered
     :param cazy_dict: dictionary of offical CAZy class names
-    :param logger: logger object
+    :param args: cmd line args parser
 
-    Return list of URLs and None, or None and error message.
+    Return list of CazyClass instances, or None and an error message.
     """
+    logger = logging.getLogger(__name__)
     logger.info("Retrieving URLs to summary CAZy class pages")
 
     # define items to be excluded from returned class list, ALWAYS exlide links to genomes
@@ -147,13 +123,13 @@ def get_cazy_class_urls(cazy_home, excluded_classes, max_tries, cazy_dict, logge
     home_page = None
     tries = 0  # number of the attempted connections to CAZy
 
-    while (home_page is None) and (tries < max_tries):
-        home_page, error = get_page(cazy_home)
+    while (home_page is None) and (tries < args.retries + 1):
+        home_page, error = get_page(cazy_home, args, max_tries=(args.retries + 1))
 
-        if (home_page is None) and (tries < max_tries):
+        if (home_page is None) and (tries < (args.retries + 1)):
             logger.error(
                 f"Failed to connect to CAZy homepage after 10 attempts,\n"
-                f"On attempt# {(tries+1)}/{max_tries} the following error was raised:\n"
+                f"On attempt# {(tries+1)}/{args.retries + 1} the following error was raised:\n"
                 f"{error}\n"
                 f"Reattempting for attempt# {(tries+2)} in 10s."
             )
@@ -217,32 +193,27 @@ def get_cazy_class_urls(cazy_home, excluded_classes, max_tries, cazy_dict, logge
     return cazy_classes
 
 
-def get_cazy_family_urls(class_url, class_name, cazy_home, args, logger):
+def get_cazy_family_urls(class_url, class_name, cazy_home, args):
     """Retrieve all protein members of each CAZy family within the given CAZy class.
 
     :param class_url: str, URL to the CAZy class
     :param class_name: str, name of CAZy class
     :param cazy_home: str, URL to CAZy home page
     :param args: args parser object
-    :param logger: logger object
 
     Returns list Family class objects, error message when connecting to CAZy and list of incorrectly
     formated URLs
     """
+    logger = logging.getLogger(__name__)
     logger.info(f"Retrieving URLs to families under {class_name}")
 
     # scrape the class page
-    class_page, error = get_page(class_url)
+    class_page, error = get_page(class_url, args, max_tries=(args.retries + 1))
 
     if class_page is None:
         logger.error(
-            (
-                f"Failed to connect to {class_url} after 10 attempts.\n"
-                "The following error was raised:\n"
-                f"{error}"
-                "Could not retrieve URLs to CAZy famileis for this class.\n"
-                "This class will be skipped during the scraping process."
-            )
+                f"Couldn't connect to {class_url} after {(args.retries + 1)} attempts. "
+                f"The following error was raised:\n{error}"
         )
         return None, error, None
 
@@ -261,8 +232,11 @@ def get_cazy_family_urls(class_url, class_name, cazy_home, args, logger):
     # tables[0] is the table containing links to CAZy families
     # tables[1] is the table containing the link to unclassified proteins
 
-    family_urls = family_urls = [f"{cazy_home}/{_['href']}" for _ in tables[0].find_all("a")]
-    family_urls.append(f"{cazy_home}/{tables[1].a['href']}")
+    family_urls = [f"{cazy_home}/{_['href']}" for _ in tables[0].find_all("a")]
+    try:
+        family_urls.append(f"{cazy_home}/{tables[1].a['href']}")
+    except TypeError:
+        family_urls = None
 
     if (args.subfamilies is False) and (family_urls is None):
         logger.warning(f"Failed to retrieve URLs to CAZy families for {class_name}\n")
@@ -270,7 +244,7 @@ def get_cazy_family_urls(class_url, class_name, cazy_home, args, logger):
 
     # retrieve URLs to subfamilies
     if args.subfamilies is True:
-        subfam_urls = get_subfamily_links(family_h3_element, cazy_home, logger)
+        subfam_urls = get_subfamily_links(family_h3_element, cazy_home)
 
         if (family_urls is None) and (subfam_urls is None):
             logger.warning(f"Failed to retrieve URLs to CAZy subfamilies for {class_name}")
@@ -315,7 +289,7 @@ def get_cazy_family_urls(class_url, class_name, cazy_home, args, logger):
 
         family_name = url[(len(cazy_home) + 1): -5]
 
-        family = Family(family_name, class_name, url, 0)
+        family = Family(family_name, class_name, url)
         family.members = set()  # later used to store Protein members
         cazy_families.append(family)
 
@@ -325,12 +299,11 @@ def get_cazy_family_urls(class_url, class_name, cazy_home, args, logger):
     return cazy_families, None, incorrect_urls
 
 
-def get_subfamily_links(family_h3_element, cazy_home, logger):
+def get_subfamily_links(family_h3_element, cazy_home):
     """Retrieve URL links to CAZy subfamilies.
 
     :param family_h3_element: bs4.element.Tag, h3 element titling the page div
     :param cazy_home: str, URL to CAZy home_page
-    :param logger: logger object
 
     Return list of URLs to subfamilies.
     """
@@ -356,132 +329,410 @@ def get_subfamily_links(family_h3_element, cazy_home, logger):
         return urls
 
 
-def parse_family(family, cazy_home, max_tries, logger, session):
+def parse_family(family, cazy_home, taxonomy_filters, kingdoms, args, session):
     """Returns a Family object with Protein members, scraped from CAZy.
 
-    :param family: Family class object, representation of CAZy family
-    :param cazy_home: str, URL to CAZy home page
-    :param logger: logger object
-
     Returns a Family object populated with Proteins and URLs of paginiation pages for which the
     scrape failed, including the number of times a connection to CAZy has been attempted. Also
     returns a list of strings containing URLs and associated error message of URLs for which a
     a connection to CAZy could not be made.
 
-    Return Family object, list of URLs which couldn't connect to CAZy and list of proteins that
-    could not be added to the SQL database.
+    :param family: Family class object, representation of CAZy family
+    :param cazy_home: str, URL to CAZy home page
+    :param taxonomy_filters: set of genera, species and strains to restrict the scrape to
+    :param kingdoms: list of taxonomy Kingdoms to restrict the scrape to
+        OR a str if the user did not define any Kingdoms to scrape  (enables faster
+        scraping via the 'all' pages)
+    :param args: cmd-line args parser
+    :param session: open SQL database session
+
+    Return Family object, Boolean whether to scrape the family again, a list of URLs which couldn't
+    connect to CAZy (and no have re-try attempts left) and list of proteins that could not be added
+    to the SQL database.
     """
+    logger = logging.getLogger(__name__)
     logger.info(f"Starting retrieval of proteins for {family.name} from {family.url}")
 
-    # compile URL to first family page of protein records
-    first_pagination_url = family.url.replace(".html", "_all.html")
+    if kingdoms == 'all':  # retrieve proteins from the proteins listed in 'all' pages
+        family, retry_scrape, failed_scrapes, sql_failures = parse_family_via_all_pages(
+            family,
+            cazy_home,
+            taxonomy_filters,
+            args,
+            session,
+        )
+        return family, retry_scrape, failed_scrapes, sql_failures
+
+    # else: scrape via the Taxonomy pages
+
+    if len(list(family.failed_pages.keys())) != 0:  # retrying scrape
+        kingdoms = list(family.failed_pages.keys())
+
+    # else, scraping for the first time so use user defined kingdoms
+
+    failed_scrapes = []  # URLs of pages for which maximum number of scrape attempts is MET
+    sql_failures = []
+
+    for kingdom in kingdoms:
+        # compile URL to first family page of protein records
+        first_pagination_url = family.url.replace(".html", f"_{kingdom}.html")
 
-    # check url formating of first paginiation url
+        # check url formating of first paginiation url
+        try:
+            re.match(
+                rf"http://www.cazy.org/(\D\D|\D\D\D)(\d+_{kingdom}|\d+_\d+_{kingdom}).html",
+                first_pagination_url,
+            ).group()
+        except AttributeError:
+            logger.warning(
+                f"Incorrect formatting of first protein table page URL: {first_pagination_url}\n"
+                "Will not try and connect to this URL."
+            )
+            failed_scrapes.append(
+                f"{first_pagination_url}\tIncorrect URL format for the first protein table page "
+                f"for {family.name} in kingdom {kingdom}"
+            )
+            continue  # could not scrape any CAZymes for the Kingdom
+
+        # Retrieve the URLs to all paginiation pages of CAZymes
+        first_pagination_page, error_message = get_page(
+            first_pagination_url,
+            args,
+            max_tries=args.retries,
+        )
+
+        if first_pagination_page is None:
+            logger.warning(
+                f"Could not connect to {first_pagination_url} after 10 attempts\n"
+                f"The following error was raised:\n{error_message}"
+            )
+            failed_scrapes.append(
+                f"{first_pagination_url}\tCould not conenct to first paginiation page to get "
+                f"all paginiation page URLs for {family.name}, kingdom: {kingdom}.\n"
+                f"Therefore, did not scrape any CAZymes from {family.name}, kingdom: {kingdom}"
+            )
+            continue
+
+        protein_page_urls, total_proteins = get_tax_page_urls(
+            first_pagination_url,
+            first_pagination_page,
+            kingdom,
+            cazy_home,
+            family.name,
+        )
+        if total_proteins == 0:
+            logger.warning(f"Protein count for {family.name} retrieved == 0")
+            continue
+
+        # Retrieve the CAZymes (proteins) and write to the local database
+        for protein in tqdm(
+            (y for x in (
+                parse_proteins(
+                    url,
+                    family.name,
+                    taxonomy_filters,
+                    kingdom,
+                    args,
+                    session,
+                ) for url in protein_page_urls
+            ) for y in x),
+            total=total_proteins,
+            desc=f"Parsing protein pages for {family.name}: {kingdom}",
+        ):
+            if protein["url"] is not None:
+                # Protein was not retrieved because could not connect to CAZy
+                try:
+                    family.failed_pages[kingdom]
+
+                    try:
+                        family.failed_pages[kingdom][protein["url"]] += 1
+                    except KeyError:  # first failed scrape for the specific paginiation page
+                        family.failed_pages[kingdom][protein["url"]] = 1
+
+                except KeyError:  # first failed attempt for the family:kingdom
+                    family.failed_pages[kingdom] = {protein["url"]: 1}
+
+                if family.failed_pages[kingdom][protein["url"]] >= (args.retries + 1):
+                    # Reached maximum attempts number of attempted connections ...
+                    failed_scrapes.append(
+                        f"{protein['url']}\t{family.cazy_class}\t"
+                        f"Failed to connect to this page of proteins for {family.name}\t"
+                        f"{protein['error']}"
+                    )
+                    # ... and do no attempt to scrape again
+                    del family.failed_pages[kingdom][protein["url"]]
+
+            if protein["sql"] is not None:  # Error occured when adding Protein to SQL database
+                sql_failures.append(
+                    f"{protein['sql']} was not added to the database, and raised the following "
+                    f"error when atempting to do so:\n{protein['error']}"
+                )
+
+    # check if any pages have attempts left for retrying for a successful scrape
+    if len(list(family.failed_pages.keys())) == 0:
+        retry_scrape = False
+    else:
+        retry_scrape = True
+
+    return family, retry_scrape, failed_scrapes, sql_failures
+
+
+def get_tax_page_urls(
+    first_pagination_url,
+    first_pagination_page,
+    kingdom,
+    cazy_home,
+    family_name,
+):
+    """Retrieve the URLs to all pages containing proteins for the current working family.
+
+    Also retrieve the total number of proteins catagloued under the family.
+
+    :param first_pagination_url: str, URL to first page contaiing proteins
+    :param first_pagination_page: BS4 object, first page containing proteins
+    :param kingdom: str, taxonomy Kingdom
+    :param cazy_home: str, URL of CAZy homepage
+    :param family_name: str, name of the CAZy family
+
+    Return list of URLs, and number of proteins in the family.
+    """
+    logger = logging.getLogger(__name__)
+
+    protein_page_urls = [first_pagination_url]
+
+    try:  # retrieve the URL to the final page of protein records in the pagination listing
+        last_pagination_url = first_pagination_page.find_all(
+            "a", {"class": "lien_pagination", "rel": "nofollow"}
+        )[-1]
+    except IndexError:  # there is no pagination; there's only one page of proteins
+        last_pagination_url = None
+
+    if last_pagination_url is not None:
+        url_prefix = last_pagination_url["href"].split("TAXO=")[0] + "TAXO="
+        last_url_num = int(last_pagination_url["href"].split("TAXO=")[-1].split("#pagination")[0])
+        url_suffix = "#pagination" + last_pagination_url["href"].split("#pagination")[-1]
+
+        # Build list of urls to all pages in the pagination listing, increasing the PRINC increment
+        protein_page_urls.extend(
+            [f"{cazy_home}/{url_prefix}{_}{url_suffix}" for _ in range(
+                100, last_url_num + 100, 100
+            )]
+        )
+
+    # Retrieve the number of proteins in the family: kingdom from the hyperlinks to the start of
+    # each Kingdom's pagination pages
+    data = first_pagination_page.find_all("div", {"class": "pos_choix"})
+    # retrieve the text for the Kingdom's hyperlink, and retrieve the number within the brackets
     try:
-        re.match(
-            r"http://www.cazy.org/\D{2,3}(\d+|\d+_\d+)_all.html", first_pagination_url
-        ).group()
-    except AttributeError:
+        protein_total = int(re.findall(
+            rf"{kingdom} \(\d+\)", data[0].text, flags=re.IGNORECASE,
+        )[0].split("(")[1][:-1])
+    except IndexError:
         logger.warning(
-            f"Incorrect formatting of first protein table page URL: {first_pagination_url}\n"
-            "Will not try and connect to this URL."
-        )
-        return(
-            family,
-            f"Incorrect URL format for the first protein table page for {family.name}",
-            None,
+            f"No proteins in {kingdom} in {family_name}"
         )
+        protein_total = 0
+
+    return protein_page_urls, protein_total
+
+
+def parse_proteins(protein_page_url, family_name, taxonomy_filters, kingdom, args, session):
+    """Returns generator of Protein objects for all protein rows on a single CAZy family page.
+
+    Returns a dictionary containing any errors that arose. If it an attempt to connect to CAZy
+    failed the URL is stored under "url". The "sql" key is used to store the name of the protein
+    which raised an SQL error further down the pipeline.
+
+    :param protein_page_url, str, URL to the CAZy family page containing protein records
+    :param family_name: str, name of CAZy family
+    :param taxonomy_filters: set of genera, species and strains to restrict the scrape to
+    :param kingdom: str, Taxonomy Kingdom of CAZymes currently being scraped
+    :param args: cmd-line args parser
+    :param session: open SQL database session
 
-    first_pagination_page, error_message = get_page(first_pagination_url)
+    Return generator object.
+    """
+    logger = logging.getLogger(__name__)
+    logger.info(f"Retrieving proteins from {protein_page_url}")
 
-    if first_pagination_page is None:
+    protein_page, error = get_page(protein_page_url, args, max_tries=args.retries)
+
+    if protein_page is None:
         logger.warning(
             (
-                f"Could not connect to {first_pagination_url} after 10 attempts\n"
+                f"Could not connect to {protein_page_url} after 10 attempts\n"
                 "The following error was raised:\n"
-                f"{error_message}"
+                f"{error}\n"
+                f"No protein records from this page will be retried."
             )
         )
-        return(
-            family,
-            [
-                f"{first_pagination_url}\t"
-                f"{family.cazy_class}\t"
-                f"Failed to connect to first page of proteins for {family.name}\t"
-                f"{error_message}"
-            ],
-            [],
+        return {"url": protein_page_url, "error": error, "sql": None}
+
+    # Get the table on the page corresponding to CAZymes
+    try:
+        cazyme_table = protein_page.select("table")[1]
+    except AttributeError:
+        logger.warning("NO PROTEIN TABLE!")
+        sys.exit(1)
+        # raised if there is not table of proteins
+        return {"url": 'No protein table', "error": None, "sql": None}
+
+    # Get all rows in the table, exluding those that are header/navigation roes
+    # Each row has an .attrs attribute, and this holds the selector options, such as
+    # "class" and "id"; CAZyme rows don't have these attributes
+    cazyme_rows = [
+        _ for _ in cazyme_table.select("tr") if "class" not in _.attrs and "id" not in _.attrs
+    ]
+
+    # Loop overal all rows and add data to the local database
+    for row in cazyme_rows:
+        yield row_to_protein(row, family_name, taxonomy_filters, kingdom, session)
+
+
+def parse_family_via_all_pages(family, cazy_home, taxonomy_filters, args, session):
+    """Parse the protein tables from the 'all' pages of CAZy family.
+
+    CAZy families have separate series of HTML tables for each taxonomy Kingdom, and a single series
+    of HTML tables containing all proteins from all Kingdoms, called 'all'. These 'all' pages
+    containing 1000 proteins per page and thus scraping these pages is significantly faster than
+    scraping all the specific Kingdom HTML tables (which hold only 100 proteins each, and thus
+    require more calls to CAZy).
+
+    :param family: Family class object, representation of CAZy family
+    :param cazy_home: str, URL to CAZy home page
+    :param taxonomy_filters: set of genera, species and strains to restrict the scrape to
+    :param args: cmd-line args parser
+    :param session: open SQL database session
+
+    Return Family object, Boolean whether to scrape the family again, a list of URLs which couldn't
+    connect to CAZy (and no have re-try attempts left) and list of proteins that could not be added
+    to the SQL database.
+    """
+    logger = logging.getLogger(__name__)
+
+    # check if there were pagination pages to which a connection could not be made previously
+    if len(list(family.failed_pages.keys())) != 0:
+        protein_page_urls = list(family.failed_pages.keys())
+        total_proteins = len(protein_page_urls * 1000)
+
+    else:  # scraping family for the first time so retrieve the URLs to the pagination pages
+        # compile URL to first family page of protein records
+        first_pagination_url = family.url.replace(".html", "_all.html")
+        # check url formating of first paginiation url
+        try:
+            re.match(
+                r"http://www.cazy.org/\D{2,3}(\d+|\d+_\d+)_all.html", first_pagination_url
+            ).group()
+        except AttributeError:
+            logger.warning(
+                f"Incorrect formatting of first protein table page URL: {first_pagination_url}\n"
+                "Will not try and connect to this URL."
+            )
+            return(
+                family,
+                False,
+                [
+                    f"{first_pagination_url}\t{family.cazy_class}\t"
+                    f"Incorrect URL format, could not connect to CAZy for {family.name}"
+                ],
+                [],
+            )
+
+        # retrieve a list of all page urls of protein tables for the CAZy family
+        first_pagination_page, error_message = get_page(
+            first_pagination_url,
+            args,
+            max_tries=args.retries,
         )
 
-    # Get the URLS to all pages of proteins and the total number of proteins in the (sub)family
-    protein_page_urls, total_proteins = get_protein_page_urls(
-        first_pagination_url,
-        first_pagination_page,
-        cazy_home,
-    )
+        if first_pagination_page is None:
+            logger.warning(
+                    f"Could not connect to {first_pagination_url} after 10 attempts\n"
+                    f"The following error was raised:\n{error_message}\nTherefore, could not "
+                    "retrieve all pagination pages URLs, therefore, cannot scrape proteins from "
+                    f"{family.name}"
+            )
+            return(
+                family,
+                False,
+                [
+                    f"{first_pagination_url}\t{family.cazy_class}\t"
+                    f"Failed to connect to first pagination page for {family.name}, therefore "
+                    f"could not retrieve URLs to all paginiation pages\t{error_message}"
+                ],
+                [],
+            )
 
-    if len(protein_page_urls) == 0:
-        return(
-            family,
-            [
-                f"{first_pagination_url}\t"
-                f"{family.cazy_class}\t"
-                f"Failed to retrieve URLs to protein table pages for {family.name}\t"
-                f"No specific error message availble. "
-                "Failed check on line 411 of scraper.crawler.__init__.py"
-            ],
-            [],
+        # Get the URLS to all pages of proteins and the total number of proteins in the (sub)family
+        protein_page_urls, total_proteins = get_paginiation_page_urls(
+            first_pagination_url,
+            first_pagination_page,
+            cazy_home,
+            family.name,
         )
 
-    failed_scrapes = []  # URLs of pages for which maximum number of attempted connections is met
+        if len(protein_page_urls) == 0:
+            return(
+                family,
+                False,
+                [
+                    f"{first_pagination_url}\t{family.cazy_class}\t"
+                    f"Failed to retrieve URLs to protein table pages for {family.name}\t"
+                    f"No specific error message availble."
+                ],
+                [],
+            )
+
+    # Scrape proteins from CAZy
+    # define lists for storing error messages during scraping and parsing proteins
+    failed_scrapes = []  # URLs of pages for which maximum number of scrape attempts is MET
     sql_failures = []
 
     for protein in tqdm(
         (y for x in (
-            parse_proteins(
+            parse_proteins_from_all(
                 url,
                 family.name,
-                logger,
+                taxonomy_filters,
                 session,
+                args,
             ) for url in protein_page_urls
         ) for y in x),
         total=total_proteins,
         desc=f"Parsing protein pages for {family.name}",
     ):
-        if protein["url"] is not None:
-            # Could not connect to CAZy
+        if protein["url"] is not None:  # Protein was not retrieved because couldn't connect to CAZy
             try:
                 family.failed_pages[protein["url"]] += 1
             except KeyError:
                 family.failed_pages[protein["url"]] = 1  # First failed attempt to connect to page
 
-            failed_scrapes.append(
-                f"{protein['url']}\t"
-                f"{family.cazy_class}\t"
-                f"Failed to connect to this page of proteins for {family.name}\t"
-                f"{protein['error']}"
-            )
-
-            if family.failed_pages[protein["url"]] == max_tries:
-                # maximum attempts to connect have been reached no more attempts made
-                # do no attempt to scrape again
+            if family.failed_pages[protein["url"]] == args.retries:
+                # maximum attempts to connect have been reached no more attempts made, write to file
+                failed_scrapes.append(
+                    f"{protein['url']}\t{family.cazy_class}\t"
+                    f"Failed to connect to this page of proteins for {family.name}, "
+                    f"and raised the following error message:\n{protein['error']}"
+                )
+                # ... and do no attempt to scrape again
                 del family.failed_paged[protein["url"]]
 
-        elif protein["sql"] is not None:
-            # Error occured when adding Protein to SQL database
+        if protein["sql"] is not None:  # Error occured when adding Protein to SQL database
             sql_failures.append(
-                f"{protein['sql']} was not added to the database\n"
-                "and raised the following error when atempting to do so:\n"
-                f"{protein['error']}"
+                f"{protein['sql']} was not added to the database\t"
+                f"and raised the following error when atempting to do so:\n{protein['error']}"
             )
 
-    if len(failed_scrapes) == 0:
-        failed_scrapes = None
+    # check if any pages for the family still have attempts left for trying for a successful scrape
+    if len(list(family.failed_pages.keys())) == 0:
+        retry_scrape = False
+    else:
+        retry_scrape = True
 
-    return family, failed_scrapes, sql_failures
+    return family, retry_scrape, failed_scrapes, sql_failures
 
 
-def get_protein_page_urls(first_pagination_url, first_pagination_page, cazy_home):
+def get_paginiation_page_urls(first_pagination_url, first_pagination_page, cazy_home, family_name):
     """Retrieve the URLs to all pages containing proteins for the current working family.
 
     Also retrieve the total number of proteins catagloued under the family.
@@ -492,6 +743,8 @@ def get_protein_page_urls(first_pagination_url, first_pagination_page, cazy_home
 
     Return list of URLs, and number of proteins in the family.
     """
+    logger = logging.getLogger(__name__)
+
     protein_page_urls = [first_pagination_url]
 
     # retrieve the URL to the final page of protein records in the pagination listing
@@ -506,7 +759,6 @@ def get_protein_page_urls(first_pagination_url, first_pagination_page, cazy_home
         url_prefix = last_pagination_url["href"].split("PRINC=")[0] + "PRINC="
         last_princ_no = int(last_pagination_url["href"].split("PRINC=")[-1].split("#pagination")[0])
         url_suffix = "#pagination" + last_pagination_url["href"].split("#pagination")[-1]
-
         # Build list of urls to all pages in the pagination listing, increasing the PRINC increment
         protein_page_urls.extend(
             [f"{cazy_home}/{url_prefix}{_}{url_suffix}" for _ in range(
@@ -514,37 +766,42 @@ def get_protein_page_urls(first_pagination_url, first_pagination_page, cazy_home
             )]
         )
 
-    # Retrieve the number of proteins in the family
-    data = first_pagination_page.find_all(
-        "div", {"class": "pos_choix"}
-    )
-    search_results = re.findall(r"\(\d+\)", data[0].text)
-    for index in range(len(search_results)):
-        search_results[index] = search_results[index][1:-1]
-        search_results[index] = int(search_results[index])
-    search_results.sort()
-    protein_total = search_results[-1]
+    # retrieve the data element that contains the links the sets of HTML tables
+    data = first_pagination_page.find_all("div", {"class": "pos_choix"})
+
+    # retrieve the number of proteins listed after 'all' in the data
+    try:
+        protein_total = int(re.findall(
+            r"all \(\d+\)", data[0].text, flags=re.IGNORECASE,
+        )[0].split("(")[1][:-1])
+    except IndexError:
+        logger.warning(f"No proteins found for 'all' in {family_name}")
+        protein_total = 0
 
     return protein_page_urls, protein_total
 
 
-def parse_proteins(protein_page_url, family_name, logger, session):
-    """Returns generator of Protein objects for all protein rows on a single CAZy family page.
+def parse_proteins_from_all(protein_page_url, family_name, taxonomy_filters, session, args):
+    """Parse proteins from the paginiation page.
 
-    :param protein_page_url, str, URL to the CAZy family page containing protein records
-    :param family_name: str, name of CAZy family
-    :param logger: logger object
-
-    Returns a dictionary containing any errors that arose. If it an attempt to connect to CAZy
+    Returns generator of Protein objects for all protein rows on a single CAZy family page. Returns
+    a dictionary containing any errors that arose. If it an attempt to connect to CAZy
     failed the URL is stored under "url". The "sql" key is used to store the name of the protein
     which raised an SQL error further down the pipeline.
 
+    :param protein_page_url, str, URL to the CAZy family page containing protein records
+    :param family_name: str, name of CAZy family
+    :param taxonomy_filters: set of genera, species and strains to restrict the scrape to
+    :param session: open SQL database session
+    :param args: cmd-line args parser
+
     Return generator object.
     """
+    logger = logging.getLogger(__name__)
     logger.info(f"Retrieving proteins from {protein_page_url}")
 
-    protein_page, error = get_page(protein_page_url)
-
+    # connect to page
+    protein_page, error = get_page(protein_page_url, args, max_tries=args.retries)
     if protein_page is None:
         logger.warning(
             (
@@ -556,19 +813,26 @@ def parse_proteins(protein_page_url, family_name, logger, session):
         )
         return {"url": protein_page_url, "error": error, "sql": None}
 
-    # retrieve protein record table
-    protein_table = protein_page.find_all("table", {"class": "listing"})[0]
-    protein_rows = [
-        _ for _ in protein_table.descendants if (
-            (_.name == "tr") and ("id" not in _.attrs) and ("class" not in _.attrs)
-        )
-    ]
+    # retrive the table of proteins
+    cazyme_table = protein_page.select("table")[1]
 
-    for row in protein_rows:
-        yield row_to_protein(row, family_name, logger, session)
+    tax_kingdom = ''  # Archaea, Bacteria, Eukaryota, Viruses, unclassified
+    for row in cazyme_table.select("tr"):
+        try:
+            if (row.attrs["class"] == ['royaume']) and (row.text.strip() != 'Top'):
+                # Row defines the taxonomy Kingdom
+                tax_kingdom = row.text.strip()
+                continue  # row does not contain protein
+            else:  # result when row containing 'Top', becuase reached end of the page
+                continue  # row does not contain protein
+        except KeyError:
+            pass
+
+        if ('class' not in row.attrs) and ('id' not in row.attrs):  # row contains protein data
+            yield row_to_protein(row, family_name, taxonomy_filters, tax_kingdom, session)
 
 
-def row_to_protein(row, family_name, logger, session):
+def row_to_protein(row, family_name, taxonomy_filters, kingdom, session):
     """Returns a Protein object representing a single protein row from a CAZy family protein page.
 
     Each row, in order, contains the protein name, EC number, source organism, GenBank ID(s),
@@ -576,6 +840,8 @@ def row_to_protein(row, family_name, logger, session):
 
     :param row: tr element from CAZy family protein page
     :param family_name: str, name of CAZy family
+    :param taxonomy_filters: set of genera, species and strains to restrict the search to
+    :param kingdom: str, Taxonomy Kingdom of CAZymes currently being scraped
     :param session: open sqlalchemy database session
 
     Returns a dictionary to store and reflect any errors that may have occurred during the parsing
@@ -583,6 +849,8 @@ def row_to_protein(row, family_name, logger, session):
 
     Return dictionary.
     """
+    logger = logging.getLogger(__name__)
+
     # retrieve list of cells ('td' elements) in row
     tds = list(row.find_all("td"))
 
@@ -590,6 +858,11 @@ def row_to_protein(row, family_name, logger, session):
 
     source_organism = tds[2].a.get_text()
 
+    if taxonomy_filters is not None:  # apply taxonomy filter
+        if any(filter in source_organism for filter in taxonomy_filters) is False:
+            # CAZyme does not match any taxonomy filters
+            return {"url": None, "error": None, "sql": None}
+
     ec_numbers = []
     all_links = None
     try:
@@ -603,75 +876,147 @@ def row_to_protein(row, family_name, logger, session):
     else:
         ec_numbers = None
 
-    links = {"GenBank": []}
-    # test for len(tds[x].contents) in case there is no link,
-    # the check of .name then ensures link is captured
-    if len(tds[3].contents) and tds[3].contents[0].name == "a":
-        links["GenBank"] = [f"{_.get_text()}" for _ in tds[3].contents if _.name == "a"]
-    if len(tds[4].contents) and tds[4].contents[0].name == "a":
-        links["UniProt"] = [f"{_.get_text()}" for _ in tds[4].contents if _.name == "a"]
-    if len(tds[5].contents) and tds[5].contents[0].name == "a":
-        links["PDB/3D"] = [f"{_.get_text()}" for _ in tds[5].contents if _.name == "a"]
-
-    # Retrieve non-primary GenBank accession
-    # these are the accessions that are not hyerlinked in CAZy
-    try:
-        genbank_synonyms = tds[3].find('br').next_siblings
-        for i in genbank_synonyms:
-            if type(i) is bs4.element.NavigableString:
-                links["GenBank"].append(i)
-    except AttributeError:
-        pass
+    # retrieve the BeautifulSoup elements of the cell containing accessions for the respective db
+    gbk_bs_elements = [_ for _ in row.select("td")[3].contents if getattr(_, "name", None) != "br"]
+    uni_bs_elements = [_ for _ in row.select("td")[4].contents if getattr(_, "name", None) != "br"]
+    pdb_bs_elements = [_ for _ in row.select("td")[5].contents if getattr(_, "name", None) != "br"]
 
-    if len(links["GenBank"]) == 0:
-        logger.warning(
-            f"Did not retrieve any GenBank accessions for {protein_name} in {family_name}.\n"
-            "The primary GenBank accession determines what unique protein the current working "
-            "protein is.\n"
-            "Protein will not be added to the local database"
+    # Retrieve primary GenBank and UniProt accessions (identified by being written in bold)
+    # CAZy defines the 'best' GenBank and UniProt models by writting them in bold
+    gbk_primary = [_.text for _ in row.select("td")[3].find_all('b')]
+    uni_primary = [_.text for _ in row.select("td")[4].find_all('b')]
+
+    # Retrieve all accessions listed for each database
+    # At this stage the non-primary accession lists containg ALL accessions in the cell
+    gbk_nonprimary = get_all_accessions(gbk_bs_elements)
+    uni_nonprimary = get_all_accessions(uni_bs_elements)
+    pdb_accessions = get_all_accessions(pdb_bs_elements)
+
+    # create dict for storing error messages for writing to the failed_to_scrape output file
+    report_dict = {"url": None, "error": None, "sql": None}
+
+    # Ensure a single primary GenBank accession is retrieved
+    if len(gbk_primary) == 0:
+
+        if len(gbk_nonprimary) == 0:
+            warning = (
+                f"NO GenBank accessions retrieved for {protein_name} in {family_name}.\n"
+                "Adding protein with the GenBank accession: 'NA' as a new protein to the db."
+            )
+            logger.warning(warning)
+            gbk_primary = ["NA"]
+            report_dict["error"] = warning
+            report_dict["sql"] = protein_name
+
+        else:
+            warning = (
+                f"GenBank accessions retrieved for {protein_name} in {family_name} but none were "
+                f"written as primary in CAZy.\nThe first accession {gbk_nonprimary[0]} written "
+                "as primary in the db "
+            )
+            gbk_primary.append(gbk_nonprimary[0])
+            gbk_nonprimary.remove(gbk_nonprimary[0])
+
+    elif len(gbk_primary) == 1:
+        # Remove the primary accession from the non-primary accession list
+        if gbk_primary[0] in gbk_nonprimary:
+            gbk_nonprimary.remove(gbk_primary[0])
+
+    else:
+        warning = (
+            f"Multiple primary GenBank acccessions retrieved for {protein_name} in "
+            f"{family_name}.\nOnly the first listed accession will be written as primary, the "
+            "others are written as non-primary. These are:"
         )
+        # remove all but first listed primary accession
+        for accession in gbk_primary[1:]:
+            warning += f"\nGenBank accession: {accession}"
+            gbk_primary.remove(accession)
+        # remove primary accession from the non-primary accession list
+        if gbk_primary[0] in gbk_nonprimary:
+            gbk_nonprimary.remove(gbk_primary[0])
+
+        logger.warning(warning)
+        report_dict["error"] = warning
+        report_dict["sql"] = protein_name
+
+    if (len(uni_primary) == 0) and (len(uni_nonprimary) != 0):
+        # move the first listed UniProt accession to the primary list
+        uni_primary.append(uni_nonprimary[0])
+        uni_nonprimary.remove(uni_primary[0])
+
+    elif len(uni_primary) > 1:
+        warning = (
+            f"Multiple UniProt primary accessions retrieved for {protein_name} in "
+            f"{family_name}.\nAll listed as primary UniProt accessions in the local db, including:"
+        )
+        for accession in uni_primary:
+            warning += f"\nUniProt accession: {accession}"
+        logger.warning(warning)
+        report_dict["error"] = warning
+        report_dict["sql"] = protein_name
 
-        return {
-            "url": None,
-            "error": (
-                "Failed to retrieve any GenBank accessions, "
-                "which define what protein the CAZyme is"
-            ),
-            "sql": protein_name,
-        }
+    # Remove primary UniProt accessions from the non-primary accessions list
+    for accession in uni_primary:
+        if accession in uni_nonprimary:
+            uni_nonprimary.remove(accession)
 
     # add protein to database
     try:
-        result = sql.add_protein_to_db(
+        sql_interface.add_protein_to_db(
             protein_name,
             family_name,
             source_organism,
-            ec_numbers,
-            links,
-            logger,
+            kingdom,
+            gbk_primary[0],
             session,
+            ec_numbers,
+            gbk_nonprimary,
+            uni_primary,
+            uni_nonprimary,
+            pdb_accessions,
         )
 
     except Exception as error_message:
-        logger.warning(f"Failed to add {protein_name} to SQL database", exc_info=1)
-        return {
-            "url": None,
-            "error": f"Failed to add to SQL database. {error_message}",
-            "sql": protein_name,
-        }
-
-    if result is not None:  # duplicate CAZymes found in the database
-        return {"url": None, "error": result, "sql": protein_name}
+        warning = (
+            f"Failed to add {protein_name} to SQL database, "
+            f"the following error was raised:\n{error_message}"
+        )
+        logger.warning(warning, exc_info=1)
+        report_dict["error"] = warning
+        report_dict["sql"] = protein_name
 
     return {"url": None, "error": None, "sql": None}
 
 
+def get_all_accessions(bs_element_lst):
+    """Retrieve all accessions listed in a cell from a CAZyme table.
+
+    :param bs_element_list: list of BeautifulSoup element from cell in HTML table
+
+    Return list of accessions."""
+    accessions = []
+
+    for bs_element in bs_element_lst:
+        try:
+            if bs_element.name == "a":  # Hyperlinked, extract accession and add to primary
+                accessions.append(bs_element.text)
+            elif bs_element.strip() != "":  # There is text in element
+                accessions.append(bs_element)
+        except TypeError:
+            pass
+
+    return accessions
+
+
 def browser_decorator(func):
-    """Decorator to retry the wrapped function up to 'retries' times."""
+    """Decorator to re-invoke the wrapped function up to 'args.retries' times."""
 
-    def wrapper(*args, retries=10, **kwargs):
+    def wrapper(*args, **kwargs):
+        logger = logging.getLogger(__name__)
         tries, success, err = 0, False, None
-        while not success and (tries < retries):
+
+        while not success and (tries < kwargs['max_tries']):
             try:
                 response = func(*args, **kwargs)
             except (
@@ -681,6 +1026,12 @@ def wrapper(*args, retries=10, **kwargs):
                 MissingSchema,
                 RequestError,
             ) as err_message:
+                if (tries < kwargs['max_tries']):
+                    logger.warning(
+                        f"Failed to connect to CAZy on try {tries}/{kwargs['max_tries']}.\n"
+                        f"Error: {err_message}"
+                        "Retrying connection to CAZy in 10s"
+                    )
                 success = False
                 response = None
                 err = err_message
@@ -690,6 +1041,7 @@ def wrapper(*args, retries=10, **kwargs):
             tries += 1
             time.sleep(10)
         if (not success) or (response is None):
+            logger.warning(f"Failed to connect to CAZy.\nError: {err}")
             return [None, err]
         else:
             return [response, None]
@@ -698,17 +1050,19 @@ def wrapper(*args, retries=10, **kwargs):
 
 
 @browser_decorator
-def get_page(url):
+def get_page(url, args, **kwargs):
     """Create browser and use browser to retrieve page for given URL.
 
     :param url: str, url to webpage
+    :param args: cmd-line args parser
+    :kwargs max_tries: max number of times connection to CAZy can be attempted
 
     Return browser response object (the page).
     """
     # create browser object
     browser = mechanicalsoup.Browser()
     # create response object
-    page = browser.get(url)
+    page = browser.get(url, timeout=args.timeout)
     page = page.soup
 
     return page
diff --git a/scraper/expand/__init__.py b/scraper/expand/__init__.py
new file mode 100644
index 00000000..f4c6ddcb
--- /dev/null
+++ b/scraper/expand/__init__.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
+# Author:
+# Emma E. M. Hobbs
+
+# Contact
+# eemh1@st-andrews.ac.uk
+
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+
+# The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+"""A module for expanding the the local CAZY database beyond what is provided within CAZy."""
diff --git a/scraper/expand/get_genbank_sequences.py b/scraper/expand/get_genbank_sequences.py
new file mode 100644
index 00000000..593e511d
--- /dev/null
+++ b/scraper/expand/get_genbank_sequences.py
@@ -0,0 +1,817 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
+# Author:
+# Emma E. M. Hobbs
+
+# Contact
+# eemh1@st-andrews.ac.uk
+
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+
+# The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+"""Retrieve proteins sequences from GenBank and populate the local database and write to FASTA"""
+
+
+import logging
+import os
+import re
+import sys
+import time
+
+import pandas as pd
+
+from datetime import datetime
+from typing import List, Optional
+
+from Bio import Entrez, SeqIO
+from tqdm import tqdm
+
+from scraper.sql.sql_orm import (
+    Cazyme,
+    CazyFamily,
+    Cazymes_Genbanks,
+    Genbank,
+    Taxonomy,
+    get_db_session,
+)
+from scraper.utilities import config_logger, file_io, parse_configuration
+from scraper.utilities.parsers import build_genbank_sequences_parser
+
+
+def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = None):
+    """Set up programme and initate run."""
+    start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")  # used in terminating message
+    start_time = pd.to_datetime(start_time)
+    date_today = datetime.now().strftime("%Y/%m/%d")  # used as seq_update_date in the db
+
+    # parse cmd-line arguments
+    if argv is None:
+        parser = build_genbank_sequences_parser()
+        args = parser.parse_args()
+    else:
+        args = build_genbank_sequences_parser(argv).parse_args()
+
+    if logger is None:
+        logger = logging.getLogger(__name__)
+        config_logger(args)
+
+    # check database was passed
+    if os.path.isfile(args.database) is False:
+        logger.error(
+            "Could not find local CAZy database. Check path is correct. Terminating programme."
+        )
+        sys.exit(1)
+
+    Entrez.email = args.email
+
+    # create session to local database
+    session = get_db_session(args)
+
+    # retrieve configuration data
+    file_io_path = file_io.__file__
+    config_dict, taxonomy_filters = parse_configuration.get_configuration(file_io_path, args)
+
+    if config_dict is None:
+        if args.update:
+            # get sequence for everything without a sequence and those with newer remote sequence
+            add_and_update_all_sequences(date_today, taxonomy_filters, session, args)
+
+        else:
+            # get sequences for everything without a sequence
+            get_missing_sequences_for_everything(date_today, taxonomy_filters, session, args)
+
+    else:
+        # get sequences for only specified classes/families
+        if args.update:
+            update_sequences_for_specific_records(
+                date_today,
+                config_dict,
+                taxonomy_filters,
+                session,
+                args,
+            )
+        else:
+            get_missing_sequences_for_specific_records(
+                date_today,
+                config_dict,
+                taxonomy_filters,
+                session,
+                args,
+            )
+
+    end_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")  # used in terminating message
+    end_time = pd.to_datetime(start_time)
+    end_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+    end_time = pd.to_datetime(end_time)
+    total_time = end_time - start_time
+
+    logger.info(
+        "Finished populating local CAZy database with GenBank protein sequences. "
+        "Terminating program.\n"
+        f"Scrape initated at {start_time}\n"
+        f"Scrape finished at {end_time}\n"
+        f"Total run time: {total_time}"
+    )
+
+    print(
+        "=====================cazy_webscraper-expand-genank_sequences=====================\n"
+        "Finished populating local CAZy database with GenBank protein sequences. "
+        "Terminating program.\n"
+        f"Scrape initated at {start_time}\n"
+        f"Scrape finished at {end_time}\n"
+        f"Total run time: {total_time}\n"
+    )
+
+
+# The folowing functions are for querying the local database to get GenBank accessions
+
+
+def get_missing_sequences_for_everything(date_today, taxonomy_filters, session, args):
+    """Retrieve protein sequences for all CAZymes in the local CAZy database that don't have seq.
+
+    :param date_today: str, today's date, used for logging the date the seq is retrieved in the db
+    :param taxonomy_filters: set of genera, species and strains to restrict sequence retrieval
+    :param session: open SQLite db session
+    :param args: cmd-line argument parser
+
+    Return nothing.
+    """
+    logger = logging.getLogger(__name__)
+
+    # retrieve only sequences for primary GenBank accessions, and those without sequences
+    if args.primary is True:
+        logger.warning(
+            "Retrieving sequences for all primary GenBank accessions that do not have sequences"
+        )
+        genbank_query = session.query(Genbank.genbank_accession, Cazymes_Genbanks, Taxonomy).\
+            join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+            filter(Cazymes_Genbanks.primary == True).\
+            filter(Genbank.sequence == None).\
+            all()
+
+    # retrieve sequences for all GenBank accessions without sequences
+    else:
+        logger.warning(
+            "Retrieving sequences for all GenBank accessions that do not have sequences"
+        )
+        genbank_query = session.query(Genbank.genbank_accession, Cazymes_Genbanks, Taxonomy).\
+            join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+            filter(Genbank.sequence == None).\
+            all()
+
+    # retrieve the genbank_accessions
+    accessions = extract_accessions(genbank_query, taxonomy_filters)
+
+    if len(accessions) == 0:
+        logger.warning(
+            "Did not retrieve any GenBank accessions from the local database\n"
+            "that have sequences missing. Not adding sequences to the local database."
+        )
+        return
+
+    # separate accesions in to separate lists of length args.epost, epost doesn't like more than 200
+    accessions = get_accession_chunks(accessions, args.epost)  # args.epost = number per chunk
+    for lst in accessions:
+        get_sequences_add_to_db(lst, date_today, session, args)
+    return
+
+
+def add_and_update_all_sequences(date_today, taxonomy_filters, session, args):
+    """Retrieve sequences for all proteins in the database.
+
+    For records with no sequences, add the retrieved sequence.
+    For records with a sequence, check if the remove sequence is more recent than the existing
+    sequence. It it is, update the local sequence.
+
+    :param date_today: str, today's date, used for logging the date the seq is retrieved in the db
+    :param taxonomy_filters: set of genera, species and strains to retrieve sequences for
+    :param session: open SQLite db session
+    :param args: cmd-line argument parser
+
+    Return nothing.
+    """
+    logger = logging.getLogger(__name__)
+
+    # retrieve only sequences for primary GenBank accessions, and those without sequences
+    if args.primary is True:
+        logger.warning(
+            "Retrieving sequences for all primary GenBank accessions that do not have sequences\n"
+            "and those whose sequences have been updated in NCBI "
+            "since they were retrieved previously"
+        )
+        genbank_query = session.query(Genbank, Cazymes_Genbanks, Taxonomy).\
+            join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+            filter(Cazymes_Genbanks.primary == True).\
+            all()
+
+    # retrieve sequences for all GenBank accessions
+    else:
+        logger.warning(
+            "Retrieving sequences for all GenBank accessions that do not have sequences\n"
+            "and those whose sequences have been updated in NCBI "
+            "since they were retrieved previously"
+        )
+        genbank_query = session.query(Genbank, Cazymes_Genbanks, Taxonomy).\
+            join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+            all()
+
+    # create dictionary of {genbank_accession: 'sequence update date' (str)}
+    accessions = extract_accessions_and_dates(genbank_query, taxonomy_filters)
+
+    if len(accessions.keys()) == 0:
+        logger.warning(
+            "Did not retrieve any GenBank accessions from the local database.\n"
+            "Not adding sequences to the local database."
+        )
+        return
+
+    accessions = get_accessions_for_new_sequences(accessions)  # list of genkbank_accession
+
+    if len(accessions) == 0:
+        logger.warning(
+            "Did not retrieve any GenBank accessions whose sequences need updating.\n"
+            "Not adding sequences to the local database."
+        )
+        return
+
+    # separate accesions in to separate lists of length args.epost, epost doesn't like more than 200
+    accessions = get_accession_chunks(accessions, args.epost)  # args.epost = number per chunk
+    for lst in accessions:
+        get_sequences_add_to_db(lst, date_today, session, args)
+    return
+
+
+def get_missing_sequences_for_specific_records(
+    date_today,
+    config_dict,
+    taxonomy_filters,
+    session,
+    args,
+):
+    """Coordinate getting the sequences for specific CAZymes, not with seqs in the db.
+
+    :param date_today: str, today's date, used for logging the date the seq is retrieved in the db
+    :param config_dict: dict, defines CAZy classes and families to get sequences for
+    :param taxonomy_filters: set of genera, species and strains to restrict sequence retrieval
+    :param session: open SQL database session
+    :param args: cmd-line args parser
+
+    Return nothing.
+    """
+    logger = logging.getLogger(__name__)
+    logger.warning(
+        "Retrieving sequences for GenBank accessions that do not have a sequence in the database"
+    )
+
+    # start with the classes
+    if len(config_dict["classes"]) != 0:
+        # retrieve list of CAZy classes to get sequences for
+        cazy_classes = config_dict["classes"]
+
+        for cazy_class in tqdm(cazy_classes, desc="Parsing CAZy classes"):
+            # retrieve class name abbreviation
+            cazy_class = cazy_class[((cazy_class.find("(")) + 1):((cazy_class.find(")")) - 1)]
+
+            # get the CAZymes within the CAZy class
+            class_subquery = session.query(Cazyme.cazyme_id).\
+                join(CazyFamily, Cazyme.families).\
+                filter(CazyFamily.family.regexp(rf"{cazy_class}\d+")).\
+                subquery()
+
+            # retrieve the GenBank accessions of the CAZymes in the CAZy class without seqs
+            if args.primary:
+                genbank_query = session.query(Genbank, Cazymes_Genbanks, Cazyme, Taxonomy).\
+                    join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+                    join(Cazyme, (Cazyme.cazyme_id == Cazymes_Genbanks.cazyme_id)).\
+                    filter(Cazyme.cazyme_id.in_(class_subquery)).\
+                    filter(Cazymes_Genbanks.primary == True).\
+                    filter(Genbank.sequence == None).\
+                    all()
+            else:
+                genbank_query = session.query(Genbank, Cazymes_Genbanks, Cazyme, Taxonomy).\
+                    join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+                    join(Cazyme, (Cazyme.cazyme_id == Cazymes_Genbanks.cazyme_id)).\
+                    filter(Cazyme.cazyme_id.in_(class_subquery)).\
+                    filter(Genbank.sequence == None).\
+                    all()
+
+            # retrieve the genbank_accessions from the sql collection object returned by the query
+            accessions = extract_accessions(genbank_query, taxonomy_filters)
+
+            if len(accessions) == 0:
+                logger.warning(
+                    f"Did not retrieve any GenBank accessions for the CAZy class {cazy_class}\n"
+                    "that have missing sequences. Not adding sequences to the local database."
+                )
+                continue
+
+            # separate accesions in to separate lists of length args.epost
+            # epost doesn't like posting more than 200 at once
+            accessions = get_accession_chunks(accessions, args.epost)  # args.epost = number/chunk
+            for lst in accessions:
+                get_sequences_add_to_db(lst, date_today, session, args)
+            continue
+
+    # Retrieve protein sequences for specified families
+    for key in config_dict:
+        if key == "classes":
+            continue
+        if config_dict[key] is None:
+            continue  # no families to parse
+
+        for family in tqdm(config_dict[key], desc=f"Parsing families in {key}"):
+            if family.find("_") != -1:  # subfamily
+                # Retrieve GenBank accessions catalogued under the subfamily
+                family_subquery = session.query(Cazyme.cazyme_id).\
+                    join(CazyFamily, Cazyme.families).\
+                    filter(CazyFamily.subfamily == family).\
+                    subquery()
+
+            else:  # family
+                # Retrieve GenBank accessions catalogued under the family
+                family_subquery = session.query(Cazyme.cazyme_id).\
+                    join(CazyFamily, Cazyme.families).\
+                    filter(CazyFamily.family == family).\
+                    subquery()
+
+            # get the GenBank accessions of thes CAZymes, without sequences
+            if args.primary:
+                genbank_query = session.query(Genbank, Cazymes_Genbanks, Cazyme, Taxonomy).\
+                    join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+                    join(Cazyme, (Cazyme.cazyme_id == Cazymes_Genbanks.cazyme_id)).\
+                    filter(Cazyme.cazyme_id.in_(family_subquery)).\
+                    filter(Cazymes_Genbanks.primary == True).\
+                    filter(Genbank.sequence == None).\
+                    all()
+            else:
+                genbank_query = session.query(Genbank, Cazymes_Genbanks, Cazyme, Taxonomy).\
+                    join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+                    join(Cazyme, (Cazyme.cazyme_id == Cazymes_Genbanks.cazyme_id)).\
+                    filter(Cazyme.cazyme_id.in_(family_subquery)).\
+                    filter(Genbank.sequence == None).\
+                    all()
+
+            # retrieve a list of GenBank accessions from the sql collection returned from the query
+            accessions = extract_accessions(genbank_query, taxonomy_filters)
+
+            if len(accessions) == 0:
+                logger.warning(
+                    f"Did not retrieve any GenBank accessions for the CAZy class {family}\n"
+                    "that have missing sequences. Not adding sequences to the local database."
+                )
+                continue
+            # separate accesions in to separate lists of length args.epost
+            # epost doesn't like posting more than 200 at once
+            accessions = get_accession_chunks(accessions, args.epost)  # args.epost = acc/chunk
+            for lst in accessions:
+                get_sequences_add_to_db(lst, date_today, session, args)
+
+    return
+
+
+def update_sequences_for_specific_records(date_today, config_dict, taxonomy_filters, session, args):
+    """Coordinate getting the sequences for specific CAZymes, not with seqs in the db nad those
+    whose seq in NCBI has been updated since the last retrieval.
+
+    For records with no sequences, add the retrieved sequence.
+    For records with a sequence, check if the remove sequence is more recent than the existing
+    sequence. It it is, update the local sequence.
+
+    :param date_today: str, today's date, used for logging the date the seq is retrieved in the db
+    :param config_dict: dict, defines CAZy classes and families to get sequences for
+    :param taxonomy_filters: set of genera, species and strains to restrict sequence retrieval
+    :param session: open SQL database session
+    :param args: cmd-line args parser
+
+    Return nothing.
+    """
+    logger = logging.getLogger(__name__)
+    logger.warning(
+        "Retrieving sequences for GenBank accessions that do not have a sequence in the database,\n"
+        "and those whose sequence in NCBI has been updated since they were previously retrieved."
+    )
+
+    # start with the classes
+    if len(config_dict["classes"]) != 0:
+        # retrieve list of CAZy classes to get sequences for
+        cazy_classes = config_dict["classes"]
+
+        for cazy_class in tqdm(cazy_classes, desc="Parsing CAZy classes"):
+            # retrieve class name abbreviation
+            cazy_class = cazy_class[((cazy_class.find("(")) + 1):((cazy_class.find(")")) - 1)]
+
+            # get the CAZymes within the CAZy class
+            class_subquery = session.query(Cazyme.cazyme_id).\
+                join(CazyFamily, Cazyme.families).\
+                filter(CazyFamily.family.regexp(rf"{cazy_class}\d+")).\
+                subquery()
+
+            # retrieve the GenBank accessions of the CAZymes in the CAZy class without seqs
+            if args.primary:
+                genbank_query = session.query(Genbank, Cazymes_Genbanks, Cazyme, Taxonomy).\
+                    join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+                    join(Cazyme, (Cazyme.cazyme_id == Cazymes_Genbanks.cazyme_id)).\
+                    filter(Cazyme.cazyme_id.in_(class_subquery)).\
+                    filter(Cazymes_Genbanks.primary == True).\
+                    all()
+            else:
+                genbank_query = session.query(Genbank, Cazymes_Genbanks, Cazyme, Taxonomy).\
+                    join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+                    join(Cazyme, (Cazyme.cazyme_id == Cazymes_Genbanks.cazyme_id)).\
+                    filter(Cazyme.cazyme_id.in_(class_subquery)).\
+                    all()
+
+            # create dictionary of genbank_accession: 'sequence update date' (str)
+            accessions = extract_accessions_and_dates(genbank_query, taxonomy_filters)
+
+            if len(accessions.keys()) == 0:
+                logger.warning(
+                    f"Did not retrieve any GenBank accessions for the CAZy class {cazy_class}.\n"
+                    "Not adding sequences to the local database."
+                )
+                continue
+
+            accessions = get_accessions_for_new_sequences(accessions)  # list of genkbank_accession
+
+            if len(accessions) == 0:
+                logger.warning(
+                    "Did not retrieve any GenBank accessions whose sequences need updating for "
+                    f"the CAZy class {cazy_class}.\n"
+                    "Not adding sequences to the local database."
+                )
+                continue
+            # separate accesions in to separate lists of length args.epost
+            # epost doesn't like posting more than 200 at once
+            accessions = get_accession_chunks(accessions, args.epost)  # args.epost = acc/chunk
+            for lst in accessions:
+                get_sequences_add_to_db(lst, date_today, session, args)
+
+    # Retrieve protein sequences for specified families
+    for key in config_dict:
+        if key == "classes":
+            continue
+        if config_dict[key] is None:
+            continue  # no families to parse
+
+        for family in tqdm(config_dict[key], desc=f"Parsing families in {key}"):
+            if family.find("_") != -1:  # subfamily
+                # Retrieve GenBank accessions catalogued under the subfamily
+                family_subquery = session.query(Cazyme.cazyme_id).\
+                    join(CazyFamily, Cazyme.families).\
+                    filter(CazyFamily.subfamily == family).\
+                    subquery()
+
+            else:  # family
+                # Retrieve GenBank accessions catalogued under the family
+                family_subquery = session.query(Cazyme.cazyme_id).\
+                    join(CazyFamily, Cazyme.families).\
+                    filter(CazyFamily.family == family).\
+                    subquery()
+
+            # get the GenBank accessions of thes CAZymes, without sequences
+            if args.primary:
+                genbank_query = session.query(Genbank, Cazymes_Genbanks, Cazyme, Taxonomy).\
+                    join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+                    join(Cazyme, (Cazyme.cazyme_id == Cazymes_Genbanks.cazyme_id)).\
+                    filter(Cazyme.cazyme_id.in_(family_subquery)).\
+                    filter(Cazymes_Genbanks.primary == True).\
+                    filter(Genbank.sequence == None).\
+                    all()
+            else:
+                genbank_query = session.query(Genbank, Cazymes_Genbanks, Cazyme, Taxonomy).\
+                    join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+                    join(Cazyme, (Cazyme.cazyme_id == Cazymes_Genbanks.cazyme_id)).\
+                    filter(Cazyme.cazyme_id.in_(family_subquery)).\
+                    filter(Genbank.sequence == None).\
+                    all()
+
+            # create dictionary of {genbank_accession: 'sequence update date' (str)}
+            accessions = extract_accessions_and_dates(genbank_query, taxonomy_filters)
+
+            if len(accessions.keys()) == 0:
+                logger.warning(
+                    f"Did not retrieve any GenBank accessions for the CAZy class {family}.\n"
+                    "Not adding sequences to the local database."
+                )
+                continue
+
+            accessions = get_accessions_for_new_sequences(accessions)  # list of genkbank_accession
+
+            if len(accessions) == 0:
+                logger.warning(
+                    "Did not retrieve any GenBank accessions whose sequences need updating for "
+                    f"the CAZy class {family}.\n"
+                    "Not adding sequences to the local database."
+                )
+                continue
+            # separate accesions in to separate lists of length args.epost
+            # epost doesn't like posting more than 200 at once
+            accessions = get_accession_chunks(accessions, args.epost)  # args.epost = acc/chunk
+            for lst in accessions:
+                get_sequences_add_to_db(lst, date_today, session, args)
+
+    return
+
+
+# The following functions are retrieving the list of Genbank accessions to retrieve sequences for #
+
+
+def extract_accessions(genbank_query, taxonomy_filters):
+    """The query contains GenBank accessions and Cazymes_Genbanks records, retrieve the accessions.
+
+    :param genbank_query: sql collection
+    :param taxonomy_filters: set of genera, species and strains to restrict retrieval of sequences
+
+    Return a list of GenBank accessions. Each element is a string of a unique accession.
+    """
+    if taxonomy_filters is None:
+        accessions = [item[0] for item in genbank_query]
+        return [x for x in accessions if "NA" != x]
+
+    else:
+        accessions = []
+        for item in genbank_query:
+            if item[0] != "NA":  # if GenBank accession not stored as 'NA'
+                source_organism = item[-1].genus + item[-1].species
+                if any(filter in source_organism for filter in taxonomy_filters):
+                    accessions.append(item[0])
+    return accessions
+
+
+def extract_accessions_and_dates(genbank_query, taxonomy_filters):
+    """Retrieve the GenBank accessions and retrieval dates of existing sequences from the db query.
+
+    :param genbank_query: sql collection
+    :param taxonomy_filters: set of genera, species and strains to restrict retrieval of sequences
+
+    Return a dict {GenBank_accession: retrieval_date}
+    """
+    accessions = {}
+
+    if taxonomy_filters is None:
+        for item in genbank_query:
+            if item[0].genbank_accession == "NA":  # no GenBank accession stored in CAZy
+                continue
+            accessions[item[0].genbank_accession] = item[0].seq_update_date
+
+    else:
+        for item in genbank_query:
+            if item[0].genbank_accession == "NA":  # no GenBank accession stored in CAZy
+                continue
+            source_organism = item[-1].genus + item[-1].species
+            if any(filter in source_organism for filter in taxonomy_filters):
+                accessions[item[0].genbank_accession] = item[0].seq_update_date
+
+    return accessions
+
+
+def get_accessions_for_new_sequences(accessions):
+    """Get the GenBank accessions of sequences to be added to the local database.
+
+    For records currently with no protein sequence, the retrieved protein sequence will be added
+    to the record. For records with a sequence, the 'UpdateDate' for the sequence from NCBI will
+    be compared against the  'seq_update_date' in the local database. The 'seq_update_date' is the
+    'UpdateDate' previosuly retrieved from NCBI. If the NCBI sequence is newer,
+    the local database will be updated with the new sequence.
+
+    :param accessions: dict, {GenBank accessions (str):sequence retrieval data (str)}
+    :param session: open SQL database session
+
+    Return nothing.
+    """
+    logger = logging.getLogger(__name__)
+
+    accessions_list = list(accessions.keys())
+    accessions_string = ",".join(accessions_list)
+    # perform batch query of Entrez
+    epost_result = Entrez.read(
+        entrez_retry(
+            Entrez.epost, "Protein", id=accessions_string, retmode="text",
+        )
+    )
+    # retrieve the web environment and query key from the Entrez post
+    epost_webenv = epost_result["WebEnv"]
+    epost_query_key = epost_result["QueryKey"]
+
+    # retrieve summary docs to check the sequence 'UpdateDates' in NCBI
+    with entrez_retry(
+        Entrez.efetch,
+        db="Protein",
+        query_key=epost_query_key,
+        WebEnv=epost_webenv,
+        rettype="docsum",
+        retmode="xml",
+    ) as handle:
+        summary_docs = Entrez.read(handle)
+
+    for doc in summary_docs:
+        try:
+            temp_accession = doc["AccessionVersion"]  # accession of the current working protein
+        except KeyError:
+            logger.warning(
+                f"Retrieved protein with accession {temp_accession} but this accession is not in "
+                "the local database.\n"
+                "Not retrieving a sequence for this accession."
+            )
+            continue
+        previous_data = accessions[temp_accession]
+        if previous_data is not None:
+            # sequence retrieved previosuly, thus check if the NCBI seq has been updated since
+            previous_data = previous_data.split("/")  # Y=[0], M=[1], D=[]
+            update_date = doc["UpdateDate"]
+            update_date = update_date.split("/")  # Y=[0], M=[1], D=[]
+            if datetime.date(
+                previous_data[0], previous_data[1], previous_data[2],
+            ) < datetime.data(
+                update_date[0], update_date[1], update_date[2],
+            ) is False:
+                # the sequence at NCBI has not been updated since the seq was retrieved
+                # thus no need to retrieve it again
+                accessions_list.remove(temp_accession)
+
+    return accessions_list
+
+
+def get_accession_chunks(lst, chunk_length):
+    """Separate the long list into separate chunks.
+
+    :param lst: list to be separated into smaller lists (or chunks)
+    :param chunk_length: int, the length of the lists the longer list is to be split up into
+
+    Return a generator object containing lists.
+    """
+    for i in range(0, len(lst), chunk_length):
+        yield lst[i:i + chunk_length]
+
+
+# The following functions are for retrieving sequences, adding to the db and writing fasta files
+
+
+def get_sequences_add_to_db(accessions, date_today, session, args):
+    """Retrieve protein sequences from Entrez and add to the local database.
+
+    :param accessions: list, GenBank accessions
+    :param date_today: str, YYYY/MM/DD
+    :param session: open SQL database session
+    :param args: cmb-line args parser
+
+    Return nothing.
+    """
+    logger = logging.getLogger(__name__)
+    # perform batch query of Entrez
+    accessions_string = ",".join(accessions)
+    epost_result = Entrez.read(
+        entrez_retry(
+            Entrez.epost, "Protein", id=accessions_string,
+        )
+    )
+    # retrieve the web environment and query key from the Entrez post
+    epost_webenv = epost_result["WebEnv"]
+    epost_query_key = epost_result["QueryKey"]
+
+    # retrieve the protein sequences
+    with entrez_retry(
+        Entrez.efetch,
+        db="Protein",
+        query_key=epost_query_key,
+        WebEnv=epost_webenv,
+        rettype="fasta",
+        retmode="text",
+    ) as seq_handle:
+        for record in SeqIO.parse(seq_handle, "fasta"):
+            # retrieve the accession of the record
+            temp_accession = record.id  # accession of the current working protein record
+
+            if temp_accession.find("|") != -1:  # sometimes multiple items are listed
+                success = False   # will be true if finds protein accession
+                temp_accession = temp_accession.split("|")
+                for item in temp_accession:
+                    # check if a accession number
+                    try:
+                        re.match(
+                            (
+                                r"(\D{3}\d{5,7}\.\d+)|(\D\d(\D|\d){3}\d)|"
+                                r"(\D\d(\D|\d){3}\d\D(\D|\d){2}\d)"
+                            ),
+                            item,
+                        ).group()
+                        temp_accession = item
+                        success = True
+                        break
+                    except AttributeError:  # raised if not an accession
+                        continue
+
+            else:
+                success = True  # have protein accession number
+
+            if success is False:
+                logger.error(
+                    f"Could not retrieve accession from {record.id}, therefore, "
+                    "protein sequence not added to the database,\n"
+                    "because cannot retrieve the necessary CAZyme record"
+                )
+                continue
+
+            # check the retrieve protein accession is in the list of retrieved accession
+            if temp_accession not in accessions:
+                logger.warning(
+                    f"Retrieved the accession {temp_accession} from the record id={record.id}, "
+                    "but this accession is not in the database.\n"
+                    "Therefore, not adding this protein seqence to the local database"
+                )
+                continue
+
+            # retrieve the GenBank record from the local data base to add the seq to
+            genbank_record = session.query(Genbank).\
+                filter(Genbank.genbank_accession == temp_accession).first()
+
+            retrieved_sequence = str(record.seq)  # convert to a string becuase SQL expects a string
+            genbank_record.sequence = retrieved_sequence
+            genbank_record.seq_update_date = date_today
+            session.commit()
+
+            if args.write is not None:
+                file_io.write_out_fasta(record, temp_accession, args)
+
+            # remove the accession from the list
+            accessions.remove(temp_accession)
+
+    if len(accessions) != 0:
+        logger.warning(
+            "Protein sequences were not retrieved for the following CAZyme in the local database"
+        )
+        for acc in accessions:
+            logger.warning(f"GenBank accession: {acc}")
+
+    return
+
+
+def entrez_retry(entrez_func, *func_args, **func_kwargs):
+    """Call to NCBI using Entrez.
+
+    Maximum number of retries is 10, retry initated when network error encountered.
+
+    :param logger: logger object
+    :param retries: parser argument, maximum number of retries excepted if network error encountered
+    :param entrez_func: function, call method to NCBI
+
+    :param *func_args: tuple, arguments passed to Entrez function
+    :param ** func_kwargs: dictionary, keyword arguments passed to Entrez function
+
+    Returns record.
+    """
+    logger = logging.getLogger(__name__)
+    record, retries, tries = None, 10, 0
+
+    while record is None and tries < retries:
+        try:
+            record = entrez_func(*func_args, **func_kwargs)
+
+        except IOError:
+            # log retry attempt
+            if tries < retries:
+                logger.warning(
+                    f"Network error encountered during try no.{tries}.\nRetrying in 10s",
+                    exc_info=1,
+                )
+                time.sleep(10)
+            tries += 1
+
+    if record is None:
+        logger.error(
+            "Network error encountered too many times. Exiting attempt to call to NCBI"
+        )
+        return
+
+    return record
+
+
+if __name__ == "__main__":
+    main()
diff --git a/scraper/expand/get_pdb_structures.py b/scraper/expand/get_pdb_structures.py
new file mode 100644
index 00000000..a933c469
--- /dev/null
+++ b/scraper/expand/get_pdb_structures.py
@@ -0,0 +1,298 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
+# Author:
+# Emma E. M. Hobbs
+
+# Contact
+# eemh1@st-andrews.ac.uk
+
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+
+# The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# Bio.PDB reference:
+# Hamelryck, T., Manderick, B. (2003) PDB parser and structure class 
+# implemented in Python. Bioinformatics 19: 2308–2310
+"""Retrieve PDB structures from RSCB PDB and write to disk"""
+
+
+import logging
+import os
+import sys
+import time
+
+import pandas as pd
+
+from datetime import datetime
+from typing import List, Optional
+
+from Bio.PDB import PDBList
+from tqdm import tqdm
+
+from scraper.sql.sql_orm import (
+    Cazyme,
+    CazyFamily,
+    Pdb,
+    Taxonomy,
+    get_db_session,
+)
+from scraper.utilities import config_logger, file_io, parse_configuration
+from scraper.utilities.parsers import build_pdb_structures_parser
+
+
+def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = None):
+    """Set up programme and initate run."""
+    start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")  # used in terminating message
+    start_time = pd.to_datetime(start_time)
+
+    # parse cmd-line arguments
+    if argv is None:
+        parser = build_pdb_structures_parser()
+        args = parser.parse_args()
+    else:
+        parser = build_pdb_structures_parser(argv)
+        args = parser.parse_args()
+
+    # build logger
+    if logger is None:
+        logger = logging.getLogger(__name__)
+        config_logger(args)
+
+    # create session to local database
+    if os.path.isfile(args.database) is False:
+        logger.error(
+            "Could not find local CAZy database. Check path is correct. Terminating programme."
+        )
+        sys.exit(1)
+    session = get_db_session(args)
+
+    # create output directory
+    if args.outdir is None:
+        # save structure files to the cwd
+        outdir = os.getcwd()
+    else:
+        outdir = args.outdir
+    file_io.make_output_directory(outdir, args.force, args.nodelete)
+
+    # check if any classes or families were specified to retrieve the sequences only for them
+    file_io_path = file_io.__file__
+    config_dict, taxonomy_filters = parse_configuration.get_configuration(file_io_path, args)
+
+    # retrieve protein structures from PDB
+
+    # retrieve sequences for all CAZymes
+    if config_dict is None:
+        get_every_cazymes_structures(outdir, taxonomy_filters, session, args)
+
+    # retrieve sequences for specific CAZy classes and/or families
+    else:
+        get_structures_for_specific_cazymes(outdir, config_dict, taxonomy_filters, session, args)
+
+    end_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")  # used in terminating message
+    end_time = pd.to_datetime(start_time)
+    end_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+    end_time = pd.to_datetime(end_time)
+    total_time = end_time - start_time
+
+    logger.info(
+        "Finished dowloading protein structures from PDB."
+        "Terminating program.\n"
+        f"Scrape initated at {start_time}\n"
+        f"Scrape finished at {end_time}\n"
+        f"Total run time: {total_time}"
+    )
+
+    print(
+        "=====================cazy_webscraper-expand-pdb_structures=====================\n"
+        "Finished dowloading protein structures from PDB."
+        "Terminating program.\n"
+        f"Scrape initated at {start_time}\n"
+        f"Scrape finished at {end_time}\n"
+        f"Total run time: {total_time}\n"
+    )
+
+
+def get_every_cazymes_structures(outdir, taxonomy_filters, session, args):
+    """Get PDB accessions in the db, and coordinate downloading the structure from pdb.
+
+    :param outdir: path to output directory
+    :param taxonomy_filters: set of genera, species, and strains to retrieve structures for
+    :param session: open SQLite db session
+    :param args: cmd-line argument parser
+
+    Return nothing.
+    """
+    # retrieve structures for only primary PDB accessions
+    if args.primary is True:
+        pdb_query = session.query(Pdb, Cazyme, Taxonomy).\
+            join(Cazyme.pdbs).join(Cazyme.taxonomy).filter(Pdb.primary == True).all()
+
+    # retrieve structures for all PDB accessions
+    else:
+        pdb_query = session.query(Pdb, Cazyme, Taxonomy).\
+            join(Cazyme.pdbs).join(Cazyme.taxonomy).all()
+
+    if taxonomy_filters is None:
+        for query_result in pdb_query:
+            pdb_accession = query_result[0].pdb_accession
+            pdb_accession = pdb_accession[:pdb_accession.find("[")]
+            download_pdb_structures(pdb_accession, outdir, args)
+
+    else:
+        for query_result in pdb_query:
+            source_organism = query_result[-1].genus + query_result[-1].species
+            if any(filter in source_organism for filter in taxonomy_filters):
+                pdb_accession = query_result[0].pdb_accession
+                pdb_accession = pdb_accession[:pdb_accession.find("[")]
+                download_pdb_structures(pdb_accession, outdir, args)
+
+    return
+
+
+def get_structures_for_specific_cazymes(outdir, config_dict, taxonomy_filters, session, args):
+    """Retrieve primary PDB accessions for CAZymes meeting criteria in the config_dict.
+
+    :param outdir: path to output directory
+    :param config_dict: dict, defines CAZy classes and families to retrieve accessions from
+    :param taxonomy_filters: set of genera, species, and strains to retrieve structures for
+    :param session: open SQLite db session
+    :param args: cmd-line argument parser
+
+    Return nothing.
+    """
+    # start with the classes
+    if len(config_dict["classes"]) != 0:
+        # create a dictionary to convert full class name to abbreviation
+        cazy_classes = config_dict["classes"]
+
+        for cazy_class in tqdm(cazy_classes, desc="Parsing CAZy classes"):
+            # retrieve class name abbreviation
+            cazy_class = cazy_class[((cazy_class.find("(")) + 1):((cazy_class.find(")")) - 1)]
+
+            # retrieve the CAZymes from the specified class
+            class_subquery = session.query(Cazyme.cazyme_id).\
+                join(CazyFamily, Cazyme.families).\
+                filter(CazyFamily.family.regexp(rf"{cazy_class}\d+")).\
+                subquery()
+
+            # Retrieve PDB accessions for the selected CAZymes
+            if args.primary:
+                pdb_query = session.query(Pdb, Cazyme, Taxonomy).\
+                    join(Cazyme.pdbs).join(Cazyme.taxonomy).\
+                    filter(Pdb.primary == True).filter(Cazyme.cazyme_id.in_(class_subquery)).all()
+
+            else:
+                pdb_query = session.query(Pdb, Cazyme, Taxonomy).\
+                    join(Cazyme.pdbs).join(Cazyme.taxonomy).\
+                    filter(Cazyme.cazyme_id.in_(class_subquery)).all()
+
+            if taxonomy_filters is None:
+                for query_result in pdb_query:
+                    pdb_accession = query_result[0].pdb_accession
+                    pdb_accession = pdb_accession[:pdb_accession.find("[")]
+                    download_pdb_structures(pdb_accession, outdir, args)
+
+            else:
+                for query_result in pdb_query:
+                    source_organism = query_result[-1].genus + query_result[-1].species
+                    if any(filter in source_organism for filter in taxonomy_filters):
+                        pdb_accession = query_result[0].pdb_accession
+                        pdb_accession = pdb_accession[:pdb_accession.find("[")]
+                        download_pdb_structures(pdb_accession, outdir, args)
+
+    # retrieve protein structure for specified families
+    for key in config_dict:
+        if key == "classes":
+            continue
+        if config_dict[key] is None:
+            continue
+
+        for family in tqdm(config_dict[key], desc=f"Parsing families in {key}"):
+            # Select the CAZymes under the specified (sub)family
+            if family.find("_") != -1:  # subfamily
+                # Retrieve GenBank accessions catalogued under the subfamily
+                family_subquery = session.query(Cazyme.cazyme_id).\
+                    join(CazyFamily, Cazyme.families).\
+                    filter(CazyFamily.subfamily == family).\
+                    subquery()
+
+            else:  # family
+                # Retrieve GenBank accessions catalogued under the family
+                family_subquery = session.query(Cazyme.cazyme_id).\
+                    join(CazyFamily, Cazyme.families).\
+                    filter(CazyFamily.family == family).\
+                    subquery()
+
+            # Retrieve PDB accessions of the selected CAZymes
+            if args.primary:
+                pdb_query = session.query(Pdb, Cazyme, Taxonomy).\
+                    join(Cazyme.pdbs).join(Cazyme.taxonomy).\
+                    filter(Pdb.primary == True).filter(Cazyme.cazyme_id.in_(family_subquery)).all()
+
+            else:
+                pdb_query = session.query(Pdb, Cazyme, Taxonomy).\
+                    join(Cazyme.pdbs).join(Cazyme.taxonomy).\
+                    filter(Cazyme.cazyme_id.in_(family_subquery)).all()
+
+            if taxonomy_filters is None:
+                for query_result in pdb_query:
+                    pdb_accession = query_result[0].pdb_accession
+                    pdb_accession = pdb_accession[:pdb_accession.find("[")]
+                    download_pdb_structures(pdb_accession, outdir, args)
+
+            else:
+                for query_result in pdb_query:
+                    source_organism = query_result[-1].genus + query_result[-1].species
+                    if any(filter in source_organism for filter in taxonomy_filters):
+                        pdb_accession = query_result[0].pdb_accession
+                        pdb_accession = pdb_accession[:pdb_accession.find("[")]
+                        download_pdb_structures(pdb_accession, outdir, args)
+
+    return
+
+
+def download_pdb_structures(pdb_accession, outdir, args):
+    """Download protein structure from the RSCB PDB database
+
+    :param pdb_accession: str, accession of record in the PDB database
+    :param outdir: path to output directory
+    :param args: cmd-line args parser
+
+    Return nothing.
+    """
+    pdbl = PDBList()
+    pdbl.retrieve_pdb_file(f"{pdb_accession}", file_format=args.pdb, pdir=args.outdir)
+    time.sleep(2)  # to prevent bombarding the system
+
+    return
+
+
+if __name__ == "__main__":
+    main()
diff --git a/scraper/parse/__init__.py b/scraper/parse/__init__.py
deleted file mode 100644
index 23db0557..00000000
--- a/scraper/parse/__init__.py
+++ /dev/null
@@ -1,419 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-# Author:
-# Emma E. M. Hobbs
-
-# Contact
-# eemh1@st-andrews.ac.uk
-
-# Emma E. M. Hobbs,
-# Biomolecular Sciences Building,
-# University of St Andrews,
-# North Haugh Campus,
-# St Andrews,
-# KY16 9ST
-# Scotland,
-# UK
-
-# The MIT License
-"""Module for parsing the webpages from CAZy."""
-
-
-import json
-import os
-import re
-import sys
-import time
-
-import pandas as pd
-
-from Bio import Entrez, SeqIO
-from Bio.PDB import PDBList
-from tqdm import tqdm
-
-from scraper.file_io import write_out_df
-
-
-def proteins_to_dataframe(families, time_stamp, args, logger):
-    """Write protein members of CAZy families to a pandas dataframe.
-
-    Duplicate rows are removed. These rows must be identical across the entire row, not only share
-    the same protein name. Duplicates are mostly likely to arise when scraping families and
-    subfamilies becuase proteins under the subfamily are also catalogued under the parent family.
-
-    :param families: list, list of CAZy families containing protein members
-    :param time_stamp: str, data and time scrape was initiated
-    :param args: args parser
-    :param logger: logger object
-
-    Return nothing.
-    """
-    # Build empty dictionary to store GenBank accession number synonyms
-    all_genbank_synonyms = {}
-
-    # Build empty dataframe to add proteins to
-    protein_dataframe = pd.DataFrame(
-        data={},
-        columns=[
-            "Protein_name",
-            "CAZy_family",
-            "EC#",
-            "Source_organism",
-            "GenBank",
-            "UniProt",
-            "PDB/3D",
-        ]
-    )
-
-    # add proteins to dataframe
-    for family in families:
-        proteins = family.get_proteins()
-        for protein in tqdm(proteins, desc=f"Writing {family.name} proteins to df"):
-            if protein is not None:
-                # write out protein to df
-                protein_dict = protein.get_protein_dict()
-                df = pd.DataFrame(protein_dict)
-                protein_dataframe = protein_dataframe.append(df, ignore_index=True)
-                # add synonym GenBank accessions to all synonyms accessions
-                genbank_synonyms = protein.genbank_synonyms
-                if genbank_synonyms is not None:
-                    all_genbank_synonyms.update(genbank_synonyms)
-
-    if args.subfamilies is True:
-        subfam = "_incld_subfams"
-    else:
-        subfam = ""
-    # compile dataframe name
-    if args.data_split == "family":
-        df_name = f"cazy_{families[0].name}{subfam}_{time_stamp}"
-        synonyms_dict = f"cazy_genbank_synonyms_{families[0].name}{subfam}_{time_stamp}"
-    elif args.data_split == "class":
-        df_name = f"cazy_{families[0].cazy_class}{subfam}_{time_stamp}"
-        synonyms_dict = f"cazy_genbank_synonyms_{families[0].cazy_class}{subfam}_{time_stamp}"
-    else:
-        df_name = f"cazy_scrape{subfam}_{time_stamp}"
-        synonyms_dict = f"cazy_genbank_synonyms{subfam}_{time_stamp}"
-
-    # Remove duplicate proteins
-    # This can arise when scraping subfamilies and families within a class
-    # The proteins within the subfamilies will also be listed under their parent family
-    protein_dataframe = protein_dataframe.drop_duplicates()
-
-    # write out dataframe
-    write_out_df(protein_dataframe, df_name, args.output, logger, args.force)
-
-    # write out dictionary of genbank_synonyms
-    if args.output is sys.stdout:
-        json.dump(all_genbank_synonyms, sys.stdout)
-
-    else:
-        output_path = args.output / f"{synonyms_dict}.json"
-        with open(output_path, "w") as fh:
-            json.dump(all_genbank_synonyms, fh)
-
-    # Additional parsing and retrieval of data: protein sequences and/or structures
-    if (args.genbank is not None) and (args.pdb is not None):
-        logger.info(f"Retrieving structures and sequences, for proteins in {df_name}")
-        get_structures_and_sequences(protein_dataframe, df_name, args, logger)
-
-    elif (args.genbank is not None) and (args.pdb is None):
-        logger.info(f"Retrieving FASTA files from GenBank, for proteins in {df_name}")
-        get_genbank_fasta(protein_dataframe, df_name, args, logger)
-
-    elif (args.genbank is None) and (args.pdb is not None):
-        logger.info(f"Retrieve PDB structure files for proteins in {df_name}")
-        get_pdb_structures(protein_dataframe, df_name, args, logger)
-
-    return
-
-
-def get_structures_and_sequences(protein_dataframe, df_name, args, logger):
-    """Coordinate the retrieval of CAZyme structure and sequences from PDB and GenBank.
-
-    :param protein_dataframe: Pandas dataframe, dataframe containing protein data from CAZy
-    :param df_name: str, name of the CAZy dataframe
-    :param args: cmd args parser
-    :param logger: logger object
-
-    Return nothing.
-    """
-    # set user email address for Entrez
-    Entrez.email = args.genbank
-
-    index = 0
-    pdbl = PDBList()
-    for index in tqdm(
-        range(len(protein_dataframe["Protein_name"])),
-        desc=f"Downloading {df_name} PDBs and FASTAs",
-    ):
-        # Retrieve accession from GenBank cell
-        df_row = protein_dataframe.iloc[index]
-        genbank_accession, cazy_family = get_genbank_accession(df_row, df_name, index, logger)
-        pdb_accessions = get_pdb_accessions(df_row, df_name, logger)
-
-        if genbank_accession is not None:
-            # get FASTA file from GenBank
-            fasta_name = f"{genbank_accession}_{cazy_family}.fasta"
-
-            if args.genbank_output is not sys.stdout:
-                fasta_name = args.genbank_output / fasta_name
-
-            download_fasta(genbank_accession, fasta_name, args, logger)
-
-        if pdb_accessions is not None:
-            # Get structure from PDB
-            if args.pdb_output is not None:
-                for accession in pdb_accessions:
-                    pdbl.retrieve_pdb_file(
-                        f"{accession}",
-                        file_format=args.pdb,
-                        pdir=args.pdb_output,
-                    )
-
-            else:
-                if args.output is not sys.stdout:
-                    for accession in pdb_accessions:
-                        pdbl.retrieve_pdb_file(
-                            f"{accession}",
-                            file_format=args.pdb,
-                            pdir=args.output,
-                        )
-                else:
-                    for accession in pdb_accessions:
-                        pdbl.retrieve_pdb_file(
-                            f"{accession}",
-                            file_format=args.pdb,
-                            pdir=os.getcwd,
-                        )
-
-    return
-
-
-def get_genbank_accession(df_row, df_name, row_index, logger):
-    """Retrieve GenBank accession for protein in the dataframe (df) row.
-
-    Retrieve the first GenBank accession becuase if multiple are given, CAZy only links
-    to the first GenBank accession.
-
-    :param df_row: Pandas series, from protein protein dataframe
-    :param df_name: str, name of the Pandas dataframe from which row was retrieved
-    :param row_index: int, index of the row in the protein dataframe
-    :param logger: logger object
-
-    Return two strings, GenBank accession of the protein and the protein's CAZy family.
-    """
-    family = df_row[1]
-    genbank_cell = df_row[4]
-
-    if type(genbank_cell) is float:
-        return None, None
-
-    # Retrieve the first accession number, and separate from assoicated HTML link
-    first_accession = genbank_cell.split(" ")[0]
-
-    # check result is in expected genbank format
-    try:
-        re.match(r"\D{3}\d+.\d+", first_accession).group()
-    except AttributeError:
-        logger.warning(
-            f"Could not return accession for protein in row {row_index} in\n"
-            f"{df_name}.\n"
-            "Not retrieving FASTA file for this protein."
-        )
-        return None, None
-
-    return first_accession, family
-
-
-def get_pdb_accessions(df_row, df_name, logger):
-    """Retrieve PDB accession for protein in the dataframe (df) row.
-
-    Retrieves all PDB accessions becuase multiple are accession can be given. Duplicate accession
-    are not retrieved.
-
-    :param df_row: Pandas series, from protein protein dataframe
-    :param df_name: str, name of the Pandas dataframe from which row was retrieved
-    :param row_index: int, index of the row in the protein dataframe
-    :param logger: logger object
-
-    Return list of PDB accessions.
-    """
-    pdb_cell = df_row[6]
-
-    # Check if null value is stored in pdb cell
-    if type(pdb_cell) is float:
-        return None
-
-    # Separate the PDB accession
-    pdb_accessions = pdb_cell.split(",\n")
-
-    index = 0
-    for index in range(len(pdb_accessions)):
-        # remove html links
-        pdb_accessions[index] = pdb_accessions[index].split(" ")[0]
-        # remove additional data in square brackest
-        pdb_accessions[index] = pdb_accessions[index].split("[")[0]
-
-    # remove duplicate accessions
-    pdb_accessions = list(dict.fromkeys(pdb_accessions))
-
-    return pdb_accessions
-
-
-def get_pdb_structures(protein_dataframe, df_name, args, logger):
-    """Coordinate the retrieval of CAZyme structures from PDB.
-
-    :param protein_dataframe: Pandas dataframe, dataframe containing protein data from CAZy
-    :param df_name: str, name of the CAZy dataframe
-    :param args: cmd args parser
-    :param logger: logger object
-
-    Return nothing.
-    """
-    # build PDBList object
-    pdbl = PDBList()
-    index = 0
-    for index in tqdm(
-        range(len(protein_dataframe["Protein_name"])),
-        desc=f"Downloading {df_name} structures",
-    ):
-        # Retrieve accession from GenBank cell
-        df_row = protein_dataframe.iloc[index]
-        pdb_accessions = get_pdb_accessions(df_row, df_name, logger)
-
-        if pdb_accessions is None:
-            continue
-
-        # Get structures from RSCB
-        if args.pdb_output is not None:
-            for accession in pdb_accessions:
-                pdbl.retrieve_pdb_file(
-                    f"{accession}",
-                    file_format=args.pdb,
-                    pdir=args.pdb_output,
-                )
-
-        else:
-            if args.output is not sys.stdout:
-                for accession in pdb_accessions:
-                    pdbl.retrieve_pdb_file(
-                        f"{accession}",
-                        file_format=args.pdb,
-                        pdir=args.output,
-                    )
-            else:
-                for accession in pdb_accessions:
-                    pdbl.retrieve_pdb_file(
-                        f"{accession}",
-                        file_format=args.pdb,
-                        pdir=os.getcwd,
-                    )
-
-    return
-
-
-def get_genbank_fasta(dataframe, df_name, args, logger):
-    """Retrieve GenBank accessions, coordinate downloading associated GenBank FASTA file.
-
-    :param df_row: Pandas series, from protein protein dataframe
-    :param df_name: str, name of the Pandas dataframe from which row was retrieved
-    :param row_index: int, index of the row in the protein dataframe
-    :param logger: logger object0345 454 111
-
-    Return  nothing.
-    """
-    # set user email address for Entrez
-    Entrez.email = args.genbank
-
-    index = 0
-    for index in tqdm(
-        range(len(dataframe["Protein_name"])), desc=f"Downloading {df_name} GenBank FASTAs"
-    ):
-        # Retrieve accession from GenBank cell
-        df_row = dataframe.iloc[index]
-        accession, cazy_family = get_genbank_accession(df_row, df_name, index, logger)
-
-        if accession is None:
-            continue
-
-        # create file name
-        file_name = f"{accession}_{cazy_family}.fasta"
-        if args.genbank_output is not sys.stdout:
-            file_name = args.genbank_output / file_name
-
-        download_fasta(accession, file_name, args, logger)
-
-    return
-
-
-def download_fasta(accession, file_name, args, logger):
-    """Download FASTA file from GenBank FTP server.
-
-    :param accession: str, accession of protein
-    :param file_name: str, path to output file desintation
-    :param args: cmd args parser
-    :param logger: logger object
-
-    Returning nothing.
-    """
-    if args.genbank_output is not sys.stdout:
-        if file_name.exists():
-            logger.warning(f"FASTA file {file_name} aleady exists, not downloading again")
-            return
-
-    handle = entrez_retry(
-        logger,
-        Entrez.efetch,
-        db="protein",
-        id=accession,
-        rettype="fasta",
-        retmode="text",
-    )
-
-    if handle is None:
-        logger.warning(f"Failed to download FASTA file for {accession}")
-        return
-
-    for record in SeqIO.parse(handle, "fasta"):
-        if args.genbank_output is not sys.stdout:
-            with open(file_name, "w") as fh:
-                SeqIO.write(record, fh, "fasta")
-        else:
-            SeqIO.write(record, sys.stdout, "fasta")
-
-    return
-
-
-def entrez_retry(logger, entrez_func, *func_args, **func_kwargs):
-    """Call to NCBI using Entrez.
-    Maximum number of retries is 10, retry initated when network error encountered.
-    :param logger: logger object
-    :param retries: parser argument, maximum number of retries excepted if network error encountered
-    :param entrez_func: function, call method to NCBI
-    :param *func_args: tuple, arguments passed to Entrez function
-    :param ** func_kwargs: dictionary, keyword arguments passed to Entrez function
-    Returns record.
-    """
-    record, retries, tries = None, 10, 0
-
-    while record is None and tries < retries:
-        try:
-            record = entrez_func(*func_args, **func_kwargs)
-
-        except IOError:
-            # log retry attempt
-            if tries < retries:
-                logger.warning(
-                    f"Network error encountered during try no.{tries}.\nRetrying in 10s",
-                    exc_info=1,
-                )
-                time.sleep(10)
-            tries += 1
-
-    if record is None:
-        logger.error(
-            "Network error encountered too many times. Exiting attempt to call to NCBI"
-        )
-        return
-
-    return record
diff --git a/scraper/scraper_config.yaml b/scraper/scraper_config.yaml
index a20a4b6f..321bc943 100644
--- a/scraper/scraper_config.yaml
+++ b/scraper/scraper_config.yaml
@@ -13,4 +13,10 @@ Polysaccharide Lyases (PLs):
   - "PL28"
 Carbohydrate Esterases (CEs):
 Auxiliary Activities (AAs):
-Carbohydrate-Binding Modules (CBMs):
\ No newline at end of file
+Carbohydrate-Binding Modules (CBMs):
+genera:  # list genera to be scraped
+ - "Trichoderma"
+species:  # list species, this will scrape all strains under the species
+strains:  # list specific strains to be scraped
+kingdom:  # Archaea, Bacteria, Eukaryota, Viruses, Unclassified
+ - "Bacteria"
\ No newline at end of file
diff --git a/scraper/sql/__init__.py b/scraper/sql/__init__.py
index 6e9f3d0c..fae871d0 100644
--- a/scraper/sql/__init__.py
+++ b/scraper/sql/__init__.py
@@ -1,5 +1,7 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
 # Author:
 # Emma E. M. Hobbs
 
@@ -16,1073 +18,22 @@
 # UK
 
 # The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
 """Module for building and querying an SQL database."""
-
-
-import os
-import sys
-
-from sqlalchemy import (
-    create_engine, Boolean, Column, ForeignKey, Integer, PrimaryKeyConstraint, String, Table
-)
-from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import relationship, sessionmaker
-
-
-# Use the declarative system
-# Database structured in NF1
-Base = declarative_base()
-Session = sessionmaker()
-
-
-# define association/relationship tables
-
-
-# linker table between cazymes and CAZy family and subfamilies
-cazymes_families = Table(
-    "cazymes_families",
-    Base.metadata,
-    Column("cazyme_id", Integer, ForeignKey("cazymes.cazyme_id")),
-    Column("family_id", Integer, ForeignKey("families.family_id")),
-    PrimaryKeyConstraint("cazyme_id", "family_id"),
-)
-
-
-# linker table between cazymes and ec numbers
-cazymes_ecs = Table(
-    "cazymes_ecs",
-    Base.metadata,
-    Column("cazyme_id", Integer, ForeignKey("cazymes.cazyme_id")),
-    Column("ec_id", Integer, ForeignKey("ecs.ec_id")),
-    PrimaryKeyConstraint("cazyme_id", "ec_id"),
-)
-
-
-# linker table between cazymes and GenBank accession of source protein sequence
-cazymes_genbanks = Table(
-    "cazymes_genbanks",
-    Base.metadata,
-    Column("cazyme_id", Integer, ForeignKey("cazymes.cazyme_id")),
-    Column("genbank_id", Integer, ForeignKey("genbanks.genbank_id")),
-    PrimaryKeyConstraint("cazyme_id", "genbank_id"),
-)
-
-
-# linker table between cazymes and UniProt accessions of CAZymes
-cazymes_uniprots = Table(
-    "cazymes_uniprots",
-    Base.metadata,
-    Column("cazyme_id", Integer, ForeignKey("cazymes.cazyme_id")),
-    Column("uniprot_id", Integer, ForeignKey("uniprots.uniprot_id")),
-    PrimaryKeyConstraint("cazyme_id", "uniprot_id"),
-)
-
-
-# linker table between CAZymes and PDB structures
-cazymes_pdbs = Table(
-    "cazymes_pdbs",
-    Base.metadata,
-    Column("cazyme_id", Integer, ForeignKey("cazymes.cazyme_id")),
-    Column("pdb_id", Integer, ForeignKey("pdbs.pdb_id")),
-    PrimaryKeyConstraint("cazyme_id", "pdb_id"),
-)
-
-
-# define models
-
-
-class Cazyme(Base):
-    """Describes a CAZyme, a protein single entry in CAZy."""
-    __tablename__ = "cazymes"
-
-    cazyme_id = Column(Integer, primary_key=True)
-    cazyme_name = Column(String)
-    taxonomy_id = Column(Integer, ForeignKey("taxs.taxonomy_id"))
-
-    taxonomy = relationship("Taxonomy", back_populates="cazymes")
-
-    families = relationship(
-        "CazyFamily",
-        secondary=cazymes_families,
-        back_populates="cazymes",
-        lazy="dynamic",
-    )
-    ecs = relationship(
-        "EC",
-        secondary=cazymes_ecs,
-        back_populates="cazymes",
-        lazy="dynamic",
-    )
-    genbanks = relationship(
-        "Genbank",
-        secondary=cazymes_genbanks,
-        back_populates="cazymes",
-        lazy="dynamic",
-    )
-    uniprots = relationship(
-        "Uniprot",
-        secondary=cazymes_uniprots,
-        back_populates="cazymes",
-        lazy="dynamic",
-    )
-    pdbs = relationship(
-        "Pdb",
-        secondary=cazymes_pdbs,
-        back_populates="cazymes",
-        lazy="dynamic",
-    )
-
-    def __repr__(self):
-        """Return string representation of Cazyme table object."""
-        return f"<CAZyme name={self.cazyme_name}, id={self.cazyme_id}>"
-
-
-class Taxonomy(Base):
-    """Describes the source organism of CAZymes."""
-    __tablename__ = "taxs"
-
-    taxonomy_id = Column(Integer, primary_key=True)
-    genus = Column(String)
-    species = Column(String)
-
-    cazymes = relationship("Cazyme", back_populates="taxonomy")
-
-    def __repr__(self):
-        """Return string representation of source organism."""
-        return f"<Source organism, taxonomy, Genus={self.genus}, Species={self.species}>"
-
-
-class CazyFamily(Base):
-    """Describes the source organism of CAZymes."""
-    __tablename__ = "families"
-    family_id = Column(Integer, primary_key=True)
-    family = Column(String)
-    subfamily = Column(String)
-
-    cazymes = relationship(
-        "Cazyme",
-        secondary=cazymes_families,
-        back_populates="families",
-        lazy="dynamic",
-    )
-
-    def __repr__(self):
-        """Return string representation of source organism."""
-        if self.subfamily is None:
-            return f"<CAZy family id={self.family_id} name={self.family}>"
-        else:
-            return f"<CAZy subfamily id={self.family_id} name={self.subfamily}>"
-
-
-class EC(Base):
-    """Describe EC numbers."""
-    __tablename__ = "ecs"
-
-    ec_id = Column(Integer, primary_key=True)
-    ec_number = Column(String)
-
-    cazymes = relationship("Cazyme", secondary=cazymes_ecs, back_populates="ecs", lazy="dynamic")
-
-    def __repr__(self):
-        """Return string representation of EC number (EC) object."""
-        return f"<EC#={self.ec_number}>"
-
-
-class Genbank(Base):
-    """Describe GenBank accession numbers of protein sequences."""
-    __tablename__ = "genbanks"
-
-    genbank_id = Column(Integer, primary_key=True)
-    genbank_accession = Column(String)
-    primary = Column(Boolean)
-
-    cazymes = relationship(
-        "Cazyme",
-        secondary=cazymes_genbanks,
-        back_populates="genbanks",
-        lazy="dynamic",
-    )
-
-    def __repr__(self):
-        """Return representation of GenBank accession number."""
-        return f"<GenBank acc={self.genbank_accession}, primary={self.primary}>"
-
-
-class Uniprot(Base):
-    """Describe UniProt accession number."""
-    __tablename__ = "uniprots"
-
-    uniprot_id = Column(Integer, primary_key=True)
-    uniprot_accession = Column(String)
-    primary = Column(Boolean)
-
-    cazymes = relationship(
-        "Cazyme",
-        secondary=cazymes_uniprots,
-        back_populates="uniprots",
-        lazy="dynamic",
-    )
-
-    def __repr__(self):
-        """Return representation of UniProt accession number."""
-        return f"<UniProt={self.uniprot_accession}, primary={self.primary}>"
-
-
-class Pdb(Base):
-    """Describe PDB accession number of protein structure."""
-    __tablename__ = "pdbs"
-
-    pdb_id = Column(Integer, primary_key=True)
-    pdb_accession = Column(String)
-    primary = Column(Boolean)
-
-    cazymes = relationship("Cazyme", secondary=cazymes_pdbs, back_populates="pdbs", lazy="dynamic")
-
-    def __repr__(self):
-        """Return representation of accesison of PDB structure record."""
-        return f"<PDB={self.pdb_accession}, primary={self.primary}>"
-
-
-def build_db(time_stamp, args, logger):
-    """Build an empty SQL database and open a session.
-
-    :param time_stamp: str, date and time stamp of when scrape was initated
-    :param args: cmd args parser
-    :param logger: logger object
-
-    Return an open database session.
-    """
-    logger.info("Building empty db to store data")
-
-    # build database engine
-
-    if args.output is sys.stdout:
-        # write to cwd, this is deleted in scrape is successful
-        cwd = os.getcwd()
-        db_path = cwd / f"cazy_scrape_temp_{time_stamp}.db"
-
-    else:
-        # write to specified output directory
-        db_path = args.output / f"cazy_scrape_{time_stamp}.db"
-
-    engine = create_engine(f"sqlite+pysqlite:///{db_path}", echo=False)
-    Base.metadata.create_all(engine)
-    Session.configure(bind=engine)
-
-    return Session()
-
-
-def add_protein_to_db(
-    cazyme_name,
-    family,
-    source_organism,
-    ec_numbers,
-    external_links,
-    logger,
-    session,
-):
-    """Coordinate adding protein (CAZyme) data to the SQL database (db).
-
-    :param cazyme_name: str, name of the protein/CAZyme
-    :param family: str, CAZy family or subfamily the protein is catalogued under in CAZy
-    :param source_organism: str, the scientific name of the organism from which the CAZy is derived
-    :param ec_numbers: list of EC numbers which the CAZyme is annotated with
-    :param external_links: dict, links to external databases
-    :param session: open sqlalchemy session to database
-
-    Return nothing or duplicate error message.
-    """
-    # Each unique protein is identified by a unique primary GenBank accession, not its CAZyme name
-    # query the local database to see if the current working protein is in the database
-    genbank_query = session.query(Genbank).\
-        filter_by(genbank_accession=external_links['GenBank'][0]).\
-        filter(Genbank.primary==True).\
-        all()
-
-    if len(genbank_query) == 0:
-        # GenBank accession was not found as a primary accession in the database
-        # Inferring the protein is not in the local database
-        add_new_protein_to_db(
-            cazyme_name,
-            family,
-            source_organism,
-            ec_numbers,
-            external_links,
-            logger,
-            session,
-        )
-
-    elif len(genbank_query) == 1:
-        # GenBank accession found as the primary accession in the database for one protien
-        # Identfied that the protein is already catalogued in the local database
-
-        # Get the genbank_id for the GenBank record, then get it's associated Cazyme objects.
-        # Above the search filtered for primary==True, so this query only retrieves CAZymes which
-        # have the GenBank accession set as their primary accession
-        genbank_id = genbank_query[0].genbank_id
-        cazyme_query = session.query(Cazyme).join(Cazyme.genbanks).\
-            filter(Genbank.genbank_id==genbank_id).all()
-
-        if len(cazyme_query) == 0:
-            logger.warning(
-                f"The GenBank accession {external_links['GenBank'][0]} with database genbank_id "
-                f"{genbank_id}\n"
-                "was previously added to the local database, but was not associated with a CAZyme"
-            )
-            # No protein is associated with the GenBank accession so treat as if it is a new protein
-            add_new_protein_to_db(
-                cazyme_name,
-                family,
-                source_organism,
-                ec_numbers,
-                external_links,
-                logger,
-                session,
-            )
-
-        elif len(cazyme_query) == 1:
-            add_data_to_protein_record(
-                cazyme_query[0],
-                family,
-                ec_numbers,
-                external_links,
-                logger,
-                session,
-            )
-
-        else:
-            # multiple CAZymes are listed with the GenBank accession as their primary GenBank
-            # accession, inferring their duplicate records for the same CAZyme
-            logger.warning(
-                "The following CAZymes found with the same primary GenBank accession "
-                f"{external_links['GenBank'][0]}, "
-                f"genbank_id={genbank_id},\n"
-                "inferring they are the same protein. Therefore, they are potentially duplicate\n"
-                "CAZymes in the local database.\n"
-                f"Protein data being added to cazyme {cazyme_query[0].cazyme_name}, "
-                f"id={cazyme_query[0].cazyme_id}"
-            )
-            for cazyme in cazyme_query:
-                logger.warning(
-                    f"Duplicate CAZyme: {cazyme.cazyme_name}, id={cazyme.cazyme_id}"
-                )
-            add_data_to_protein_record(
-                cazyme_query[0],
-                family,
-                ec_numbers,
-                external_links,
-                logger,
-                session,
-            )
-
-    else:
-        # The GenBank accession was found multiple times, labeled as the primary accession, in the
-        # local database.
-        logger.warning(
-            "Multiple copies of the GenBank accession "
-            f"{external_links['GenBank'][0].genbank_accession} found "
-            "in the local database as a primary accession.\n"
-            "Checking for potentially duplicate CAZymes in the local database"
-        )
-        # Check how many CAZymes the GenBank accession is associated with
-        duplicate_cazyme_entries = []  # Cazyme objects with the same primary GenBank accession
-
-        for genbank_object in genbank_query:
-            # retrieve CAZymes that are linked to the primary GenBank accession
-            genbank_id = genbank_object.genbank_id
-            cazyme_query = session.query(Cazyme).join(Cazyme.genbanks).\
-                filter(Genbank.genbank_id==genbank_id).all()
-
-            if len(cazyme_query) == 0:
-                logger.warning(
-                    f"The GenBank accession {genbank_object.genbank_accession} with the id "
-                    f"{genbank_object.genbank_id}\n"
-                    "was previously add to the local database as a primary GenBank accession\n"
-                    "but NOT associated with a CAZyme."
-                )
-
-            elif len(cazyme_query) == 1:
-                duplicate_cazyme_entries.append(cazyme_query[0])
-
-            else:
-                # multiple CAZymes have the GenBank accession as their primary GenBank accession
-                logger.warning(
-                    f"The following CAZymes have the GenBank accession {genbank_object.accession}, "
-                    f"genbank_id={genbank_object.genbank_id}\n,"
-                    "as their primary GenBank accession,"
-                    "infering they are the same CAZyme and are duplicates of each other"
-                )
-                for cazyme in cazyme_query:
-                    logger.warning(
-                        f"Duplicate CAZymes: {cazyme.cazyme_name}, cazyme_id={cazyme.cazyme_id}"
-                    )
-                    duplicate_cazyme_entries.append(cazyme)
-
-        # check how many CAZyme duplicates there are that have the same primary GenBank accession
-        if len(duplicate_cazyme_entries) == 0:
-            # The GenBank accession has been entered multiple times into the database, but not once
-            # associated with a CAZyme.
-            logger.warning(
-                f"The GenBank accession {external_links['GenBank'][0]} has been entered multiple\n"
-                "times as a primary GenBank accession into the local CAZy database with different "
-                "'genbank_id's,\n"
-                "but it was not associated with a CAZyme, therefore, adding it to the database as "
-                "a new CAZyme."
-            )
-            add_new_protein_to_db(
-                cazyme_name,
-                family,
-                source_organism,
-                ec_numbers,
-                external_links,
-                logger,
-                session,
-            )
-
-        elif len(duplicate_cazyme_entries) == 1:
-            # only one CAZyme found associated with the primary GenBank accession
-            # add the protein data to this CAZyme
-            logger.warning(
-                f"The GenBank accession {external_links['GenBank'][0]} has been entered multiple\n"
-                "times as a primary GenBank accession into the local CAZy database with different "
-                "'genbank_id's,\n"
-                f"but associated with only one CAZyme: {duplicate_cazyme_entries[0].cazyme_name} "
-                f"id={duplicate_cazyme_entries[0].cazyme_id}"
-            )
-            add_data_to_protein_record(
-                duplicate_cazyme_entries[0],
-                family,
-                ec_numbers,
-                external_links,
-                logger,
-                session,
-            )
-
-        else:
-            logger.warning(
-                "The following CAZymes appear to be duplicates in the local database becuase\n"
-                "they have the same primary GenBank accession number, "
-                f"{external_links['GenBank'][0]}.\n"
-                "Although the GenBank accessions have different genbank_ids, therefore, the\n"
-                "accession has been added to the database as a primary accession multiple times.\n"
-                f"Protein data being added to {duplicate_cazyme_entries[0].cazyme_name} "
-                f"id={duplicate_cazyme_entries[0].cazyme_id}"
-            )
-            for cazyme in duplicate_cazyme_entries:
-                logger.warning(
-                    f"Duplicate CAZyme: {cazyme.cazyme_name}, id={cazyme.cazyme_id}"
-                )
-            # add the protein data scraped from CAZy to the first duplicate CAZyme
-            add_data_to_protein_record(
-                duplicate_cazyme_entries[0],
-                family,
-                ec_numbers,
-                external_links,
-                logger,
-                session,
-            )
-
-    return
-
-
-def add_new_protein_to_db(
-    cazyme_name,
-    family,
-    source_organism,
-    ec_numbers,
-    external_links,
-    logger,
-    session,
-):
-    """Add a new protein (a CAZyme) record to the database.
-
-    :param cazyme_name: str, name of the protein/CAZyme
-    :param family: str, CAZy family or subfamily the protein is catalogued under in CAZy
-    :param source_organism: str, the scientific name of the organism from which the CAZy is derived
-    :param ec_numbers: list of EC numbers which the CAZyme is annotated with
-    :param external_links: dict, links to external databases
-    :param session: open sqlalchemy session to database
-
-    Return nothing.
-    """
-    # define the CAZyme
-    new_cazyme = Cazyme(cazyme_name=cazyme_name)
-
-    # define source organism
-    genus_sp_separator = source_organism.find(" ")
-    genus = source_organism[:genus_sp_separator]
-    species = source_organism[genus_sp_separator:]
-
-    # check if the source  organism is already catalogued
-    tax_query = session.query(Taxonomy).filter_by(genus=genus, species=species).all()
-
-    if len(tax_query) == 0:
-        # create Taxonomy model object
-        new_cazyme.taxonomy = Taxonomy(genus=genus, species=species)
-
-    elif len(tax_query) == 1:
-        # add exiting Taxonomy object to the new cazyme
-        new_cazyme.taxonomy = tax_query[0]
-
-    else:
-        logger.warning(
-            f"The species {genus} {species} has been loaded into the database "
-            f"{len(tax_query)} times.\n"
-        )
-        new_cazyme.taxonomy = tax_query[0]
-
-    # add the new cazyme to the database
-    session.add(new_cazyme)
-    session.commit()
-
-    # add Family/Subfamily classifications
-    if family.find("_") != -1:
-        add_cazy_subfamily(family, new_cazyme, session, logger)
-    else:
-        add_cazy_family(family, new_cazyme, session, logger)
-
-    # define ec_number
-    if ec_numbers is not None:
-        add_ec_numbers(ec_numbers, new_cazyme, session, logger)
-
-    # add GenBank accessions
-    try:
-        genbank_accessions = external_links["GenBank"]
-        add_genbank_accessions(genbank_accessions, new_cazyme, session, logger)
-    except KeyError:
-        pass
-
-    # add UniProt accessions
-    try:
-        uniprot_accessions = external_links["UniProt"]
-        add_uniprot_accessions(uniprot_accessions, new_cazyme, session, logger)
-    except KeyError:
-        pass
-
-    # add PDB/3D accessions
-    try:
-        pdb_accessions = external_links["PDB/3D"]
-        add_pdb_accessions(pdb_accessions, new_cazyme, session, logger)
-    except KeyError:
-        pass
-
-    # final commit to ensure all changes are commited
-    session.commit()
-
-    return
-
-
-def add_data_to_protein_record(
-    cazyme,
-    family,
-    ec_numbers,
-    external_links,
-    logger,
-    session,
-):
-    """Add data to an existing record in the SQL database.
-
-    :param cazyme: CAZyme class object
-    :param family: str, CAZy family or subfamily the protein is catalogued under in CAZy
-    :param ec_numbers: list of EC numbers which the CAZyme is annotated with
-    :param external_links: dict, links to external databases
-    :param session: open sqlalchemy session to database
-
-    Return nothing.
-    """
-    # add Family/Subfamily classifications
-    if family.find("_") != -1:
-        add_cazy_subfamily(family, cazyme, session, logger)
-    else:
-        add_cazy_family(family, cazyme, session, logger)
-
-    # define ec_number
-    if ec_numbers is not None:
-        add_ec_numbers(ec_numbers, cazyme, session, logger)
-
-    # add GenBank accessions
-    try:
-        genbank_accessions = external_links["GenBank"]
-        add_genbank_accessions(genbank_accessions, cazyme, session, logger)
-    except KeyError:
-        pass
-
-    # add UniProt accessions
-    try:
-        uniprot_accessions = external_links["GenBank"]
-        add_uniprot_accessions(uniprot_accessions, cazyme, session, logger)
-    except KeyError:
-        pass
-
-    # add PDB/3D accessions
-    try:
-        pdb_accessions = external_links["GenBank"]
-        add_pdb_accessions(pdb_accessions, cazyme, session, logger)
-    except KeyError:
-        pass
-
-    # final commit to ensure all changes are commited
-    session.commit()
-
-    return
-
-
-def add_cazy_family(family, cazyme, session, logger):
-    """Add CAZy family to CAZyme record in the local CAZy database.
-
-    :param family: str, name of a CAZy family/subfamily
-    :param cazyme: Cazymes class object
-    :param session: open local database session connector
-    :param logger: logger object
-
-    Return nothing.
-    """
-    # Check if Family is already in the local database
-    family_query = session.query(CazyFamily).filter_by(family=family).all()
-
-    if len(family_query) == 0:
-        # add new CAZy to the database
-        cazy_family = CazyFamily(family=family)
-        session.add(cazy_family)
-        session.commit()
-
-        if not(cazy_family in cazyme.families):
-            cazyme.families.append(cazy_family)
-        session.commit()
-
-    elif len(family_query) == 1:
-        # check if it is associated with a CAZy subfamily
-
-        if family_query[0].subfamily is not None:
-            # The current family record is associated with a subfamily
-            # the current working family is not therefore
-            # add new CAZy family without a subfamily association to the database
-            cazy_family = CazyFamily(family=family)
-            session.add(cazy_family)
-            session.commit()
-
-            if not(family_query[0] in cazyme.families):
-                cazyme.families.append(cazy_family)
-            session.commit()
-
-        else:
-            # add existing Family record to current working CAZyme
-            if not(family_query[0] in cazyme.families):
-                cazyme.families.append(family_query[0])
-            session.commit()
-
-    else:
-        # check if any of the multiple Family records are associated with subfamilies or not
-        nonsubfamily_asociated_family_entries = []
-
-        for entry in family_query:
-            # check if retrieved family record is associated with a subfamily
-            # retrieve only entries NOT associated with a subfamily
-            if entry.subfamily is None:
-                nonsubfamily_asociated_family_entries.append(entry)
-
-        if len(nonsubfamily_asociated_family_entries) == 0:
-            # add new CAZy family without a subfamily association to the database
-            cazy_family = CazyFamily(family=family)
-            session.add(cazy_family)
-            session.commit()
-            if not(cazy_family in cazyme.families):
-                cazyme.families.append(cazy_family)
-            session.commit()
-
-        elif len(nonsubfamily_asociated_family_entries) == 1:
-            # Add existing non-subfamily associated family instance to CAZyme
-            if not(nonsubfamily_asociated_family_entries[0] in cazyme.families):
-                cazyme.families.append(nonsubfamily_asociated_family_entries[0])
-            session.commit()
-
-        else:
-            logger.warning(
-                f"Duplicate family entries found for the CAZy family {family} "
-                "without subfamily association.\n"
-                "Linking the family with the id "
-                f"{nonsubfamily_asociated_family_entries[0].family_id} to the cazyme "
-                f"{cazyme.cazyme_name} id={cazyme.cazyme_id}"
-            )
-            if not(nonsubfamily_asociated_family_entries[0] in cazyme.families):
-                cazyme.families.append(nonsubfamily_asociated_family_entries[0])
-            session.commit()
-
-    session.commit()
-    return
-
-
-def add_cazy_subfamily(family, cazyme, session, logger):
-    """Add CAZy family to CAZyme record in the local CAZy database.
-
-    :param family: str, name of a CAZy family/subfamily
-    :param cazyme: Cazymes class object
-    :param session: open local database session connector
-    :param logger: logger object
-
-    Return nothing.
-    """
-    # check if the subfamily is already in the database
-    subfam_query = session.query(CazyFamily).filter_by(subfamily=family).all()
-
-    if len(subfam_query) == 0:
-        # add new CAZy subfamily to the database
-        cazy_family = CazyFamily(family=family[:family.find("_")], subfamily=family)
-        session.add(cazy_family)
-        session.commit()
-
-        if not(cazy_family in cazyme.families):
-            cazyme.families.append(cazy_family)
-        session.commit()
-
-    elif len(subfam_query) == 1:
-        # add existing subfamily to the current working CAZyme
-        if not(subfam_query[0] in cazyme.families):
-            cazyme.families.append(subfam_query[0])
-        session.commit()
-
-    else:
-        logger.warning(
-            f"Duplicate subfamily entries found for the CAZy subfamily {family}.\n"
-            f"Add the family with the id {subfam_query[0].family_id} to the cazyme "
-            f"{cazyme.cazyme_name} id={cazyme.cazyme_id}"
-        )
-        if not(subfam_query[0] in cazyme.families):
-            cazyme.families.append(subfam_query[0])
-        session.commit()
-
-    session.commit()
-    return
-
-
-def add_ec_numbers(ec_numbers, cazyme, session, logger):
-    """Add EC numbers to CAZyme record in the local CAZy database.
-
-    :param ec_numbers: list of EC numbers (str)
-    :param new_cazyme: Cazymes class object
-    :param session: open local database session connector
-    :param logger: logger object
-
-    Return nothing.
-    """
-    for ec in ec_numbers:
-        # check if the EC number is already in the database
-        ec_query = session.query(EC).filter_by(ec_number=ec).all()
-
-        if len(ec_query) == 0:
-            # add new EC number to the database
-            new_ec = EC(ec_number=ec)
-            session.add(new_ec)
-            session.commit()
-
-            if not(new_ec in cazyme.ecs):
-                cazyme.ecs.append(new_ec)
-            session.commit()
-
-        elif len(ec_query) == 1:
-            # add existing EC number record to the CAZyme record
-            if not(ec_query[0] in cazyme.ecs):
-                cazyme.ecs.append(ec_query[0])
-            session.commit()
-
-        else:
-            # duplicate records found for the current EC number
-            logger.warning(
-                f"Duplicate entries found for the EC# {ec} in the local CAZy database."
-                f"Add the family with the id {ec_query[0].ec_id} to the cazyme "
-                f"{cazyme.cazyme_name} id={cazyme.cazyme_id}"
-            )
-            if not(ec_query[0] in cazyme.ecs):
-                cazyme.ecs.append(ec_query[0])
-            session.commit()
-
-    session.commit()
-    return
-
-
-def add_genbank_accessions(genbank_accessions, cazyme, session, logger):
-    """Add GenBank protein accession numbers to CAZyme record in the local CAZy database.
-
-    :param genbank_accessions: list of GenBank protein accession numbers (str)
-    :param cazyme: Cazymes class object
-    :param session: open local database session connector
-    :param logger: logger object
-
-    Return nothing.
-    """
-    if len(genbank_accessions) == 0:
-        return
-
-    elif len(genbank_accessions) == 1:
-        add_primary_genbank(genbank_accessions[0], cazyme, session, logger)
-        # check if accession is already in the database
-
-    else:
-        add_primary_genbank(genbank_accessions[0], cazyme, session, logger)
-
-        for accession in genbank_accessions[1:]:
-            # check if accession is in the database already
-            genbank_query = session.query(Genbank).filter_by(genbank_accession=accession).all()
-
-            if len(genbank_query) == 0:
-                # add new genbank accession
-                new_accession = Genbank(genbank_accession=accession, primary=False)
-                session.add(new_accession)
-                session.commit()
-
-                if not(new_accession in cazyme.genbanks):
-                    cazyme.genbanks.append(new_accession)
-                session.commit()
-
-            elif len(genbank_query) == 1:
-                # add GenBank record to current working CAZyme
-                if not(genbank_query[0] in cazyme.genbanks):
-                    cazyme.genbanks.append(genbank_query[0])
-                session.commit()
-
-            else:
-                logger.warning(
-                    f"Duplicate entries for GenBank accession {accession}"
-                    f"Adding the accession entry with the ID {genbank_query[0].genbank_id} to the\n"
-                    f"cazyme {cazyme.cazyme_name} id={cazyme.cazyme_id}"
-                )
-                if not(genbank_query[0] in cazyme.genbanks):
-                    cazyme.genbanks.append(genbank_query[0])
-                session.commit()
-
-    session.commit()
-    return
-
-
-def add_primary_genbank(accession, cazyme, session, logger):
-    """Add primary GenBank accession for CAZyme to the local CAZy database.
-
-    :param accession: str, primary GenBank accession of a CAZyme
-    :param cazyme: Cazymes class object
-    :param session: open local database session connector
-    :param logger: logger object
-
-    Return nothing.
-    """
-    genbank_query = session.query(Genbank).filter_by(genbank_accession=accession).all()
-
-    if len(genbank_query) == 0:
-        # add new genbank accession
-        new_accession = Genbank(genbank_accession=accession, primary=True)
-        session.add(new_accession)
-        session.commit()
-
-        if not(new_accession in cazyme.genbanks):
-            cazyme.genbanks.append(new_accession)
-        session.commit()
-
-    elif len(genbank_query) == 1:
-        # add GenBank record to current working CAZyme
-        if not(genbank_query[0] in cazyme.genbanks):
-            cazyme.genbanks.append(genbank_query[0])
-        session.commit()
-
-    else:
-        logger.warning(
-            f"Duplicate entries for GenBank accession {accession}"
-            f"Adding the accession entry with the ID {genbank_query[0].genbank_id} to the\n"
-            f"cazyme {cazyme.cazyme_name} id={cazyme.cazyme_id}"
-        )
-        if not(genbank_query[0] in cazyme.genbanks):
-            cazyme.genbanks.append(genbank_query[0])
-        session.commit()
-
-    session.commit()
-    return
-
-
-def add_uniprot_accessions(uniprot_accessions, cazyme, session, logger):
-    """Add UniProt protein accessions to CAZyme record in the local CAZy database.
-
-    :param uniprot_accessions: list of UniProt protein accession numbers (str)
-    :param cazyme: Cazymes class object
-    :param session: open local database session connector
-    :param logger: logger object
-
-    Return nothing.
-    """
-    if len(uniprot_accessions) == 0:
-        return
-
-    elif len(uniprot_accessions) == 1:
-        add_primary_uniprot(uniprot_accessions[0], cazyme, session, logger)
-        # check if accession is already in the database
-
-    else:
-        add_primary_uniprot(uniprot_accessions[0], cazyme, session, logger)
-
-        for accession in uniprot_accessions[1:]:
-            # check if accession is in the database already
-            uniprot_query = session.query(Uniprot).filter_by(uniprot_accession=accession).all()
-
-            if len(uniprot_query) == 0:
-                # add new uniprot accession
-                new_accession = Uniprot(uniprot_accession=accession, primary=False)
-                session.add(new_accession)
-                session.commit()
-
-                if not(new_accession in cazyme.uniprots):
-                    cazyme.uniprots.append(new_accession)
-                session.commit()
-
-            elif len(uniprot_query) == 1:
-                # add UniProt record to current working CAZyme
-                if not(uniprot_query[0] in cazyme.uniprots):
-                    cazyme.uniprots.append(uniprot_query[0])
-                session.commit()
-
-            else:
-                logger.warning(
-                    f"Duplicate entries for UniProt accession {accession}"
-                    f"Adding the accession entry with the ID {uniprot_query[0].uniprot_id} to the\n"
-                    f"cazyme {cazyme.cazyme_name} id={cazyme.cazyme_id}"
-                )
-                if not(uniprot_query[0] in cazyme.uniprots):
-                    cazyme.uniprots.append(uniprot_query[0])
-                session.commit()
-
-    session.commit()
-    return
-
-
-def add_primary_uniprot(accession, cazyme, session, logger):
-    """Add primary UniProt accession for CAZyme to the local CAZy database.
-
-    :param accession: str, primary UniProt accession of a CAZyme
-    :param cazyme: Cazymes class object
-    :param session: open local database session connector
-    :param logger: logger object
-
-    Return nothing.
-    """
-    uniprot_query = session.query(Uniprot).filter_by(uniprot_accession=accession).all()
-
-    if len(uniprot_query) == 0:
-        # add new uniprot accession
-        new_accession = Uniprot(uniprot_accession=accession, primary=True)
-        session.add(new_accession)
-        session.commit()
-
-        if not(new_accession in cazyme.uniprots):
-            cazyme.uniprots.append(new_accession)
-        session.commit()
-
-    elif len(uniprot_query) == 1:
-        # add UniProt record to current working CAZyme
-        if not(uniprot_query[0] in cazyme.uniprots):
-            cazyme.uniprots.append(uniprot_query[0])
-        session.commit()
-
-    else:
-        logger.warning(
-            f"Duplicate entries for UniProt accession {accession}"
-            f"Adding the accession entry with the ID {uniprot_query[0].uniprot_id} to the\n"
-            f"cazyme {cazyme.cazyme_name} id={cazyme.cazyme_id}"
-        )
-        if not(uniprot_query[0] in cazyme.uniprots):
-            cazyme.uniprots.append(uniprot_query[0])
-        session.commit()
-
-    session.commit()
-    return
-
-
-def add_pdb_accessions(pdb_accessions, cazyme, session, logger):
-    """Add PDB/3D protein accessions to CAZyme record in the local CAZy database.
-
-    :param pdb_accessions: list of UniProt protein accession numbers (str)
-    :param cazyme: Cazymes class object
-    :param session: open local database session connector
-    :param logger: logger object
-
-    Return nothing.
-    """
-    if len(pdb_accessions) == 0:
-        return
-
-    elif len(pdb_accessions) == 1:
-        add_primary_pdb(pdb_accessions[0], cazyme, session, logger)
-        # check if accession is already in the database
-
-    else:
-        add_primary_pdb(pdb_accessions[0], cazyme, session, logger)
-
-        for accession in pdb_accessions[1:]:
-            # check if accession is in the database already
-            pdb_query = session.query(Pdb).filter_by(pdb_accession=accession).all()
-
-            if len(pdb_query) == 0:
-                # add new pdb accession
-                new_accession = Pdb(pdb_accession=accession, primary=False)
-                session.add(new_accession)
-                session.commit()
-
-            if not(new_accession in cazyme.pdbs):
-                cazyme.pdbs.append(new_accession)
-                session.commit()
-
-            elif len(pdb_query) == 1:
-                # add PDB/3D record to current working CAZyme
-                if not(pdb_query[0] in cazyme.pdbs):
-                    cazyme.pdbs.append(pdb_query[0])
-                session.commit()
-
-            else:
-                logger.warning(
-                    f"Duplicate entries for PDB/3D accession {accession}"
-                    f"Adding the accession entry with the ID {pdb_query[0].pdb_id} to the\n"
-                    f"cazyme {cazyme.cazyme_name} id={cazyme.cazyme_id}"
-                )
-                if not(pdb_query[0] in cazyme.pdbs):
-                    cazyme.pdbs.append(pdb_query[0])
-                session.commit()
-
-    session.commit()
-    return
-
-
-def add_primary_pdb(accession, cazyme, session, logger):
-    """Add primary PDB/3D accession for CAZyme to the local CAZy database.
-
-    :param accession: str, primary UniProt accession of a CAZyme
-    :param cazyme: Cazymes class object
-    :param session: open local database session connector
-    :param logger: logger object
-
-    Return nothing.
-    """
-    pdb_query = session.query(Pdb).filter_by(pdb_accession=accession).all()
-
-    if len(pdb_query) == 0:
-        # add new pdb accession
-        new_accession = Pdb(pdb_accession=accession, primary=True)
-        session.add(new_accession)
-        session.commit()
-
-        if not(new_accession in cazyme.pdbs):
-            cazyme.pdbs.append(new_accession)
-        session.commit()
-
-    elif len(pdb_query) == 1:
-        # add PDB/3D record to current working CAZyme
-        if not(pdb_query[0] in cazyme.pdbs):
-            cazyme.pdbs.append(pdb_query[0])
-        session.commit()
-
-    else:
-        logger.warning(
-            f"Duplicate entries for PDB/3D accession {accession}"
-            f"Adding the accession entry with the ID {pdb_query[0].pdb_id} to the\n"
-            f"cazyme {cazyme.cazyme_name} id={cazyme.cazyme_id}"
-        )
-        if not(pdb_query[0] in cazyme.pdbs):
-            cazyme.pdbs.append(pdb_query[0])
-        session.commit()
-
-    session.commit()
-    return
diff --git a/scraper/sql/sql_interface.py b/scraper/sql/sql_interface.py
new file mode 100644
index 00000000..9901578e
--- /dev/null
+++ b/scraper/sql/sql_interface.py
@@ -0,0 +1,662 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
+# Author:
+# Emma E. M. Hobbs
+
+# Contact
+# eemh1@st-andrews.ac.uk
+
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+
+# The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+"""Submodule for interacting with a local SQL database"""
+
+
+import logging
+
+from sqlalchemy.exc import IntegrityError
+from scraper.sql.sql_orm import (
+    Cazyme,
+    Taxonomy,
+    CazyFamily,
+    Cazymes_Genbanks,
+    EC,
+    Genbank,
+    Kingdom,
+    Uniprot,
+    Pdb,
+)
+
+
+class SqlInterfaceException(Exception):
+    """General exception for SQL interface"""
+
+    def __init__(self, message):
+        self.message = message
+
+
+def add_protein_to_db(
+    cazyme_name,
+    family,
+    source_organism,
+    kingdom,
+    primary_genbank,
+    session,
+    ec_numbers=[],
+    gbk_nonprimary=[],
+    uni_primary=[],
+    uni_nonprimary=[],
+    pdb_accessions=[],
+):
+    """Coordinate adding protein (CAZyme) data to the SQL database (db).
+
+    Every CAZyme has a cazyme name (called 'protein name' in CAZy), CAZy (sub)family, source
+    organism, and primary GenBank accession. The 'protein_name' assigned by CAZy is not unique for
+    each protein. The primary GenBank accession is the only hyperlinked GenBank accession for the
+    protein, and believed to be used by CAZy to indicate the source GenBank protein record. It may
+    be possible that a GenBank accession is the primary accession for one CAZyme and a non-primary
+    accession for another, becuase CAZy does not appear to ID unique proteins  by the GenBank
+    accession because duplicate CAZyme entries can be found within CAZy.
+
+    EC numbers, UniProt accessions and PDB accessions may not be given. The UniProt and PDB
+    accessions are recorded as the primary accessions, and all other listed accessions as
+    non-primary accessions.
+
+    There are a minority of CAZymes in CAZy with NO GenBank accessions. These CAZymes are annotated
+    with the GenBank accession (str) 'NA' in the local db, and are logged.
+
+    :param cazyme_name: str, name of the protein/CAZyme
+    :param family: str, CAZy family or subfamily the protein is catalogued under in CAZy
+    :param source_organism: str, the scientific name of the organism from which the CAZy is derived
+    :param kingdom: str, taxonomy Kingdom of the source organism
+    :param primary_genbank: str, the hyperlinked GenBank accession from CAZy
+    :param session: open sqlalchemy session to database
+
+    ::optional parameters::
+    :param ec_numbers: list of EC numbers which the CAZyme is annotated with
+    :param gbk_nonprimary: list of non-primary GenBank accessions
+    :param uni_primary: list, primary accessions of associated records in UniProtKB
+    :param uni_nonprimary: list, non-primary accessions of associated records in UniProtKB
+    :param pdb_accessions: list, accessions of associated records in PDB
+
+    Return nothing.
+    """
+    error_message = None
+    # Each unique protein is identified by a unique primary GenBank accession
+    try:
+        primary_genbank_object = Genbank(genbank_accession=primary_genbank)
+        session.add(primary_genbank_object)
+        session.commit()
+
+    except IntegrityError:
+        # raised when Genbank accession already in the database
+        session.rollback()  # enable continued interation with the database
+
+        parse_unique_genbank_conflict(
+            cazyme_name,
+            family,
+            source_organism,
+            kingdom,
+            primary_genbank,
+            session,
+            ec_numbers,
+            gbk_nonprimary,
+            uni_primary,
+            uni_nonprimary,
+            pdb_accessions,
+        )
+
+        return
+
+    error_message = add_new_protein_to_db(
+        cazyme_name,
+        family,
+        source_organism,
+        kingdom,
+        primary_genbank_object,
+        session,
+        ec_numbers,
+        gbk_nonprimary,
+        uni_primary,
+        uni_nonprimary,
+        pdb_accessions,
+    )
+
+    if error_message is not None:
+        raise SqlInterfaceException(error_message)
+
+    return
+
+
+def parse_unique_genbank_conflict(
+    cazyme_name,
+    family,
+    source_organism,
+    kingdom,
+    primary_genbank,
+    session,
+    ec_numbers=[],
+    gbk_nonprimary=[],
+    uni_primary=[],
+    uni_nonprimary=[],
+    pdb_accessions=[],
+):
+    """Called when primary GenBank accession is already in the local database.
+
+    Check if the accession in the database is a primary accession. If it is then add data to the
+    existing protein record. If not then add the protein data as a new protein to the database.
+
+    :param cazyme_name: str, name of the protein/CAZyme
+    :param family: str, CAZy family or subfamily the protein is catalogued under in CAZy
+    :param source_organism: str, the scientific name of the organism from which the CAZy is derived
+    :param kingdom: str, taxonomy Kingdom of the source_organism
+    :param primary_genbank: str, the hyperlinked GenBank accession from CAZy
+    :param session: open sqlalchemy session to database
+
+    ::optional parameters::
+    :param ec_numbers: list of EC numbers which the CAZyme is annotated with
+    :param gbk_nonprimary: list of non-primary GenBank accessions
+    :param uni_primary: list, primary accessions of associated records in UniProtKB
+    :param uni_nonprimary: list, non-primary accessions of associated records in UniProtKB
+    :param pdb_acccessions: list, accessions of associated records in PDB
+
+    Return nothing.
+    """
+    logger = logging.getLogger(__name__)
+    error_message = None
+
+    # check if the local GenBank object is for a primary GenBank accession
+    primary_genbank_query = session.query(Genbank).\
+        filter(Genbank.genbank_accession == primary_genbank).\
+        filter(Cazymes_Genbanks.primary == True).all()
+
+    if len(primary_genbank_query) == 0:
+        # Accession was not found as a primary accession, inferring the protein is not in the db
+        error_message = add_new_protein_to_db(
+            cazyme_name,
+            family,
+            source_organism,
+            kingdom,
+            primary_genbank_query[0],
+            session,
+            ec_numbers,
+            gbk_nonprimary,
+            uni_primary,
+            uni_nonprimary,
+            pdb_accessions,
+        )
+
+    else:
+        # Primary GenBank accession found, add additional data to the respective CAZyme
+        cazyme_query = session.query(Cazyme, Genbank, Cazymes_Genbanks).\
+            join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+            join(Cazyme, (Cazyme.cazyme_id == Cazymes_Genbanks.cazyme_id)).\
+            filter(Genbank.genbank_accession == primary_genbank).\
+            filter(Cazymes_Genbanks.primary == True).all()
+
+        if len(cazyme_query) == 0:
+            logger.warning(
+                f"GenBank accession {primary_genbank}, id={primary_genbank_query[0].genbank_id}\n"
+                "was previously added to the local database, but not associated with a CAZyme\n"
+                "Adding protein data as a new CAZyme in the local database."
+            )
+            error_message = add_new_protein_to_db(
+                cazyme_name,
+                family,
+                source_organism,
+                kingdom,
+                primary_genbank_query[0],
+                session,
+                ec_numbers,
+                gbk_nonprimary,
+                uni_primary,
+                uni_nonprimary,
+                pdb_accessions,
+            )
+
+        elif len(cazyme_query) == 1:
+            add_data_to_protein_record(
+                cazyme_query[0][0],
+                family,
+                session,
+                ec_numbers,
+                gbk_nonprimary,
+                uni_primary,
+                uni_nonprimary,
+                pdb_accessions,
+            )
+
+        else:
+            # multiple CAZymes have the same primary GenBank accession, inferring duplicates
+            logger.warning(
+                "Potential duplicate CAZymes found in the local database, because they have the "
+                f"same primary GenBank accession {primary_genbank}\nPotential duplicate CAZymes:"
+            )
+            for cazyme in cazyme_query:
+                logger.warning(f"Name={cazyme[0].cazyme_name}, id={cazyme[0].cazyme_id}")
+            logger.warning(
+                f"Protein data added to cazyme {cazyme_query[0][0].cazyme_name}, "
+                f"id={cazyme_query[0][0].cazyme_id}"
+            )
+            add_data_to_protein_record(
+                cazyme_query[0][0],
+                family,
+                session,
+                ec_numbers,
+                gbk_nonprimary,
+                uni_primary,
+                uni_nonprimary,
+                pdb_accessions,
+            )
+
+    return error_message
+
+
+def add_new_protein_to_db(
+    cazyme_name,
+    family,
+    source_organism,
+    tax_kingdom,
+    primary_genbank_object,
+    session,
+    ec_numbers=[],
+    gbk_nonprimary=[],
+    uni_primary=[],
+    uni_nonprimary=[],
+    pdb_accessions=[],
+):
+    """Add a new protein (a CAZyme) record to the database.
+
+    :param cazyme_name: str, name of the protein/CAZyme
+    :param family: str, CAZy family or subfamily the protein is catalogued under in CAZy
+    :param source_organism: str, the scientific name of the organism from which the CAZy is derived
+    :param tax_kingdom: str, taxonomy Kingdom of the source organism
+    :param primary_genbank_object: sql_orm.Genbank instance, represents the primary accession
+    :param session: open sqlalchemy session to database
+
+    ::optional parameters::
+    :param ec_numbers: list of EC numbers which the CAZyme is annotated with
+    :param gbk_nonprimary: list of non-primary GenBank accessions
+    :param uni_primary: list, primary accessions of associated records in UniProtKB
+    :param uni_nonprimary: list, non-primary accessions of associated records in UniProtKB
+    :param pdb_accessions: list, =accessions of associated records in PDB
+
+    Return nothing.
+    """
+    logger = logging.getLogger(__name__)
+    error_message = None
+
+    # add the taxonomy Kingdom
+    try:
+        new_kingdom = Kingdom(kingdom=f'{tax_kingdom[0].upper()}{tax_kingdom[1:]}')
+        session.add(new_kingdom)
+        session.commit()
+    except IntegrityError:  # raised when Kingdom is already in the Kingdom table
+        session.rollback()
+        # retrieve the existing Kingdom instance
+        tax_kingdom = f'{tax_kingdom[0].upper()}{tax_kingdom[1:]}'
+        new_kingdom = session.query(Kingdom).filter(Kingdom.kingdom == tax_kingdom).all()[0]
+
+    # define source organism
+    if source_organism == 'unidentified':
+        genus = source_organism
+        species = source_organism
+
+    else:
+        genus_sp_separator = source_organism.find(" ")
+        genus = source_organism[:genus_sp_separator]
+        species = source_organism[genus_sp_separator:]
+
+    # Add the CAZyme and its taxonomy data
+    try:
+        new_tax = Taxonomy(genus=genus, species=species)
+        new_tax.tax_kingdom = new_kingdom
+
+        new_cazyme = Cazyme(cazyme_name=cazyme_name)
+        new_cazyme.taxonomy = new_tax
+
+        session.add(new_cazyme)
+        session.commit()
+
+    except IntegrityError:  # raised if Taxonomy record already in the db
+        session.rollback()
+
+        try:
+            new_cazyme = Cazyme(cazyme_name=cazyme_name)
+            tax_query = session.query(Taxonomy).\
+                filter(Taxonomy.genus == genus).filter(Taxonomy.species == species).all()
+            tax_query[0].cazymes.append(new_cazyme)
+            session.commit()
+
+        except IntegrityError:
+            logger.warning(
+                f"Could not add Taxonomy data for cazyme {cazyme_name} from {genus} {species}"
+            )
+            error_message = (
+                f"Could not add CAZyme {cazyme_name} from {source_organism} to the database"
+            )
+
+    # establish relationship between the CAZyme and its primary GenBank accession
+    try:
+        relationship = Cazymes_Genbanks(
+            cazymes=new_cazyme,
+            genbanks=primary_genbank_object,
+            primary=True,
+        )
+        session.add(relationship)
+        session.commit()
+    except IntegrityError:  # raised if CAZyme and GenBank accession are already linked
+        session.rollback()
+
+    if family.find("_") != -1:
+        add_cazy_subfamily(family, new_cazyme, session)
+    else:
+        add_cazy_family(family, new_cazyme, session)
+
+    if len(ec_numbers) != 0:
+        add_ec_numbers(ec_numbers, new_cazyme, session)
+
+    if len(gbk_nonprimary) != 0:
+        add_nonprimary_gbk_accessions(gbk_nonprimary, new_cazyme, session)
+
+    if len(uni_primary) != 0:
+        add_uniprot_accessions(uni_primary, new_cazyme, True, session)
+
+    if len(uni_nonprimary) != 0:
+        add_uniprot_accessions(uni_nonprimary, new_cazyme, False, session)
+
+    if len(pdb_accessions) != 0:
+        add_pdb_accessions(pdb_accessions, new_cazyme, session)
+
+    return error_message
+
+
+def add_data_to_protein_record(
+    cazyme,
+    family,
+    session,
+    ec_numbers=[],
+    gbk_nonprimary=[],
+    uni_primary=[],
+    uni_nonprimary=[],
+    pdb_accessions=[],
+):
+    """Add data to an existing record in the SQL database.
+
+    :param cazyme_name: Cazyme class instance - class imported from scraper.sql.sql_orm
+    :param family: str, CAZy family or subfamily the protein is catalogued under in CAZy
+    :param session: open sqlalchemy session to database
+
+    ::optional parameters::
+    :param ec_numbers: list of EC numbers which the CAZyme is annotated with
+    :param gbk_nonprimary: list of non-primary GenBank accessions
+    :param uni_primary: list, primary accessions of associated records in UniProtKB
+    :param uni_nonprimary: list, non-primary accessions of associated records in UniProtKB
+    :param pdb_accessions: list, accessions of associated records in PDB
+
+    Return nothing.
+    """
+    if family.find("_") != -1:
+        add_cazy_subfamily(family, cazyme, session)
+    else:
+        add_cazy_family(family, cazyme, session)
+
+    if len(ec_numbers) != 0:
+        add_ec_numbers(ec_numbers, cazyme, session)
+
+    if len(gbk_nonprimary) != 0:
+        add_nonprimary_gbk_accessions(gbk_nonprimary, cazyme, session)
+
+    if len(uni_primary) != 0:
+        add_uniprot_accessions(uni_primary, cazyme, True, session)
+
+    if len(uni_nonprimary) != 0:
+        add_uniprot_accessions(uni_nonprimary, cazyme, False, session)
+
+    if len(pdb_accessions) != 0:
+        add_pdb_accessions(pdb_accessions, cazyme, session)
+
+    return
+
+
+def add_cazy_family(family, cazyme, session):
+    """Add CAZy family to CAZyme record in the local CAZy database.
+
+    :param family: str, name of a CAZy family/subfamily
+    :param cazyme: Cazymes class object
+    :param session: open local database session connector
+
+    Return nothing.
+    """
+    try:
+        cazyme.families.append(CazyFamily(family=family))
+        session.commit()
+        return
+
+    except IntegrityError:
+        session.rollback()
+
+    # get the record that caused raising the Integrity Error
+    family_query = session.query(CazyFamily).filter(CazyFamily.family == family).all()
+
+    try:
+        cazyme.families.append(family_query[0])
+        session.commit()
+    except (IntegrityError, IndexError) as e:
+        session.rollback()
+
+    return
+
+
+def add_cazy_subfamily(subfamily, cazyme, session):
+    """Add CAZy family to CAZyme record in the local CAZy database.
+
+    :param family: str, name of a CAZy family/subfamily
+    :param cazyme: Cazymes class object
+    :param session: open local database session connector
+
+    Return nothing.
+    """
+    family = subfamily[:subfamily.find("_")]
+
+    try:
+        cazyme.families.append(CazyFamily(family=family, subfamily=subfamily))
+        session.commit()
+        return
+
+    except IntegrityError:
+        session.rollback()
+
+    # get the record that caused raising the IntegrityError
+    subfam_query = session.query(CazyFamily).\
+        filter(CazyFamily.family == family).filter(CazyFamily.subfamily == subfamily).all()
+
+    try:
+        cazyme.families.append(subfam_query[0])
+        session.commit()
+    except (IntegrityError, IndexError) as e:
+        session.rollback()
+
+    return
+
+
+# Note: Not all CAZymes have non-primary GenBank accessions, EC numbers, UniProt accessions or
+# PDB accessions
+
+
+def add_nonprimary_gbk_accessions(genbank_accessions, cazyme, session):
+    """Add non-primary GenBank protein accessions to the local database.
+
+    :param genbank_accessions: list of non-primary GenBank protein accession numbers (str)
+    :param cazyme: Cazymes class object
+    :param session: open local database session connector
+
+    Return nothing.
+    """
+    for accession in genbank_accessions:
+        try:
+            new_genbank = Genbank(genbank_accession=accession)
+            session.add(new_genbank)
+            session.commit()
+
+        except IntegrityError:
+            session.rollback()
+
+            genbank_query = session.query(Genbank, Cazymes_Genbanks).\
+                filter(Genbank.genbank_accession == accession).\
+                filter(Cazymes_Genbanks.primary == False).all()
+
+            try:
+                relationship = Cazymes_Genbanks(
+                    cazyme_id=cazyme.cazyme_id,
+                    genbank_id=genbank_query[0][0].genbank_id,
+                    primary=False,
+                )
+                session.add(relationship)
+                session.commit()
+            except (IntegrityError, IndexError) as e:
+                session.rollback()
+            continue
+
+        try:
+            relationship = Cazymes_Genbanks(cazymes=cazyme, genbanks=new_genbank, primary=False)
+            session.add(relationship)
+            session.commit()
+        except IntegrityError:
+            session.rollback()
+
+    return
+
+
+def add_ec_numbers(ec_numbers, cazyme, session):
+    """Add EC numbers to CAZyme record in the local CAZy database.
+
+    :param ec_numbers: list of EC numbers (str)
+    :param new_cazyme: Cazymes class object
+    :param session: open local database session connector
+
+    Return nothing.
+    """
+    for ec in ec_numbers:
+        try:
+            new_ec = EC(ec_number=ec)
+            session.add(new_ec)
+            session.commit()
+
+        except IntegrityError:
+            session.rollback()
+
+            ec_query = session.query(EC).filter(EC.ec_number == ec).all()
+            try:
+                cazyme.ecs.append(ec_query[0])
+                session.commit()
+            except (IntegrityError, IndexError) as e:
+                session.rollback()
+            continue
+
+        try:
+            cazyme.ecs.append(new_ec)
+            session.commit()
+        except IntegrityError:
+            session.rollback()
+
+    return
+
+
+def add_uniprot_accessions(uniprot_accessions, cazyme, primary, session):
+    """Add primary UniProt accessions to CAZyme record in local CAZy database.
+
+    :param uniprot_accessions: list of Uniprot accessions
+    :param cazyme: Cazyme class instance
+    :param primary: boolean, True = primary accessions, False non-primary accessions
+    :param session: open local database session connector
+
+    Return nothing.
+    """
+    for accession in uniprot_accessions:
+        try:
+            new_uniprot = Uniprot(uniprot_accession=accession, primary=primary)
+            session.add(new_uniprot)
+            session.commit()
+        except IntegrityError:
+            session.rollback()
+
+            uniprot_query = session.query(Uniprot).filter(Uniprot.uniprot_accession == accession).\
+                filter(Uniprot.primary == primary).all()
+
+            try:
+                cazyme.uniprots.append(uniprot_query[0])
+                session.commit()
+            except (IntegrityError, IntegrityError) as e:
+                session.rollback()
+            continue
+
+        try:
+            cazyme.uniprots.append(new_uniprot)
+            session.commit()
+        except IntegrityError:
+            session.rollback()
+
+    return
+
+
+def add_pdb_accessions(pdb_accessions, cazyme, session):
+    """Add PDB/3D protein accessions to CAZyme record in the local CAZy database.
+
+    :param pdb_accessions: list of UniProt protein accession numbers (str)
+    :param cazyme: Cazymes class object
+    :param session: open local database session connector
+
+    Return nothing.
+    """
+    for accession in pdb_accessions:
+        try:
+            new_pdb = Pdb(pdb_accession=accession)
+            session.add(new_pdb)
+            session.commit()
+        except IntegrityError:
+            session.rollback()
+
+            pdb_query = session.query(Pdb).filter(Pdb.pdb_accession == accession).all()
+
+            try:
+                cazyme.pdbs.append(pdb_query[0])
+                session.commit()
+            except (IntegrityError, IntegrityError) as e:
+                session.rollback()
+            continue
+
+        try:
+            cazyme.pdbs.append(new_pdb)
+            session.commit()
+        except IntegrityError:
+            session.rollback()
+
+    return
diff --git a/scraper/sql/sql_orm.py b/scraper/sql/sql_orm.py
new file mode 100644
index 00000000..c92f8ff9
--- /dev/null
+++ b/scraper/sql/sql_orm.py
@@ -0,0 +1,557 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
+# Author:
+# Emma E. M. Hobbs
+
+# Contact
+# eemh1@st-andrews.ac.uk
+
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+
+# The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+"""Submodule to build a local SQL database"""
+
+import logging
+import os
+import re
+import sys
+
+import sqlite3
+
+from sqlalchemy import (
+    Boolean,
+    Column,
+    ForeignKey,
+    Index,
+    Integer,
+    PrimaryKeyConstraint,
+    String,
+    Table,
+    UniqueConstraint,
+    create_engine,
+    event,
+    exc,
+)
+from sqlalchemy.engine import Engine
+from sqlalchemy.ext.compiler import compiles
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy.orm import relationship, sessionmaker
+from sqlalchemy.sql.expression import BinaryExpression, func, literal
+from sqlalchemy.sql.operators import custom_op
+
+
+# Use the declarative system
+# Database structured in NF1
+Base = declarative_base()
+Session = sessionmaker()
+
+
+# Enable regular expression searching of the database
+class ReString(String):
+    """Enchanced version of standard SQLAlchemy's :class:`String`.
+
+    Supports additional operators that can be used while constructing filter expressions.
+    """
+    class comparator_factory(String.comparator_factory):
+        """Contains implementation of :class:`String` operators related to regular expressions."""
+        def regexp(self, other):
+            return RegexMatchExpression(self.expr, literal(other), custom_op('~'))
+
+        def iregexp(self, other):
+            return RegexMatchExpression(self.expr, literal(other), custom_op('~*'))
+
+        def not_regexp(self, other):
+            return RegexMatchExpression(self.expr, literal(other), custom_op('!~'))
+
+        def not_iregexp(self, other):
+            return RegexMatchExpression(self.expr, literal(other), custom_op('!~*'))
+
+
+class RegexMatchExpression(BinaryExpression):
+    """Represents matching of a column againsts a regular expression."""
+
+
+@compiles(RegexMatchExpression, 'sqlite')
+def sqlite_regex_match(element, compiler, **kw):
+    """Compile the SQL expression representing a regular expression match for the SQLite engine."""
+    # determine the name of a custom SQLite function to use for the operator
+    operator = element.operator.opstring
+    try:
+        func_name, _ = SQLITE_REGEX_FUNCTIONS[operator]
+    except (KeyError, ValueError) as e:
+        would_be_sql_string = ' '.join((compiler.process(element.left),
+                                        operator,
+                                        compiler.process(element.right)))
+        raise exc.StatementError(
+            f"unknown regular expression match operator: {operator} {would_be_sql_string} {e}"
+        )
+
+    # compile the expression as an invocation of the custom function
+    regex_func = getattr(func, func_name)
+    regex_func_call = regex_func(element.left, element.right)
+    return compiler.process(regex_func_call)
+
+
+@event.listens_for(Engine, 'connect')
+def sqlite_engine_connect(dbapi_connection, connection_record):
+    """Listener for the event of establishing connection to a SQLite database.
+
+    Creates the functions handling regular expression operators
+    within SQLite engine, pointing them to their Python implementations above.
+    """
+    if not isinstance(dbapi_connection, sqlite3.Connection):
+        return
+
+    for name, function in SQLITE_REGEX_FUNCTIONS.values():
+        dbapi_connection.create_function(name, 2, function)
+
+
+# Mapping from the regular expression matching operators
+# to named Python functions that implement them for SQLite.
+SQLITE_REGEX_FUNCTIONS = {
+    '~': ('REGEXP',
+          lambda value, regex: bool(re.match(regex, value))),
+    '~*': ('IREGEXP',
+           lambda value, regex: bool(re.match(regex, value, re.IGNORECASE))),
+    '!~': ('NOT_REGEXP',
+           lambda value, regex: not re.match(regex, value)),
+    '!~*': ('NOT_IREGEXP',
+            lambda value, regex: not re.match(regex, value, re.IGNORECASE)),
+}
+
+
+# define association/relationship tables
+
+
+# linker table between cazymes and CAZy family and subfamilies
+cazymes_families = Table(
+    "cazymes_families",
+    Base.metadata,
+    Column("cazyme_id", Integer, ForeignKey("cazymes.cazyme_id")),
+    Column("family_id", Integer, ForeignKey("families.family_id")),
+    PrimaryKeyConstraint("cazyme_id", "family_id"),
+)
+
+
+# linker table between cazymes and ec numbers
+cazymes_ecs = Table(
+    "cazymes_ecs",
+    Base.metadata,
+    Column("cazyme_id", Integer, ForeignKey("cazymes.cazyme_id")),
+    Column("ec_id", Integer, ForeignKey("ecs.ec_id")),
+    PrimaryKeyConstraint("cazyme_id", "ec_id"),
+)
+
+
+# linker table between cazymes and UniProt accessions of CAZymes
+cazymes_uniprots = Table(
+    "cazymes_uniprots",
+    Base.metadata,
+    Column("cazyme_id", Integer, ForeignKey("cazymes.cazyme_id")),
+    Column("uniprot_id", Integer, ForeignKey("uniprots.uniprot_id")),
+    PrimaryKeyConstraint("cazyme_id", "uniprot_id"),
+)
+
+
+# linker table between CAZymes and PDB structures
+cazymes_pdbs = Table(
+    "cazymes_pdbs",
+    Base.metadata,
+    Column("cazyme_id", Integer, ForeignKey("cazymes.cazyme_id")),
+    Column("pdb_id", Integer, ForeignKey("pdbs.pdb_id")),
+    PrimaryKeyConstraint("cazyme_id", "pdb_id"),
+)
+
+
+# define models
+
+
+class Cazyme(Base):
+    """Describes a CAZyme, which is a protein single entry in CAZy.
+
+    Every CAZyme will have a name, a source organism, at least one CAZy family, and at least
+    a primary GenBank accession. A CAZyme may also have non-primary GenBank accessions, EC
+    number annotations, UniProt accessions and PDB accessions.
+    """
+    __tablename__ = "cazymes"
+
+    cazyme_id = Column(Integer, primary_key=True)
+    cazyme_name = Column(String)
+    taxonomy_id = Column(Integer, ForeignKey("taxs.taxonomy_id"))
+
+    taxonomy = relationship("Taxonomy", back_populates="cazymes")
+
+    families = relationship(
+        "CazyFamily",
+        secondary=cazymes_families,
+        back_populates="cazymes",
+        lazy="dynamic",
+    )
+    cazymes_genbanks = relationship(
+        "Cazymes_Genbanks",
+        back_populates="cazymes",
+        lazy="dynamic",
+    )
+
+    # Not all CAZymes will have EC numbers, UniProt accessions or PDB accessions
+    ecs = relationship(
+        "EC",
+        secondary=cazymes_ecs,
+        back_populates="cazymes",
+        lazy="dynamic",
+    )
+    uniprots = relationship(
+        "Uniprot",
+        secondary=cazymes_uniprots,
+        back_populates="cazymes",
+        lazy="dynamic",
+    )
+    pdbs = relationship(
+        "Pdb",
+        secondary=cazymes_pdbs,
+        back_populates="cazymes",
+        lazy="dynamic",
+    )
+
+    def __str__(self):
+        return f"-CAZyme name={self.cazyme_name}, id={self.cazyme_id}-"
+
+    def __repr__(self):
+        return f"<Class Cazyme: name={self.cazyme_name}, id={self.cazyme_id}>"
+
+
+class Taxonomy(Base):
+    """Describes the source organism of CAZymes."""
+    __tablename__ = "taxs"
+    __table_args__ = (
+        UniqueConstraint("genus", "species"),
+        Index("organism_index", "genus", "species", "kingdom_id")
+    )
+
+    taxonomy_id = Column(Integer, primary_key=True)
+    genus = Column(String)
+    species = Column(String)
+    kingdom_id = Column(Integer, ForeignKey("kingdoms.kingdom_id"))
+
+    tax_kingdom = relationship("Kingdom", back_populates="taxonomy")
+
+    cazymes = relationship("Cazyme", back_populates="taxonomy")
+
+    def __str__(self):
+        return f"-Source organism, Genus={self.genus}, Species={self.species}-"
+
+    def __repr__(self):
+        return (
+            f"<Class Taxonomy: genus={self.genus}, species={self.species}, id={self.taxonomy_id}>"
+        )
+
+
+class Kingdom(Base):
+    """Describes a taxonomy Kingdom."""
+    __tablename__ = "kingdoms"
+    __table_args__ = (
+        UniqueConstraint("kingdom"),
+    )
+
+    kingdom_id = Column(Integer, primary_key=True)
+    kingdom = Column(String)
+
+    taxonomy = relationship("Taxonomy", back_populates="tax_kingdom")
+
+    def __str__(self):
+        return f"-Kingdom, taxonomy_kingdom={self.kingdom}-"
+
+    def __repr__(self):
+        return f"<Class Kingdom, taxonomy_kingdom={self.kingdom}, id={self.kingdom_id}>"
+
+
+class CazyFamily(Base):
+    """Describes a CAZy family.
+
+    Every unique CAZy family-subfamily pair will be given a unique family_id. For example,
+    if a CAZyme is catalogued under a subfamily, the parent CAZy family and the CAZy subfamily
+    will be listed together, and given a single family_id. If another protein is catalogued
+    under only the parent CAZy family, another entry with for the CAZy family will be made with
+    a null value for the subfamily and a different family_id. """
+    __tablename__ = "families"
+
+    family_id = Column(Integer, primary_key=True)
+    family = Column(ReString, nullable=False)
+    subfamily = Column(String, nullable=True)
+
+    __table_args__ = (
+        Index(
+            "subfamily_option",
+            "family",
+            "subfamily",
+            unique=True,
+            postgresql_where=(subfamily.isnot(None)),
+        ),
+        Index("family_option", "family", unique=True, postgresql_where=(subfamily.is_(None))),
+    )
+
+    cazymes = relationship(
+        "Cazyme",
+        secondary=cazymes_families,
+        back_populates="families",
+        lazy="dynamic",
+    )
+
+    def __str__(self):
+        if self.subfamily is None:
+            return f"-CAZy family {self.family}, id={self.family_id}-"
+        else:
+            return f"-CAZy subfamily {self.subfamily}, parent={self.family}, id={self.family_id}-"
+
+    def __repr__(self):
+        """Return string representation of source organism."""
+        return(
+            f"<Class Family, family={self.family}, subfamily={self.subfamily}, id={self.family_id}"
+        )
+
+
+class Genbank(Base):
+    """Describe a GenBank accession number of protein sequences.
+
+    The associated GenBank protein record is the source record from which CAZy retrieves the
+    protein sequence for the CAZyme.
+    """
+    __tablename__ = "genbanks"
+    __table_args__ = (
+        UniqueConstraint("genbank_accession"),
+    )
+
+    genbank_id = Column(Integer, primary_key=True)
+    genbank_accession = Column(String, index=True)
+    sequence = Column(String)
+    seq_update_date = Column(String)  # 'YYYY/MM/DD'
+
+    cazymes_genbanks = relationship(
+        "Cazymes_Genbanks",
+        back_populates="genbanks",
+        lazy="dynamic",
+    )
+
+    def __str__(self):
+        return f"-Genbank accession={self.genbank_accession}-"
+
+    def __repr__(self):
+        return f"<Class GenBank acc={self.genbank_accession}>"
+
+
+class Cazymes_Genbanks(Base):
+    """Represent assoication between a CAZyme and its primary and non-primary GenBank accessions.
+
+    The primary GenBank accession is the only hyperlinked
+    GenBank accession for the protein, and believed to be used by CAZy to indicate the source
+    GenBank protein record for the record in CAZy. It can not be guareenteed that a GenBank
+    accession will only be recorded as a primary OR a non-primary accession. It may be possible
+    that a GenBank accession is the primary accession for one CAZyme and a non-primary accession
+    for another. This is believed to be possible becuase CAZy does not appear to ID unique proteins
+    by the GenBank accession because duplicate entries for CAZyme can be found within CAZy.
+    """
+    __tablename__ = "cazymes_genbanks"
+    __table_args__ = (
+        UniqueConstraint("cazyme_id", "genbank_id", "primary"),
+    )
+
+    link_id = Column(Integer, primary_key=True)  # unique ID of the CAZyme-GenBank relationship
+    cazyme_id = Column(Integer, ForeignKey("cazymes.cazyme_id"))
+    genbank_id = Column(Integer, ForeignKey("genbanks.genbank_id"))
+
+    primary = Column(Boolean, index=True)
+
+    cazymes = relationship("Cazyme", back_populates="cazymes_genbanks")
+    genbanks = relationship("Genbank", back_populates="cazymes_genbanks")
+
+    def __str__(self):
+        return f"cazyme_id={self.cazyme_id}--genbank_id={self.genbank_id}--primary={self.primary}-"
+
+    def __repr__(self):
+        return(
+            f"<Class Cazymes_GenBanks cazyme_id={self.cazyme_id}-"
+            f"-genbank_id={self.genbank_id}-primary={self.primary}>"
+        )
+
+
+# Not all CAZymes will have EC numbers, UniProt accessions or PDB accessions
+
+
+class EC(Base):
+    """Describe EC numbers."""
+    __tablename__ = "ecs"
+    __table_args__ = (
+        UniqueConstraint("ec_number"),
+    )
+
+    ec_id = Column(Integer, primary_key=True)
+    ec_number = Column(String, index=True)
+
+    cazymes = relationship("Cazyme", secondary=cazymes_ecs, back_populates="ecs", lazy="dynamic")
+
+    def __str__(self):
+        return f"-EC{self.ec_number}-ec_id={self.ec_number}-"
+
+    def __repr__(self):
+        return f"<Class EC, EC{self.ec_number}, ec_id={self.ec_number}>"
+
+
+class Uniprot(Base):
+    """Describe a UniProt accession number.
+
+    The primary UniProt accession is the first UniProt accession that is lsited in UniProt for
+    the CAZyme.
+    """
+    __tablename__ = "uniprots"
+    __table_args__ = (
+        UniqueConstraint("uniprot_accession", "primary"),
+    )
+
+    uniprot_id = Column(Integer, primary_key=True)
+    uniprot_accession = Column(String)
+    primary = Column(Boolean)
+    sequence = Column(String)
+    seq_update_date = Column(String)  # 'YYYY/MM/DD'
+
+    Index('uniprot_idx', uniprot_accession, primary)
+
+    cazymes = relationship(
+        "Cazyme",
+        secondary=cazymes_uniprots,
+        back_populates="uniprots",
+        lazy="dynamic",
+    )
+
+    def __str__(self):
+        return(
+            f"-UniProt accession={self.uniprot_accession}, "
+            f"id={self.uniprot_id}, primary={self.primary}-"
+        )
+
+    def __repr__(self):
+        return(
+            f"<Class Uniprot accession={self.uniprot_accession}, "
+            f"id={self.uniprot_id}, primary={self.primary}>"
+        )
+
+
+class Pdb(Base):
+    """Describe a PDB accession number of protein structure."""
+    __tablename__ = "pdbs"
+    __table_args__ = (
+        UniqueConstraint("pdb_accession"),
+    )
+
+    pdb_id = Column(Integer, primary_key=True)
+    pdb_accession = Column(String)
+
+    Index('pdb_idx', pdb_accession)
+
+    cazymes = relationship("Cazyme", secondary=cazymes_pdbs, back_populates="pdbs", lazy="dynamic")
+
+    def __str__(self):
+        return f"-PDB accession={self.pdb_accession}, id={self.pdb_id}-"
+
+    def __repr__(self):
+        return f"<Class Pdb accession={self.pdb_accession}, id={self.pdb_id}>"
+
+
+class Log(Base):
+    """Record what data was added to the database and when."""
+    __tablename__ = "logs"
+
+    log_id = Column(Integer, primary_key=True)
+    date = Column(String)  # date CAZy scrape was initiated
+    time = Column(String)  # time scrape was initated
+    classes = Column(String)  # CAZy classes scraped
+    families = Column(String)  # CAZy families scraped
+    kingdoms = Column(String)  # Taxonomy Kingdoms to retrieve CAZymes from
+    genera_filter = Column(String)
+    species_filter = Column(String)
+    strains_filter = Column(String)
+    cmd_line = Column(String)  # command line arguments
+
+    def __str__(self):
+        return(
+            f"Log: date={self.date}, scraped classes={self.classes}, "
+            f"scraped families={self.families}, cmd line commands={self.cmd_line}"
+        )
+
+    def __repr__(self):
+        return(
+            f"Class Log: date={self.date}, scraped classes={self.classes}, "
+            f"scraped families={self.families}, cmd line commands={self.cmd_line}>"
+        )
+
+
+def build_db(time_stamp, args):
+    """Build an empty SQL database and open a session.
+
+    :param time_stamp: str, date and time stamp of when scrape was initated
+    :param args: cmd args parser
+
+    Return an open database session.
+    """
+    logger = logging.getLogger(__name__)
+    logger.info("Building empty db to store data")
+
+    if args.output is sys.stdout:
+        # write to cwd, this is deleted in scrape is successful
+        cwd = os.getcwd()
+        db_path = cwd + f"cazy_scrape_temp_{time_stamp}.db"
+
+    else:
+        # write to specified output directory
+        db_path = args.output / f"cazy_scrape_{time_stamp}.db"
+
+    engine = create_engine(f"sqlite+pysqlite:///{db_path}", echo=False)
+    Base.metadata.create_all(engine)
+    Session.configure(bind=engine)
+
+    return Session()
+
+
+def get_db_session(args):
+    """Create open session to local CAZy SQL database.
+
+    :param args: cmd args parser
+
+    Return an open database session.
+    """
+    logger = logging.getLogger(__name__)
+    logger.info("Opening session to an existing local database")
+
+    db_path = args.database
+
+    engine = create_engine(f"sqlite+pysqlite:///{db_path}", echo=False)
+    Base.metadata.create_all(engine)
+    Session.configure(bind=engine)
+
+    return Session()
diff --git a/scraper/useful_websites.txt b/scraper/useful_websites.txt
deleted file mode 100644
index f9ee0370..00000000
--- a/scraper/useful_websites.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-https://docs.sqlalchemy.org/en/13/orm/tutorial.html
-http://www.mapfish.org/doc/tutorials/sqlalchemy.html
-
-https://realpython.com/flask-connexion-rest-api-part-3/#sqlalchemy-models
-https://realpython.com/building-a-simple-web-app-with-bottle-sqlalchemy-twitter-api/#the-db-and-sqlalchemy
-https://realpython.com/flask-by-example-part-2-postgres-sqlalchemy-and-alembic/
-https://realpython.com/python-sqlite-sqlalchemy/#working-with-sqlalchemy-and-python-objects
diff --git a/scraper/utilities/__init__.py b/scraper/utilities/__init__.py
index 8cc0468b..24f64188 100644
--- a/scraper/utilities/__init__.py
+++ b/scraper/utilities/__init__.py
@@ -1,5 +1,7 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
 # Author:
 # Emma E. M. Hobbs
 
@@ -16,194 +18,47 @@
 # UK
 
 # The MIT License
-"""Build cmd-line parser and logger."""
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+"""Module containing functions for building parsers, loggers and parsing configuration."""
+
 
-import argparse
 import logging
-import sys
-
-from pathlib import Path
-from typing import List, Optional
-
-
-def build_parser(argv: Optional[List] = None):
-    """Return ArgumentParser parser for script."""
-    # Create parser object
-    parser = argparse.ArgumentParser(
-        prog="cazy_webscraper.py",
-        description="Scrapes the CAZy database",
-        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
-    )
-
-    # Add optional arguments to parser
-
-    # Add option to specify path to configuration file
-    parser.add_argument(
-        "-c",
-        "--config",
-        type=Path,
-        metavar="config file",
-        default=None,
-        help="Path to configuration file. Default: None, scrapes entire database",
-    )
-
-    # Add option to define complete classes to scrape
-    parser.add_argument(
-        "--classes",
-        type=str,
-        default=None,
-        help="Classes from which all families are to be scraped. Separate classes by ','"
-    )
-
-    # Add option on how to split data
-    parser.add_argument(
-        "-d",
-        "--data_split",
-        choices=[None, "class", "family"],
-        type=str,
-        default=None,
-        help="How data is to be split. Not split=all, split by class=class, split by family=family",
-    )
-
-    # Add option to force file over writting
-    parser.add_argument(
-        "-f",
-        "--force",
-        dest="force",
-        action="store_true",
-        default=False,
-        help="Force file over writting",
-    )
-
-    # Add option to specify families to scrape
-    parser.add_argument(
-        "--families",
-        type=str,
-        default=None,
-        help="Families to scrape. Separate families by commas 'GH1,GH2'"
-    )
-
-    # Add option to download FASTA file for protein from GenBank
-    parser.add_argument(
-        "-g",
-        "--genbank",
-        type=str,
-        metavar="Email address of user",
-        default=None,
-        help="Enable FASTA files from GenBank, and user email required for Entrez",
-    )
-
-    # Add log file name option
-    # If not given, no log file will be written out
-    parser.add_argument(
-        "-l",
-        "--log",
-        type=Path,
-        metavar="log file name",
-        default=None,
-        help="Defines log file name and/or path",
-    )
-
-    # Add option to prevent over writing of existing files
-    # and cause addition of files to output directory
-    parser.add_argument(
-        "-n",
-        "--nodelete",
-        dest="nodelete",
-        action="store_true",
-        default=False,
-        help="enable/disable deletion of exisiting files",
-    )
-
-    # Add option to specify output directory to write output dataframes to
-    parser.add_argument(
-        "-o",
-        "--output",
-        type=Path,
-        metavar="output file name",
-        default=sys.stdout,
-        help="Output filename",
-    )
-
-    # Add option to specify ouput directory for writing out fasta files from GenBank to
-    parser.add_argument(
-        "-genbank_output",
-        type=Path,
-        metavar="output file name",
-        default=sys.stdout,
-        help="Output filename",
-    )
-
-    # Add option to specift output directory for writing out PDB structure files to
-    parser.add_argument(
-        "-pdb_output",
-        type=Path,
-        metavar="output file name",
-        default=None,
-        help="Output filename",
-    )
-
-    # Add option to download FASTA file for protein from GenBank
-    parser.add_argument(
-        "-p",
-        "--pdb",
-        choices=[None, "mmCif", "pdb", "xml", "mmtf", "bundle"],
-        type=str,
-        default=None,
-        help="Enable downloading of protein structures in XXXX format from PDB",
-    )
-
-    # Add option to enable number of times to retry scraping
-    parser.add_argument(
-        "-r",
-        "--retries",
-        type=int,
-        default=0,
-        help="Number of times to retry scraping a family or class page if error encountered",
-    )
-
-    # Add option to enable retrieval of subfamilies
-    parser.add_argument(
-        "-s",
-        "--subfamilies",
-        dest="subfamilies",
-        action="store_true",
-        default=False,
-        help="Enable retrieval of subfamilies from CAZy",
-    )
-
-    # Add option for more detail (verbose) logging
-    parser.add_argument(
-        "-v",
-        "--verbose",
-        dest="verbose",
-        action="store_true",
-        default=False,
-        help="Set logger level to 'INFO'",
-    )
-
-    if argv is None:
-        # parse command-line
-        return parser
-    else:
-        # return namespace
-        return parser.parse_args(argv)
 
 
-def build_logger(script_name, args) -> logging.Logger:
-    """Return a logger for this script.
-    Enables logger for script, sets parameters and creates new file to store log.
-    :param script_name: str, name of script
-    :param args: parser argument
-    Return logger object.
+def config_logger(args) -> logging.Logger:
+    """Configure package wide logger.
+
+    Configure a logger at the package level, from which the module will inherit.
+    If CMD-line args are provided, these are used to define output streams, and
+    logging level.
+
+    :param args: cmd-line args parser
+
+    Return nothing
     """
-    logger = logging.getLogger(script_name)
+    logger = logging.getLogger(__package__)
 
     # Set format of loglines
-    log_formatter = logging.Formatter(
-        script_name + ": {} - {}".format("%(asctime)s", "%(message)s")
-    )
+    log_formatter = logging.Formatter("[%(levelname)s] [%(name)s]: %(message)s")
 
+    # define logging level
     if args.verbose is True:
         logger.setLevel(logging.INFO)
     else:
@@ -220,4 +75,4 @@ def build_logger(script_name, args) -> logging.Logger:
         file_log_handler.setFormatter(log_formatter)
         logger.addHandler(file_log_handler)
 
-    return logger
+    return
diff --git a/scraper/utilities/file_io/__init__.py b/scraper/utilities/file_io/__init__.py
new file mode 100644
index 00000000..8a417b43
--- /dev/null
+++ b/scraper/utilities/file_io/__init__.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
+# Author:
+# Emma E. M. Hobbs
+
+# Contact
+# eemh1@st-andrews.ac.uk
+
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+
+# The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+"""Submodule for handling inputs and outputs"""
+
+
+import logging
+import shutil
+import sys
+
+from Bio import SeqIO
+
+
+def make_output_directory(output, force, nodelete):
+    """Create output directory for genomic files.
+
+    :param output: path, path of dir to be created
+    :param force: bool, enable/disable creating dir if already exists
+    :param nodelete: bool, enable/disable deleting content in existing dir
+
+    Raises FileExistsError if an attempt is made to create a directory that already
+    exist and force (force overwrite) is False.
+
+    Return Nothing
+    """
+    logger = logging.getLogger(__name__)
+
+    if output.exists():
+        if force is True:
+
+            if nodelete is True:
+                logger.warning(
+                    f"Output directory {output} exists, nodelete is {nodelete}. "
+                    "Adding output to output directory."
+                )
+                return
+
+            else:
+                logger.warning(
+                    f"Output directory {output} exists, nodelete is {nodelete}. "
+                    "Deleting content currently in output directory."
+                )
+                shutil.rmtree(output)
+                output.mkdir(exist_ok=force)
+                return
+
+        else:
+            logger.warning(
+                f"Output directory {output} exists. 'force' is False, cannot write to existing "
+                "output directory.\nTerminating program."
+            )
+            sys.exit(1)
+
+    else:
+        output.mkdir(exist_ok=force)
+        logger.warning(f"Built output directory: {output}")
+
+    return
+
+
+def write_out_failed_scrapes(failed_urls, time_stamp, args):
+    """Write out the URLs for which a connection to CAZy failed.
+    :param failed_urls: list, contains the URL and reason for the failed scrape
+    :param args: cmd args parser
+    Return nothing.
+    """
+    logger = logging.getLogger(__name__)
+
+    if args.output is not sys.stdout:
+        output_path = args.output / f"failed_cazy_scrapes_{time_stamp}.txt"
+
+        with open(output_path, "a") as fh:
+            for url in failed_urls:
+                fh.write(f"{url}\n")
+
+    else:
+        logger.error("The following items were not scraped:")
+        for url in failed_urls:
+            logger.error(url)
+
+    return
+
+
+def write_out_failed_proteins(sql_failures, time_stamp, args):
+    """Write out the names of proteins which raised errors when being added to the local db.
+    :param sql_failures: list, the names of proteins that were unsuccessfully added to the db
+    :param args: cmd args parser
+    Return nothing.
+    """
+    logger = logging.getLogger(__name__)
+
+    if args.output is not sys.stdout:
+        output_path = args.output / f"failed_db_protein_additions_{time_stamp}.txt"
+
+        with open(output_path, "a") as fh:
+            for fail in sql_failures:
+                fh.write(f"{fail}\n")
+
+    else:
+        logger.error("The following proteins were not entered into database:")
+        for fail in sql_failures:
+            logger.error(fail)
+
+    return
+
+
+def write_out_fasta(record, genbank_accession, args):
+    """Write out GenBank protein record to a FASTA file.
+
+    :param record: SeqIO parsed record
+    :param genbank_accession: str, accession number of the protein sequence in NCBI.GenBank
+    :param args: cmd-line arguments parser
+
+    Return nothing.
+    """
+    fasta_name = f"{genbank_accession}.fasta"
+    fasta_name = args.write / fasta_name
+
+    with open(fasta_name, "w") as fh:
+        SeqIO.write(record, fh, "fasta")
+
+    return
diff --git a/scraper/file_io/__init__.py b/scraper/utilities/parse_configuration/__init__.py
similarity index 65%
rename from scraper/file_io/__init__.py
rename to scraper/utilities/parse_configuration/__init__.py
index 5142d158..28959690 100644
--- a/scraper/file_io/__init__.py
+++ b/scraper/utilities/parse_configuration/__init__.py
@@ -1,5 +1,7 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
 # Author:
 # Emma E. M. Hobbs
 
@@ -16,57 +18,37 @@
 # UK
 
 # The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
 """Module for handling input and output files and directories."""
 
+
 import json
+import logging
 import re
-import shutil
 import sys
 import yaml
 
 from pathlib import Path
 
 
-def make_output_directory(output, logger, force, nodelete):
-    """Create output directory for genomic files.
-
-    :param output: path, path of dir to be created
-    :param logger: logger object
-    :param force: bool, enable/disable creating dir if already exists
-    :param nodelete: bool, enable/disable deleting content in existing dir
-
-    Raises FileExistsError if an attempt is made to create a directory that already
-    exist and force (force overwrite) is False.
-
-    Return Nothing
-    """
-    if force is True:
-        logger.warning(
-            "Output directory %s exists, nodelete is %s", output, nodelete,
-        )
-
-        if nodelete and output.exists():
-            logger.warning("Not deleting directory %s", output)
-
-        elif output.exists():
-            logger.warning("Deleting directory %s", output)
-            shutil.rmtree(output)
-
-    logger.info("Creating directory %s", output)
-    try:
-        output.mkdir(exist_ok=force)
-    except FileExistsError:
-        logger.warning(
-            (
-                "Out directory already exists."
-                "New directory not made, writing to existing directory."
-            )
-        )
-
-    return
-
-
-def parse_configuration(file_io_path, args, logger):
+def parse_configuration(file_io_path, args):
     """Parse configuration data, and retrieve user specified CAZy classes and families.
 
     If no user defined configuration is given the default behaviour to scrape the entirity of CAZy
@@ -74,12 +56,33 @@ def parse_configuration(file_io_path, args, logger):
 
     :param file_io_path: str, path to directory where file_io is installed
     :param args: parser arguments
-    :param logger: logger object
 
-    Return list of classes not to scrape, dict of families to scrape, and dict of class synonoms.
+    Return list of classes not to scrape, dict of families to scrape, dict of class synonoms,
+    a dict of taxonomy filters (genera, species and strains) to restrict the scrape to, list of
+    kingdoms to be scraped.
     """
+    logger = logging.getLogger(__name__)
+    # open config dict
+    raw_config_dict = None
+    if args.config is not None:
+        try:
+            with open(args.config, "r") as fh:
+                raw_config_dict = yaml.full_load(fh)
+        except FileNotFoundError:
+            logger.error(
+                "Did not find the configuration file. Check the path is correct.\n"
+                "Terminating programme"
+            )
+            sys.exit(1)
+
+    # retrieve taxonomy filters
+    taxonomy_filter = get_genera_species_strains(args, raw_config_dict)
+
+    # retrieve Kingdoms to scrape
+    kingdoms = get_kingdoms(args, raw_config_dict)
+
     # Get dictionary of accepted CAZy class synonyms
-    cazy_dict, std_class_names = get_cazy_dict_std_names(file_io_path, logger)
+    cazy_dict, std_class_names = get_cazy_dict_std_names(file_io_path)
 
     # Retrieve user specified CAZy classes and families to be scraped at CAZy
 
@@ -97,20 +100,20 @@ def parse_configuration(file_io_path, args, logger):
     # user passed a YAML configuration file
     if args.config is not None:
         # add configuration data from YAML file yo configuration dictionary
-        config_dict = get_yaml_configuration(config_dict, cazy_dict, std_class_names, args, logger)
+        config_dict = get_yaml_configuration(config_dict, cazy_dict, std_class_names, args)
 
         if (args.classes is None) and (args.families is None):  # no cmd-line configuration
             # get list of CAZy classes not to scrape
-            excluded_classes = get_excluded_classes(std_class_names, config_dict, cazy_dict, logger)
+            excluded_classes = get_excluded_classes(std_class_names, config_dict, cazy_dict)
 
             # convert empty lists to None type objects
-            config_dict = convert_lists_to_none(config_dict, logger)
+            config_dict = convert_lists_to_none(config_dict)
 
-            return excluded_classes, config_dict, cazy_dict
+            return excluded_classes, config_dict, cazy_dict, taxonomy_filter, kingdoms
 
         else:  # get cmd defined configuration
-            cmd_config = get_cmd_defined_fams_classes(cazy_dict, std_class_names, args, logger)
-            cmd_config = convert_lists_to_none(cmd_config, logger)
+            cmd_config = get_cmd_defined_fams_classes(cazy_dict, std_class_names, args)
+            cmd_config = convert_lists_to_none(cmd_config)
 
             # add cmd defined configuration to config_dict
             # add items from file_config to cmd_config
@@ -121,38 +124,126 @@ def parse_configuration(file_io_path, args, logger):
                             config_dict[key].append(item)
 
             # get list of CAZy classes that will not be scraped
-            excluded_classes = get_excluded_classes(std_class_names, config_dict, cazy_dict, logger)
+            excluded_classes = get_excluded_classes(std_class_names, config_dict, cazy_dict)
 
             # convert empty lists to None type objects
-            config_dict = convert_lists_to_none(config_dict, logger)
+            config_dict = convert_lists_to_none(config_dict)
 
-            return excluded_classes, config_dict, cazy_dict
+            return excluded_classes, config_dict, cazy_dict, taxonomy_filter, kingdoms
 
     else:  # user did not pass config file
         if (args.classes is None) and (args.families is None):
             # No specific families or classes specified for scraping
-            return None, None, cazy_dict
+            return None, None, cazy_dict, taxonomy_filter, kingdoms
 
         else:  # configuration specified only via the cmd_line
-            config_dict = get_cmd_defined_fams_classes(cazy_dict, std_class_names, args, logger)
+            config_dict = get_cmd_defined_fams_classes(cazy_dict, std_class_names, args)
 
             # get list of CAZy classes that will not be scraped
-            excluded_classes = get_excluded_classes(std_class_names, config_dict, cazy_dict, logger)
+            excluded_classes = get_excluded_classes(std_class_names, config_dict, cazy_dict)
 
             # convert empty lists to None type objects
-            config_dict = convert_lists_to_none(config_dict, logger)
+            config_dict = convert_lists_to_none(config_dict)
+
+            return excluded_classes, config_dict, cazy_dict, taxonomy_filter, kingdoms
+
+
+def get_genera_species_strains(args, raw_config_dict):
+    """Retrieve Genera, Species and Strains to retrict the scrape to.
+
+    :param args: cmd-line arguments parser
+    :param raw_config_dict: dictionary of content from YAML config file
+
+    Return set contain user specificed genera, species and strains.
+    """
+    taxonomy_filter = {"genera": [], "species": [], "strains": []}
+
+    if raw_config_dict is not None:
+        for key in ["genera", "species", "strain"]:
+            try:
+                if raw_config_dict[key] is not None:
+                    taxonomy_filter[key] = raw_config_dict[key]
+            except KeyError:
+                pass
+
+    if args.genera is not None:
+        taxonomy_filter["genera"] += (args.genera).split(",")
+
+    if args.species is not None:
+        taxonomy_filter["species"] += (args.species).split(",")
 
-            return excluded_classes, config_dict, cazy_dict
+    if args.strains is not None:
+        taxonomy_filter["strains"] += (args.strains).split(",")
 
+    taxonomy_filter = convert_lists_to_none(taxonomy_filter)
 
-def get_cazy_dict_std_names(file_io_path, logger):
+    return taxonomy_filter
+
+
+def get_kingdoms(args, raw_config_dict):
+    """Retrieve list of Kingdoms to scrape CAZymes from.
+
+    :param args: cmd args parser
+    :param raw_config_dict: dictionary of content from YAML config file
+
+    Return list of Kingdoms to  be scrapped.
+    """
+    logger = logging.getLogger(__name__)
+
+    kingdoms = []
+
+    if raw_config_dict is not None:
+        try:
+            if raw_config_dict["kingdom"] is not None:
+                kingdoms += raw_config_dict["kingdom"]
+                yaml_kingdoms = True
+            else:
+                yaml_kingdoms = False
+        except KeyError:
+            yaml_kingdoms = False
+    else:
+        yaml_kingdoms = False
+
+    if args.kingdoms is not None:
+        kingdoms += (args.kingdoms).split(",")
+
+    kingdoms = [kingdom.lower() for kingdom in kingdoms]
+    kingdoms = list(set(kingdoms))
+    cazy_kingdoms = ['archaea', 'bacteria', 'eukaryota', 'viruses', 'unclassified']
+    for kd in kingdoms:
+        if kd not in cazy_kingdoms:
+            logger.warning(
+                f"'{kd}' written in configuration, but it not a CAZy listed taxonomy Kingdom.\n"
+                f"CAZymes will not be scrapped from the user listed kingdom: {kd}"
+            )
+            kingdoms.remove(kd)
+
+    if (len(kingdoms) == 0):
+        if (args.kingdoms is not None) or (yaml_kingdoms is True):
+            # user had specified Kingdoms to be scraped
+            logger.warning(
+                "None of the Kingdoms listed match the Kingdoms listed in CAZy.\n"
+                "The classes in CAZy are: archaea, bacteria, eukaryota, viruses, and unclassified\n"
+                "Terminating programme"
+            )
+            sys.exit(1)
+
+        else:
+            # user did not specify any Kingdoms
+            kingdoms = 'all'  # scrape CAZymes from all Kingdoms
+
+    return kingdoms
+
+
+def get_cazy_dict_std_names(file_io_path):
     """Retrieve dictionary of acccepted CAZy class synonym names, and list of offical class.
 
     :param args: cmd args parser
-    :param logger: logger object
 
     Return dictionary.
     """
+    logger = logging.getLogger(__name__)
+
     # build path to the JSON file containing the cazy dict
     dict_path = file_io_path.replace("__init__.py", "cazy_dictionary.json")
     dict_path = Path(dict_path)
@@ -172,15 +263,16 @@ def get_cazy_dict_std_names(file_io_path, logger):
     return cazy_dict, std_class_names
 
 
-def get_yaml_configuration(config_dict, cazy_dict, std_class_names, args, logger):
+def get_yaml_configuration(config_dict, cazy_dict, std_class_names, args):
     """Parse data from configuration YAML file.
 
     :param config_dict: dict, store CAZy classes and families to scrape
     :param args: cmd args parser
-    :param logger: logger object
 
     Return dictionary containing CAZy classes and families named in YAML configuration file.
     """
+    logger = logging.getLogger(__name__)
+
     # open configuration file
     try:
         with open(args.config) as fh:
@@ -199,11 +291,10 @@ def get_yaml_configuration(config_dict, cazy_dict, std_class_names, args, logger
         yaml_config_dict,
         cazy_dict,
         std_class_names,
-        logger,
     )
 
     for key in yaml_config_dict:
-        if key != "classes":
+        if (key != "classes") and (key != "genera") and (key != "species") and (key != "strains"):
             if yaml_config_dict[key] is not None:
                 for item in yaml_config_dict[key]:
                     if item not in config_dict[key]:  # do not add duplicates
@@ -212,15 +303,16 @@ def get_yaml_configuration(config_dict, cazy_dict, std_class_names, args, logger
     return config_dict
 
 
-def get_yaml_cazy_classes(yaml_config_dict, cazy_dict, std_class_names, logger):
+def get_yaml_cazy_classes(yaml_config_dict, cazy_dict, std_class_names):
     """Retrieve list of CAZy classes listed in the YAML file, in their standardised CAZy name.
 
     :param config_dict: dictionary of YAML content
     :param cazy_dict: dictionary of accepted CAZy class name synonyms
-    :param logger: logger object
 
     Return list of CAZy classes specified by user to be scraped.
     """
+    logger = logging.getLogger(__name__)
+
     try:
         cazy_classes = yaml_config_dict["classes"]
     except (KeyError, TypeError) as e:
@@ -238,21 +330,21 @@ def get_yaml_cazy_classes(yaml_config_dict, cazy_dict, std_class_names, logger):
 
     if len(cazy_classes) != 0:
         # standardise CAZy class names
-        cazy_classes = parse_user_cazy_classes(cazy_classes, cazy_dict, std_class_names, logger)
+        cazy_classes = parse_user_cazy_classes(cazy_classes, cazy_dict, std_class_names)
 
     return cazy_classes
 
 
-def parse_user_cazy_classes(cazy_classes, cazy_dict, std_class_names, logger):
+def parse_user_cazy_classes(cazy_classes, cazy_dict, std_class_names):
     """Standardise the CAZy class names listed in configuration file.
 
     :param cazy_classes: list, list of CAZy classes from configuration file
     :param cazy_dict: dict, keyed by class name, keyed by list of accepted synonoms
     :param std_class_names: list, list of all CAZy classes
-    :param logger: logger object
 
     Return list of CAZy classes listed by user in the configuration file.
     """
+    logger = logging.getLogger(__name__)
     logger.info("Standardising names of class listed in configuration file")
 
     index = 0
@@ -277,16 +369,17 @@ def parse_user_cazy_classes(cazy_classes, cazy_dict, std_class_names, logger):
     return cazy_classes
 
 
-def get_cmd_defined_fams_classes(cazy_dict, std_class_names, args, logger):
+def get_cmd_defined_fams_classes(cazy_dict, std_class_names, args):
     """Retrieve classes and families specified for scraping from the cmd-line args.
 
     :param cazy_dict: dict, accepted synonyms of CAZy class names
     :param std_class_names: list, standardised CAZy class names
     :param args: cmd args parser
-    :param logger: logger object
 
     Return dictionary of CAZy classes and families to be scraped.
     """
+    logger = logging.getLogger(__name__)
+
     # create dictionary which will store families and classes to be scraped
     config_dict = {
         'classes': [],
@@ -303,7 +396,7 @@ def get_cmd_defined_fams_classes(cazy_dict, std_class_names, args, logger):
     if cazy_classes is not None:
         cazy_classes = cazy_classes.strip().split(",")
         # Standardise CAZy class names
-        cazy_classes = parse_user_cazy_classes(cazy_classes, cazy_dict, std_class_names, logger)
+        cazy_classes = parse_user_cazy_classes(cazy_classes, cazy_dict, std_class_names)
         config_dict["classes"] = cazy_classes
 
     families = args.families
@@ -352,7 +445,7 @@ def get_cmd_defined_fams_classes(cazy_dict, std_class_names, args, logger):
     return config_dict
 
 
-def get_excluded_classes(std_class_names, config_dict, cazy_dict, logger):
+def get_excluded_classes(std_class_names, config_dict, cazy_dict):
     """Define the CAZy classes that will not be scraped.
 
     This includes classes for which not Families have been specified for scraping.
@@ -360,7 +453,6 @@ def get_excluded_classes(std_class_names, config_dict, cazy_dict, logger):
     :param std_class_names: list of standardised CAZy class names
     :param config_dict: configuration dict defining classes and families to be scraped
     :param cazy_dict: dict, accepted CAZy classes synonyms
-    :param logger: logger object
 
     Return list of CAZy classes not to be scraped.
     """
@@ -388,11 +480,10 @@ def get_excluded_classes(std_class_names, config_dict, cazy_dict, logger):
     return excluded_classes
 
 
-def convert_lists_to_none(config_dict, logger):
+def convert_lists_to_none(config_dict):
     """Convert empty lists to None type objects in configuration dictionary.
 
     :param config_dict: dict, CAZy classes and families to be scraped
-    :param logger: logger object
 
     Return dictionary with no empty lists.
     """
@@ -404,52 +495,16 @@ def convert_lists_to_none(config_dict, logger):
     return config_dict
 
 
-def write_out_df(dataframe, df_name, outdir, logger, force):
-    """Write out dataframe to output directory.
-
-    :param dataframe: pandas dataframe
-    :param df_name: str, name of dataframe
-    :param outdir: Path, path to output directory
-    :param logger: logger object
-    :param force: bool, enable/disable over writing of existing file
-
-    Return nothing.
-    """
-    # build output path
-    output_path = outdir / f"{df_name}.csv"
-
-    logger.info("Checking if output directory for dataframe already exists")
-    if output_path.exists():
-        if force is False:
-            logger.warning(
-                (
-                    "Specified directory for dataframe already exists.\n"
-                    "Exiting writing out dataframe."
-                )
-            )
-            return ()
-        else:
-            logger.warning(
-                (
-                    "Specified directory for dataframe already exists.\n"
-                    "Forced overwritting enabled."
-                )
-            )
-
-    logger.info("Writing out species dataframe to directory")
-    dataframe.to_csv(output_path)
-    return
-
-
-def write_out_failed_scrapes(failed_urls, time_stamp, args, logger):
+def write_out_failed_scrapes(failed_urls, time_stamp, args):
     """Write out the URLs for which a connection to CAZy failed.
 
     :param failed_urls: list, contains the URL and reason for the failed scrape
     :param args: cmd args parser
-    :param logger: logger object
 
     Return nothing.
     """
+    logger = logging.getLogger(__name__)
+
     if args.output is not sys.stdout:
         output_path = args.output / f"failed_cazy_scrapes_{time_stamp}.txt"
 
@@ -465,15 +520,16 @@ def write_out_failed_scrapes(failed_urls, time_stamp, args, logger):
     return
 
 
-def write_out_failed_proteins(sql_failures, time_stamp, args, logger):
+def write_out_failed_proteins(sql_failures, time_stamp, args):
     """Write out the names of proteins which raised errors when being added to the local db.
 
     :param sql_failures: list, the names of proteins that were unsuccessfully added to the db
     :param args: cmd args parser
-    :param logger: logger object
 
     Return nothing.
     """
+    logger = logging.getLogger(__name__)
+
     if args.output is not sys.stdout:
         output_path = args.output / f"failed_db_protein_additions_{time_stamp}.txt"
 
@@ -487,3 +543,37 @@ def write_out_failed_proteins(sql_failures, time_stamp, args, logger):
             logger.error(fail)
 
     return
+
+
+def get_configuration(file_io_path, args):
+    """Get configuration for the Expand module.
+
+    :param file_io_path: Path to file_io module
+    :param args: cmd-line argument parser
+
+    Return configuration dictionary and set of taxonomy filters.
+    """
+    # retrieve inital parsing of configuration data
+    excluded_classes, config_dict, cazy_dict, taxonomy_filters_dict = parse_configuration(
+        file_io_path,
+        args,
+    )
+
+    # excluded_classes and cazy_dict are used in the crawler module but are not needed for the
+    # the expand module
+    taxonomy_filters = []
+
+    for key in taxonomy_filters_dict:
+        try:
+            if len(taxonomy_filters_dict[key]) != 0:
+                taxonomy_filters += taxonomy_filters_dict[key]
+        except (TypeError, KeyError) as e:
+            pass
+
+    if len(taxonomy_filters) == 0:
+        taxonomy_filters = None
+
+    else:
+        taxonomy_filters = set(taxonomy_filters)
+
+    return config_dict, taxonomy_filters
diff --git a/scraper/file_io/cazy_dictionary.json b/scraper/utilities/parse_configuration/cazy_dictionary.json
similarity index 100%
rename from scraper/file_io/cazy_dictionary.json
rename to scraper/utilities/parse_configuration/cazy_dictionary.json
diff --git a/scraper/utilities/parsers/__init__.py b/scraper/utilities/parsers/__init__.py
new file mode 100644
index 00000000..0d015b0d
--- /dev/null
+++ b/scraper/utilities/parsers/__init__.py
@@ -0,0 +1,463 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
+# Author:
+# Emma E. M. Hobbs
+
+# Contact
+# eemh1@st-andrews.ac.uk
+
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+
+# The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+"""Submodule for building cmd-line parsers"""
+
+
+import argparse
+import sys
+
+from pathlib import Path
+from typing import List, Optional
+
+
+def build_parser(argv: Optional[List] = None):
+    """Return ArgumentParser parser for script."""
+    # Create parser object
+    parser = argparse.ArgumentParser(
+        prog="cazy_webscraper.py",
+        description="Scrapes the CAZy database",
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+    )
+
+    # Add optional arguments to parser
+
+    # Add option to specify path to configuration file
+    parser.add_argument(
+        "-c",
+        "--config",
+        type=Path,
+        metavar="config file",
+        default=None,
+        help="Path to configuration file. Default: None, scrapes entire database",
+    )
+
+    # Add option to define complete classes to scrape
+    parser.add_argument(
+        "--classes",
+        type=str,
+        default=None,
+        help="Classes from which all families are to be scraped. Separate classes by ','"
+    )
+
+    # Add option to provide a path to an existing SQL database to add newly scraped data to
+    parser.add_argument(
+        "-d",
+        "--database",
+        type=Path,
+        metavar="local database path",
+        default=None,
+        help="path to an existing local CAZy SQL database",
+    )
+
+    # Add option to force file over writting
+    parser.add_argument(
+        "-f",
+        "--force",
+        dest="force",
+        action="store_true",
+        default=False,
+        help="Force file over writting",
+    )
+
+    # Add option to restrict scrape to specific genera
+    parser.add_argument(
+        "--genera",
+        type=str,
+        default=None,
+        help="Genera to restrict the scrape to"
+    )
+
+    # Add option to specify families to scrape
+    parser.add_argument(
+        "--families",
+        type=str,
+        default=None,
+        help="Families to scrape. Separate families by commas 'GH1,GH2' (case sensitive)"
+    )
+
+    # Add option to restrict the scrape to specific kingdoms
+    parser.add_argument(
+        "--kingdoms",
+        type=str,
+        default=None,
+        help=(
+            "Kingdoms to scrape. Separate by a single comma.\n"
+            "Options= archaea, bacteria, eukaryota, viruses, unclassified (not case sensitive)"
+        ),
+    )
+
+    # Add log file name option
+    # If not given, no log file will be written out
+    parser.add_argument(
+        "-l",
+        "--log",
+        type=Path,
+        metavar="log file name",
+        default=None,
+        help="Defines log file name and/or path",
+    )
+
+    # Add option to prevent over writing of existing files
+    # and cause addition of files to output directory
+    parser.add_argument(
+        "-n",
+        "--nodelete",
+        dest="nodelete",
+        action="store_true",
+        default=False,
+        help="enable/disable deletion of exisiting files",
+    )
+
+    # Add option to specify output directory to write output dataframes to
+    parser.add_argument(
+        "-o",
+        "--output",
+        type=Path,
+        metavar="output file name",
+        default=sys.stdout,
+        help="Output filename",
+    )
+
+    # Add option to enable number of times to retry scraping
+    parser.add_argument(
+        "-r",
+        "--retries",
+        type=int,
+        default=10,
+        help="Number of times to retry scraping a family or class page if error encountered",
+    )
+
+    # Add option to enable retrieval of subfamilies
+    parser.add_argument(
+        "-s",
+        "--subfamilies",
+        dest="subfamilies",
+        action="store_true",
+        default=False,
+        help="Enable retrieval of subfamilies from CAZy",
+    )
+
+    # Add option to restrict the scrape to specific species. This will scrape CAZymes from
+    # all strains belonging to each listed species
+    parser.add_argument(
+        "--species",
+        type=str,
+        default=None,
+        help="Species (written as Genus Species) to restrict the scrape to"
+    )
+
+    # Add option to restrict scraping to specific strains of organisms
+    parser.add_argument(
+        "--strains",
+        type=str,
+        default=None,
+        help=(
+            "Specific strains of organisms to restrict the scrape to "
+            "(written as Genus Species Strain)"
+        ),
+    )
+
+    # Add option to define time out limit for trying to connect to CAZy
+    parser.add_argument(
+        "-t",
+        "--timeout",
+        type=int,
+        default=45,
+        help="Connection timeout limit (seconds)"
+    )
+
+    # Add option for more detail (verbose) logging
+    parser.add_argument(
+        "-v",
+        "--verbose",
+        dest="verbose",
+        action="store_true",
+        default=False,
+        help="Set logger level to 'INFO'",
+    )
+
+    if argv is None:
+        # parse command-line
+        return parser
+    else:
+        # return namespace
+        return parser.parse_args(argv)
+
+
+def build_genbank_sequences_parser(argv: Optional[List] = None):
+    """Return ArgumentParser parser for the script 'expand.genbank_sequences.py'."""
+    # Create parser object
+    parser = argparse.ArgumentParser(
+        prog="genbank_sequences.py",
+        description="Populates local CAZy database with protein sequences from GenBank",
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+    )
+
+    # Add positional/required arguments
+    parser.add_argument(
+        "database",
+        type=Path,
+        metavar="local CAZy database",
+        help="Path to local CAZy database",
+    )
+
+    parser.add_argument(
+        "email",
+        type=str,
+        metavar="user email address",
+        help="User email address, requirement of NCBI-Entrez",
+    )
+
+    # Add optional arguments to parser
+
+    # Add option to specify path to configuration file
+    parser.add_argument(
+        "-c",
+        "--config",
+        type=Path,
+        metavar="config file",
+        default=None,
+        help="Path to configuration file. Default: None, scrapes entire database",
+    )
+
+    # Add option to define classes to retrieve protein sequences for
+    parser.add_argument(
+        "--classes",
+        type=str,
+        default=None,
+        help="Classes from which all families are to be scraped. Separate classes by ','"
+    )
+
+    # specify the number of accessions posted in single ePost to NCBI
+    parser.add_argument(
+        "-e",
+        "--epost",
+        type=int,
+        default=150,
+        help="Number of accessions posted to NCBI per epost, advice to be max 200. Default=150"
+    )
+
+    # Add option to specify families to retrieve protein sequences for
+    parser.add_argument(
+        "--families",
+        type=str,
+        default=None,
+        help="Families to scrape. Separate families by commas 'GH1,GH2'"
+    )
+
+    # Add log file name option
+    # If not given, no log file will be written out
+    parser.add_argument(
+        "-l",
+        "--log",
+        type=Path,
+        metavar="log file name",
+        default=None,
+        help="Defines log file name and/or path",
+    )
+
+    # enable retrieving protein sequences for only primary GenBank accessions
+    parser.add_argument(
+        "-p",
+        "--primary",
+        dest="primary",
+        action="store_true",
+        default=False,
+        help="Enable retrieveing protein sequences for only primary GenBank accessions",
+    )
+
+    # Add option to update sequences if the retrieved sequence is different
+    # If not enabled then sequences will only be retrieved and added for proteins that do not
+    # already have a protein sequence
+    parser.add_argument(
+        "-u",
+        "--update",
+        dest="update",
+        action="store_true",
+        default=False,
+        help="Enable overwriting sequences in the database if the retrieved sequence is different",
+    )
+
+    # Add option to specify output directory to write output dataframes to
+    parser.add_argument(
+        "-w",
+        "--write",
+        type=Path,
+        metavar="path to FASTA file dire",
+        default=None,
+        help="Enable writing out protein sequences to a FASTA file",
+    )
+
+    # Add option for more detail (verbose) logging
+    parser.add_argument(
+        "-v",
+        "--verbose",
+        dest="verbose",
+        action="store_true",
+        default=False,
+        help="Set logger level to 'INFO'",
+    )
+
+    if argv is None:
+        # parse command-line
+        return parser
+    else:
+        # return namespace
+        return parser.parse_args(argv)
+
+
+def build_pdb_structures_parser(argv: Optional[List] = None):
+    """Return ArgumentParser parser for the script 'expand.genbank_sequences.py'."""
+    # Create parser object
+    parser = argparse.ArgumentParser(
+        prog="pdb_structures.py",
+        description="Download structures from PDB",
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+    )
+
+    # Add positional/required arguments
+    parser.add_argument(
+        "database",
+        type=Path,
+        metavar="local CAZy database",
+        help="Path to local CAZy database",
+    )
+
+    parser.add_argument(
+        "pdb",
+        choices=["mmCif", "pdb", "xml", "mmtf", "bundle"],
+        type=str,
+        help="File format of downloaded structure from PDB",
+    )
+
+    # Add optional arguments to parser
+
+    # Add option to specify path to configuration file
+    parser.add_argument(
+        "-c",
+        "--config",
+        type=Path,
+        metavar="config file",
+        default=None,
+        help="Path to configuration file. Default: None, scrapes entire database",
+    )
+
+    # Add option to define classes to retrieve protein sequences for
+    parser.add_argument(
+        "--classes",
+        type=str,
+        default=None,
+        help="Classes from which all families are to be scraped. Separate classes by ','"
+    )
+
+    # Add option to specify families to retrieve protein sequences for
+    parser.add_argument(
+        "--families",
+        type=str,
+        default=None,
+        help="Families to scrape. Separate families by commas 'GH1,GH2'"
+    )
+
+    # enable force writing in an existing directory
+    parser.add_argument(
+        "-f"
+        "--force",
+        dest="force",
+        action="store_true",
+        default=False,
+        help="Force file over writting",
+    )
+
+    # Add log file name option
+    # If not given, no log file will be written out
+    parser.add_argument(
+        "-l",
+        "--log",
+        type=Path,
+        metavar="log file name",
+        default=None,
+        help="Defines log file name and/or path",
+    )
+
+    # Add option to prevent over writing of existing files
+    # and cause addition of files to output directory
+    parser.add_argument(
+        "-n",
+        "--nodelete",
+        dest="nodelete",
+        action="store_true",
+        default=False,
+        help="enable/disable deletion of exisiting files",
+    )
+
+    # enable specifying an output directory
+    parser.add_argument(
+        "-o",
+        "--outdir",
+        type=Path,
+        metavar="output directory path",
+        help="Path to output directory to which downloaded structures are retrieved",
+    )
+
+    # enable retrieving protein sequences for only primary GenBank accessions
+    parser.add_argument(
+        "-p",
+        "--primary",
+        dest="primary",
+        action="store_true",
+        default=False,
+        help="Enable retrieveing protein structures for only primary GenBank accessions",
+    )
+
+    # Add option for more detail (verbose) logging
+    parser.add_argument(
+        "-v",
+        "--verbose",
+        dest="verbose",
+        action="store_true",
+        default=False,
+        help="Set logger level to 'INFO'",
+    )
+
+    if argv is None:
+        # parse command-line
+        return parser
+    else:
+        # return namespace
+        return parser.parse_args(argv)
diff --git a/setup.py b/setup.py
index a6c233e0..ee0a0611 100644
--- a/setup.py
+++ b/setup.py
@@ -49,7 +49,13 @@
     keywords="bioinforamtics protein webscraper",
     platforms="Posix, MacOS X",
     url="https://github.com/HobnobMancer/cazy_webscraper",
-    entry_points={"console_scripts": ["cazy_webscraper.py = scraper.cazy_webscraper:main"]},
+    entry_points={
+        "console_scripts": [
+            "cazy_webscraper.py = scraper.cazy_webscraper:main",
+            "genbank_sequences.py = scraper.expand.genbank_sequences:main",
+            "pdb_structures.py = scraper.expand.pdb_structures:main",
+        ]
+    },
     install_requires=[
         "biopython>=1.76",
         "mechanicalsoup",


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index a7b61a04..45992af3 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -20,13 +20,22 @@
 Contains fixtures used by multiple test files.
 """
 
+
 import logging
+import json
 
 from datetime import datetime
 from pathlib import Path
 
 import pytest
 
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy.orm import Session
+from sqlalchemy import create_engine
+
+
+Base = declarative_base()
+
 
 @pytest.fixture
 def test_dir():
@@ -54,10 +63,46 @@ def cazy_home_url():
 @pytest.fixture
 def cazy_dictionary(test_input_dir):
     dict_path = test_input_dir / "cazy_dictionary.json"
-    return dict_path
+    with open(dict_path, "r") as fh:
+        cazy_dict = json.load(fh)
+    return cazy_dict
 
 
 @pytest.fixture
 def time_stamp():
     time_stamp = datetime.now().strftime("%Y-%m-%d--%H-%M-%S")  # used in naming files
     return time_stamp
+
+
+# Define fixtures for testing SQL ORM and interface
+
+
+@pytest.fixture(scope="session")
+def engine():
+    db_path = "tests/test_inputs/test_inputs_sql/unit_test_db_2021-03-01--15-06-59.db"
+    return create_engine(f"sqlite+pysqlite:///{db_path}", echo=False)
+
+
+@pytest.fixture(scope="session")
+def tables(engine):
+    Base.metadata.create_all(engine)
+    yield
+    Base.metadata.drop_all(engine)
+
+
+@pytest.fixture
+def db_session(engine, tables):
+    """Returns an sqlalchemy session, and after the test tears down everything properly."""
+    connection = engine.connect()
+    # begin the nested transaction
+    transaction = connection.begin()
+    # use the connection with the already started transaction
+    session = Session(bind=connection)
+
+    yield session
+
+    session.close()
+    # roll back the broader transaction
+    transaction.rollback()
+    # put back the connection to the connection pool
+    connection.close()
diff --git a/tests/test_crawler.py b/tests/test_crawler.py
index aca7e425..ae9fde94 100644
--- a/tests/test_crawler.py
+++ b/tests/test_crawler.py
@@ -26,13 +26,22 @@
 import types
 import pytest
 
-
 from argparse import Namespace
 from requests.exceptions import MissingSchema
 
 from bs4 import BeautifulSoup
 
 from scraper import crawler
+from scraper.sql import sql_interface
+
+
+@pytest.fixture
+def args():
+    args = {"args": Namespace(
+        retries=2,
+        timeout=45,
+    )}
+    return args
 
 
 @pytest.fixture
@@ -54,11 +63,24 @@ def cazy_home_no_spip(input_dir):
 
 
 @pytest.fixture
-def args_datasplit_family():
+def args_subfam_true():
     argsdict = {
         "args": Namespace(
-            data_split="family",
             subfamilies=True,
+            retries=2,
+            timeout=45,
+        )
+    }
+    return argsdict
+
+
+@pytest.fixture
+def args_subfam_false():
+    argsdict = {
+        "args": Namespace(
+            subfamilies=False,
+            retries=2,
+            timeout=45,
         )
     }
     return argsdict
@@ -70,6 +92,12 @@ def cazy_class_page(input_dir):
     return file_path
 
 
+@pytest.fixture
+def cazy_class_page_no_fams(input_dir):
+    file_path = input_dir / "cazy_classpage_no_fams.html"
+    return file_path
+
+
 @pytest.fixture
 def family_urls(input_dir):
     file_path = input_dir / "test_family_urls.txt"
@@ -117,22 +145,13 @@ def no_subfam_h3_element(input_dir):
 
 
 @pytest.fixture
-def protein_list():
-    return [
-        crawler.Protein("protein_name", "GH1", "1.2.3.4", "organism"),
-        crawler.Protein(
-            "protein",
-            "GH1",
-            "",
-            "organism",
-            {"GenBank": ["link1"], "UniProt": ["link2"], "PDB": ["link3"]},
-        ),
+def protein_gen():
+    result_list = [
+        {"url": None, "error": None, "sql": None},
+        {"url": "www.cazy.org/GH1.html", "error": "no internet connection", "sql": None},
+        {"url": None, "error": "sql error", "sql": "protein_name"},
     ]
-
-
-@pytest.fixture
-def protein_gen(protein_list):
-    return (_ for _ in protein_list)
+    return (_ for _ in result_list)
 
 
 @pytest.fixture
@@ -147,6 +166,12 @@ def gh147_page(input_dir):
     return file_path
 
 
+@pytest.fixture
+def pag_page(input_dir):
+    file_page = input_dir / "pagination_page.html"
+    return file_page
+
+
 @pytest.fixture
 def no_links_page(input_dir):
     file_path = input_dir / "cazy_no_links.html"
@@ -177,49 +202,53 @@ def protein_with_no_gb(input_dir):
     return file_path
 
 
-# test the classes Protein and Family
+@pytest.fixture
+def protein_with_no_uniprot_no_pdb(input_dir):
+    file_path = input_dir / "protein_no_uniprot_no_pdb.html"
+    return file_path
 
 
-def test_protein_get_protein_dict():
-    """Test the Protein class __str__ and __repr__."""
-    protein = crawler.Protein(
-        "protein_name",
-        "GH1",
-        ["1.2.3.4"],
-        "organism",
-        {"GenBank": ["link1", "linka", "linkb"], "UniProt": ["link2"], "PDB/3D": ["link3"]},
-    )
+@pytest.fixture
+def test_fam():
+    test_fam = crawler.Family("GH3", "Glycoside Hydrolases (GHs)", "http://www.cazy.org/GH1.html")
+    return test_fam
 
-    protein_dict = protein.get_protein_dict()
 
-    expected_protein_dict = {
-        'Protein_name': ['protein_name'],
-        'CAZy_family': ['GH1'],
-        'EC#': ['1.2.3.4'],
-        'Source_organism': ['organism'],
-        'GenBank': ['link1,\nlinka,\nlinkb'],
-        'UniProt': ['link2'],
-        'PDB/3D': ['link3'],
-    }
+# test classes
 
-    assert expected_protein_dict == protein_dict
 
+def test_cazy_class():
+    """Test building a CAZy class instance."""
+    new_class = crawler.CazyClass("GH", "class_url", 0)
+    new_class_failed_families = crawler.CazyClass("GH", "class_url", 0, {"GH1": "GH1_url"})
 
-def test_family_get_name():
-    """Tests get family name for Family."""
-    family = crawler.Family("GH1", "Glycoside_Hydrolases(GH)")
+    assert new_class.name == "GH"
+    assert new_class_failed_families.name == "GH"
+    new_class
+    repr(new_class)
 
-    family_name = family.get_family_name()
 
-    exepected_name = "GH1"
+def test_family_get_name():
+    """Tests get family name for Family."""
+    fam_1 = crawler.Family("GH1", "Glycoside_Hydrolases(GH)", "class_url")
+    fam_2 = crawler.Family("GH2", "Glycoside_Hydrolases(GH)", "class_url", {"url":0})
 
-    assert exepected_name == family_name
+    assert "GH1" == fam_1.name
+    assert "GH2" == fam_2.name
+    fam_1
+    repr(fam_1)
 
 
 # test get_cazy_class_urls
 
 
-def test_get_class_urls_exclusions_none(cazy_home_url, cazy_home_page, null_logger, monkeypatch):
+def test_get_class_urls_exclusions_none(
+    cazy_home_url,
+    cazy_home_page,
+    cazy_dictionary,
+    monkeypatch,
+    args,
+):
     """Test get_cazy_class_urls when excluded_classess is None."""
     with open(cazy_home_page, "r") as fp:
         home_page = BeautifulSoup(fp, features="lxml")
@@ -229,24 +258,16 @@ def mock_get_home_page(*args, **kwargs):
 
     monkeypatch.setattr(crawler, "get_page", mock_get_home_page)
 
-    expected_result = [
-        'http://www.cazy.org/Glycoside-Hydrolases.html',
-        'http://www.cazy.org/GlycosylTransferases.html',
-        'http://www.cazy.org/Polysaccharide-Lyases.html',
-        'http://www.cazy.org/Carbohydrate-Esterases.html',
-        'http://www.cazy.org/Auxiliary-Activities.html',
-        'http://www.cazy.org/Carbohydrate-Binding-Modules.html',
-    ]
-
-    assert expected_result == crawler.get_cazy_class_urls(
+    result = crawler.get_cazy_classes(
         cazy_home_url,
         None,
-        1,
-        null_logger,
+        cazy_dictionary,
+        args["args"],
     )
+    assert len(result) == 6
 
 
-def test_get_class_urls_fail(cazy_home_url, null_logger, monkeypatch):
+def test_get_class_urls_fail(cazy_home_url, cazy_dictionary, monkeypatch, args):
     """Test get_cazy_class_urls home_page not returned"""
 
     def mock_get_home_page(*args, **kwargs):
@@ -255,15 +276,16 @@ def mock_get_home_page(*args, **kwargs):
     monkeypatch.setattr(crawler, "get_page", mock_get_home_page)
 
     with pytest.raises(SystemExit) as pytest_wrapped_e:
-        crawler.get_cazy_class_urls(cazy_home_url, None, 1, null_logger)
+        crawler.get_cazy_classes(cazy_home_url, None, cazy_dictionary, args["args"])
     assert pytest_wrapped_e.type == SystemExit
 
 
 def test_get_class_urls_exclusions_given(
     cazy_home_url,
     cazy_home_page,
-    null_logger,
     monkeypatch,
+    cazy_dictionary,
+    args,
 ):
     """Test get_cazy_class_urls when excluded_classess is not None."""
     with open(cazy_home_page) as fp:
@@ -276,27 +298,22 @@ def mock_get_home_page(*args, **kwargs):
 
     monkeypatch.setattr(crawler, "get_page", mock_get_home_page)
 
-    expected_result = [
-        'http://www.cazy.org/GlycosylTransferases.html',
-        'http://www.cazy.org/Polysaccharide-Lyases.html',
-        'http://www.cazy.org/Carbohydrate-Esterases.html',
-        'http://www.cazy.org/Auxiliary-Activities.html',
-        'http://www.cazy.org/Carbohydrate-Binding-Modules.html',
-    ]
-
-    assert expected_result == crawler.get_cazy_class_urls(
+    result = crawler.get_cazy_classes(
         cazy_home_url,
         exclusions,
-        1,
-        null_logger,
+        cazy_dictionary,
+        args["args"],
     )
 
+    assert len(result) == 5
+
 
 def test_get_class_urls_attribute(
     cazy_home_url,
     cazy_home_no_spip,
-    null_logger,
     monkeypatch,
+    cazy_dictionary,
+    args,
 ):
     """Test get_cazy_class_urls when attribute error is raised."""
     with open(cazy_home_no_spip) as fp:
@@ -309,18 +326,20 @@ def mock_get_home_page(*args, **kwargs):
 
     monkeypatch.setattr(crawler, "get_page", mock_get_home_page)
 
-    assert None is crawler.get_cazy_class_urls(
-        cazy_home_url,
-        exclusions,
-        1,
-        null_logger,
-    )
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        crawler.get_cazy_classes(
+            cazy_home_url,
+            exclusions,
+            cazy_dictionary,
+            args["args"],
+        )
+    assert pytest_wrapped_e.type == SystemExit
 
 
 # test get_cazy_family_urls
 
 
-def test_get_family_urls_fail(args_datasplit_family, null_logger, monkeypatch):
+def test_get_family_urls_fail(args_subfam_true, monkeypatch, cazy_home_url):
     """Test get_cazy_family_urls when no page is returned."""
 
     def mock_get_page(*args, **kwargs):
@@ -328,20 +347,18 @@ def mock_get_page(*args, **kwargs):
 
     monkeypatch.setattr(crawler, "get_page", mock_get_page)
 
-    assert None is crawler.get_cazy_family_urls(
+    assert crawler.get_cazy_family_urls(
         "class_url",
-        "cazy_home_url",
         "class_name",
-        args_datasplit_family["args"],
-        null_logger,
-    )
+        cazy_home_url,
+        args_subfam_true["args"],
+    ) == (None, 'error', None)
 
 
 def test_get_family_urls_success(
     cazy_class_page,
-    args_datasplit_family,
+    args_subfam_true,
     family_urls,
-    null_logger,
     monkeypatch,
 ):
     """Test get_cazy_family_urls when successful, and subfamilies is True."""
@@ -357,205 +374,473 @@ def mock_get_subfams(*args, **kwargs):
     monkeypatch.setattr(crawler, "get_page", mock_get_page)
     monkeypatch.setattr(crawler, "get_subfamily_links", mock_get_subfams)
 
-    assert family_urls == crawler.get_cazy_family_urls(
-        "class_url",
-        "http://www.cazy.org",
-        "class_name",
-        args_datasplit_family["args"],
-        null_logger,
+    crawler.get_cazy_family_urls(
+        "http://www.cazy.org/Glycoside-Hydrolases.html",
+        "Glycoside Hydrolases (GHs)",
+        "http://www.cazy.org/",
+        args_subfam_true["args"],
+    )
+
+
+def test_get_family_urls_no_urls_no_subfams(
+    cazy_class_page_no_fams,
+    args_subfam_false,
+    monkeypatch,
+):
+    """Test get_cazy_family_urls when no family URLs are retrieved and args.subfamilies is False."""
+    with open(cazy_class_page_no_fams) as fp:
+        page = BeautifulSoup(fp, features="lxml")
+
+    def mock_get_page(*args, **kwargs):
+        return [page, None]
+
+    monkeypatch.setattr(crawler, "get_page", mock_get_page)
+
+    crawler.get_cazy_family_urls(
+        "http://www.cazy.org/Glycoside-Hydrolases.html",
+        "Glycoside Hydrolases (GHs)",
+        "http://www.cazy.org/",
+        args_subfam_false["args"],
+    )
+
+
+def test_get_family_urls_no_urls_subfams(
+    cazy_class_page_no_fams,
+    args_subfam_true,
+    monkeypatch,
+):
+    """Test get_cazy_family_urls when no family URLs are retrieved and args.subfamilies is True."""
+    with open(cazy_class_page_no_fams) as fp:
+        page = BeautifulSoup(fp, features="lxml")
+
+    def mock_get_page(*args, **kwargs):
+        return [page, None]
+
+    def mock_subfamilies(*args, **kwargs):
+        return [
+            "http://www.cazy.org/GH5_1.html",
+            "http://www.cazy.org/GH5_2.html",
+            "http://www.cazy.org/GH5_3.html",
+        ]
+
+    monkeypatch.setattr(crawler, "get_page", mock_get_page)
+    monkeypatch.setattr(crawler, "get_subfamily_links", mock_subfamilies)
+
+    crawler.get_cazy_family_urls(
+        "http://www.cazy.org/Glycoside-Hydrolases.html",
+        "Glycoside Hydrolases (GHs)",
+        "http://www.cazy.org/",
+        args_subfam_true["args"],
+    )
+
+
+def test_get_family_urls_no_urls_subfams_none(
+    cazy_class_page_no_fams,
+    args_subfam_true,
+    monkeypatch,
+):
+    """Test get_cazy_family_urls when no family or subfamily URLs are retrieved."""
+    with open(cazy_class_page_no_fams) as fp:
+        page = BeautifulSoup(fp, features="lxml")
+
+    def mock_get_page(*args, **kwargs):
+        return [page, None]
+
+    def mock_subfamilies(*args, **kwargs):
+        return None
+
+    monkeypatch.setattr(crawler, "get_page", mock_get_page)
+    monkeypatch.setattr(crawler, "get_subfamily_links", mock_subfamilies)
+
+    crawler.get_cazy_family_urls(
+        "http://www.cazy.org/Glycoside-Hydrolases.html",
+        "Glycoside Hydrolases (GHs)",
+        "http://www.cazy.org/",
+        args_subfam_true["args"],
     )
 
 
 # test get_subfamily_links
 
 
-def test_get_subfam_links_len_0(family_h3_element, subfamily_urls, null_logger):
+def test_get_subfam_links_len_0(family_h3_element, subfamily_urls, ):
     """Test get_subfamily_links when no links are retrieved."""
 
     assert subfamily_urls == crawler.get_subfamily_links(
         family_h3_element,
         "http://www.cazy.org",
-        null_logger,
     )
 
 
-def test_get_subfam_links_urls(no_subfam_h3_element, null_logger):
+def test_get_subfam_links_urls(no_subfam_h3_element, ):
     """Test get_subfamily_links when urls are retrieved."""
 
     assert None is crawler.get_subfamily_links(
         no_subfam_h3_element,
         "http://www.cazy.org",
-        null_logger,
     )
 
 
 # test parse_family()
 
 
-def test_parse_family_fam_name(null_logger):
-    """Tests parse_family() when family name is incorrectly formated"""
+def test_parse_family_incorrect_url(args):
+    """Tests parse_family() when the first page URL is in the incorrect format."""
+
+    test_fam = crawler.Family(
+        "GHs3ad",
+        "Glycoside Hydrolases (GHs)",
+        "http://www.caaazy.org/GHaaaaaa1.html",
+    )
 
     crawler.parse_family(
-        "http://www.cazy.org/GH_test_1.html",
-        "GH_test_1",
-        "http://www.cazy.org",
-        null_logger,
+        test_fam,
+        "http://www.cazy.org/",
+        None,
+        ['bacteria'],
+        args['args'],
+        "sessions",
     )
 
 
-def test_parse_family_url(null_logger):
-    """Test parse_family() whwn the url is incorrectly formatted."""
+def test_parse_family_no_page(monkeypatch, args):
+    """Test parse_family() no page is returned."""
+
+    def mock_get_page(*args, **kwargs):
+        return None, "error_message"
+
+    monkeypatch.setattr(crawler, "get_page", mock_get_page)
+
+    test_fam = crawler.Family(
+        "GH3",
+        "Glycoside Hydrolases (GHs)",
+        "http://www.cazssssy.org/GH3.html",
+    )
 
     crawler.parse_family(
-        "http://www.cazy.org/GH_test_1.html",
-        "GH1",
-        "http://www.cazy.org",
-        null_logger,
+        test_fam,
+        "http://www.cazy.org/",
+        None,
+        ['bacteria'],
+        args['args'],
+        "sessions",
     )
 
 
-def test_parse_family_no_page(null_logger, monkeypatch):
-    """Tests parse_family() when no page retrieved for first paginiation page of proteins"""
+def test_parse_family_no_page_urls(monkeypatch, args):
+    """Tests parse_family() when protein page URLs are retrieved"""
 
     def mock_get_page(*args, **kwargs):
-        return [None, "error message"]
+        return "mock_page", None
+
+    def mock_page_urls(*args, **kwargs):
+        return [], 0
 
     monkeypatch.setattr(crawler, "get_page", mock_get_page)
+    monkeypatch.setattr(crawler, "get_tax_page_urls", mock_page_urls)
+
+    test_fam = crawler.Family("GH3", "Glycoside Hydrolases (GHs)", "http://www.cazy.org/GH1.html")
 
     crawler.parse_family(
-        "http://www.cazy.org/GH1.html",
-        "GH1",
+        test_fam,
         "http://www.cazy.org",
-        null_logger,
+        None,
+        ['bacteria'],
+        args['args'],
+        "session",
     )
 
 
-def test_parse_family_success(protein_gen, null_logger, monkeypatch):
+def test_parse_family_success(protein_gen, monkeypatch, args):
     """Test parse_family() when successful."""
 
     def mock_get_page(*args, **kwargs):
-        return ["first paginiation page", None]
+        return "mock_page", None
 
-    def mock_get_urls(*args, **kwargs):
-        return ["http://www.cazy.org/GH1_all.html"]
+    def mock_page_urls(*args, **kwargs):
+        return [], 0
 
     def mock_parse_proteins(*args, **kwargs):
-        return protein_gen
+        return [
+            {"url": None, "error": None, "sql": None},
+            {"url": None, "error": None, "sql": None},
+        ]
 
     monkeypatch.setattr(crawler, "get_page", mock_get_page)
-    monkeypatch.setattr(crawler, "get_protein_page_urls", mock_get_urls)
+    monkeypatch.setattr(crawler, "get_tax_page_urls", mock_page_urls)
     monkeypatch.setattr(crawler, "parse_proteins", mock_parse_proteins)
 
+    test_family = crawler.Family("GH1", "Glycoside Hydrolases (GH)", "www.cazy.org/GH1.html")
+
     crawler.parse_family(
+        test_family,
         "http://www.cazy.org/GH1.html",
+        None,
+        ['bacteria'],
+        args['args'],
+        "session",
+    )
+
+
+def test_parse_family_sql_url_errors(protein_gen, monkeypatch, args):
+    """Test parse_family() when URL and SQL errors are raised when parsing a protein."""
+
+    def mock_get_page(*args, **kwargs):
+        return "mock_page", None
+
+    def mock_page_urls(*args, **kwargs):
+        return [], 0
+
+    def mock_parse_proteins(*args, **kwargs):
+        return [
+            {"url": 'www.url_address', "error": 'error message', "sql": None},
+            {"url": None, "error": 'error message', "sql": 'protein and sql'},
+        ]
+
+    monkeypatch.setattr(crawler, "get_page", mock_get_page)
+    monkeypatch.setattr(crawler, "get_tax_page_urls", mock_page_urls)
+    monkeypatch.setattr(crawler, "parse_proteins", mock_parse_proteins)
+
+    test_family = crawler.Family("GH1", "Glycoside Hydrolases (GH)", "www.cazy.org/GH1.html")
+
+    crawler.parse_family(
+        test_family,
+        "http://www.cazy.org/GH1.html",
+        None,
+        ['bacteria'],
+        args['args'],
+        "session",
+    )
+
+
+def test_parse_family_previous_failed_pages(protein_gen, monkeypatch, args):
+    """Test parse_family() when the family has previously failed families."""
+
+    def mock_get_page(*args, **kwargs):
+        return "mock_page", None
+
+    def mock_page_urls(*args, **kwargs):
+        return [], 0
+
+    def mock_parse_proteins(*args, **kwargs):
+        return [
+            {"url": None, "error": None, "sql": None},
+            {"url": None, "error": None, "sql": None},
+        ]
+
+    monkeypatch.setattr(crawler, "get_page", mock_get_page)
+    monkeypatch.setattr(crawler, "get_tax_page_urls", mock_page_urls)
+    monkeypatch.setattr(crawler, "parse_proteins", mock_parse_proteins)
+
+    test_family = crawler.Family(
         "GH1",
-        "http://www.cazy.org",
-        null_logger,
+        "Glycoside Hydrolases (GH)",
+        "www.cazy.org/GH1.html",
+        {"pageURL1": 1, "pageURL2":2}
+    )
+
+    crawler.parse_family(
+        test_family,
+        "http://www.cazy.org/GH1.html",
+        None,
+        ['bacteria'],
+        args['args'],
+        "session",
     )
 
 
-# test get_protein_page_urls()
+# test get_tax_page_urls()
 
 
-def test_get_protein_page_urls_no_links(no_links_page):
-    """Test get_protein_page_urls() on page with no links."""
-    with open(no_links_page) as fp:
+def test_get_tax_page_urls_no_links(gh147_page):
+    """Test get_tax_page_urls() on page with no links."""
+    with open(gh147_page) as fp:
         soup = BeautifulSoup(fp, features="lxml")
 
-    crawler.get_protein_page_urls("http://www.cazy.org/GH147_all.html", soup, "http://www.cazy.org")
+    crawler.get_tax_page_urls(
+        "http://www.cazy.org/GH147_bacteria.html",
+        soup,
+        'bacteria',
+        "http://www.cazy.org",
+        'GH147',
+    )
 
 
-def test_get_protein_page_urls_no_pag(gh147_page):
-    """Test get_protein_page_urls() on page with no pagination of proteins."""
+def test_get_tax_page_urls_no_pag(gh147_page):
+    """Test get_tax_page_urls() on page with no pagination of proteins."""
     with open(gh147_page) as fp:
         soup = BeautifulSoup(fp, features="lxml")
 
-    crawler.get_protein_page_urls("http://www.cazy.org/GH147_all.html", soup, "http://www.cazy.org")
+    crawler.get_tax_page_urls(
+        "http://www.cazy.org/GH147_bacteria.html",
+        soup,
+        'bacteria',
+        "http://www.cazy.org",
+        'GH147',
+    )
 
 
-def test_get_protein_page_urls_pag(gh1_page):
-    """Test get_protein_page_urls() on page with pagination of proteins."""
-    with open(gh1_page) as fp:
+def test_get_tax_page_urls_page(pag_page):
+    """Test get_tax_page_urls() on page with pagination of proteins."""
+    with open(pag_page) as fp:
         soup = BeautifulSoup(fp, features="lxml")
 
-    crawler.get_protein_page_urls("http://www.cazy.org/GH1_all.html", soup, "http://www.cazy.org")
+    crawler.get_tax_page_urls(
+        "http://www.cazy.org/GH1_bacteria.html",
+        soup,
+        'bacteria',
+        "http://www.cazy.org",
+        'GH147',
+    )
 
 
 # test parse_proteins
 
 
-def test_parse_proteins_none(null_logger, monkeypatch):
+def test_parse_proteins_none(monkeypatch, args):
     """Test parse_proteins when no page is returned."""
 
     def mock_get_page(*args, **kwargs):
-        return [None, "error"]
+        return None, "error message"
+
+    def mock_row(*args, **kwargs):
+        return {"url": None, "error": None, "sql": None}
 
     monkeypatch.setattr(crawler, "get_page", mock_get_page)
+    monkeypatch.setattr(crawler, "row_to_protein", mock_row)
 
-    assert True is isinstance(
-        crawler.parse_proteins("protein_url", "family", null_logger),
-        types.GeneratorType,
-    )
+    crawler.parse_proteins("protein_page_url", "GH1", None, 'bacteria', args['args'], "session")
 
 
-def test_parse_proteins(gh147_page, null_logger, monkeypatch):
+def test_parse_proteins(gh147_page, monkeypatch, args):
     """Tests parse_proteins when successful."""
     with open(gh147_page) as fp:
         soup = BeautifulSoup(fp, features="lxml")
 
     def mock_get_page(*args, **kwargs):
-        return soup
+        return soup, None
+
+    def mock_row(*args, **kwargs):
+        return {"url": None, "error": None, "sql": None}
 
     monkeypatch.setattr(crawler, "get_page", mock_get_page)
+    monkeypatch.setattr(crawler, "row_to_protein", mock_row)
+
+    crawler.parse_proteins("protein_url", "family", None, 'bacteria', args['args'], "session")
 
-    crawler.parse_proteins("protein_url", "family", null_logger)
+
+def test_parse_proteins_full(args, db_session, gh147_page):
+    """Test parsing proteins and adding to a database."""
+    with open(gh147_page) as fp:
+        soup = BeautifulSoup(fp, features="lxml")
+        crawler.parse_proteins("protein_url", "family", None, 'bacteria', args['args'], "session")
 
 
 # test row_to_protein()
 
 
-def test_row_to_protein_no_ecs(protein_without_ec):
+def test_row_to_protein_no_ecs(protein_without_ec, monkeypatch):
     """Test row_to_protein when no EC#s are listed."""
     with open(protein_without_ec) as fp:
         row = BeautifulSoup(fp, features="lxml")
 
-    assert True is isinstance(
-        crawler.row_to_protein(row, "GH147"),
-        crawler.Protein
-    )
+    def mock_sql(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_protein_to_db", mock_sql)
 
+    crawler.row_to_protein(row, "GH147", set(["Bacteroides caccae"]), 'bacteria', "session")
 
-def test_row_to_protein_ec(protein_with_ec):
+
+def test_row_to_protein_ec(protein_with_ec, monkeypatch):
     """Test row_to_protein when EC#s are listed."""
     with open(protein_with_ec) as fp:
         row = BeautifulSoup(fp, features="lxml")
 
-    assert True is isinstance(
-        crawler.row_to_protein(row, "GH147"),
-        crawler.Protein
-    )
+    def mock_sql(*args, **kwargs):
+        return
 
+    monkeypatch.setattr(sql_interface, "add_protein_to_db", mock_sql)
 
-def test_row_to_protein_gb_synoymns(protein_with_gb_synonyms):
+    crawler.row_to_protein(row, "GH147", set(["Bacteroides"]), 'bacteria', "session")
+
+
+def test_row_to_protein_gb_synoymns(protein_with_gb_synonyms, monkeypatch):
     """Test row_to_protein when protein has GenBank synonyms."""
     with open(protein_with_gb_synonyms) as fp:
         row = BeautifulSoup(fp, features="lxml")
 
-    assert True is isinstance(
-        crawler.row_to_protein(row, "GH147"),
-        crawler.Protein
-    )
+    def mock_sql(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_protein_to_db", mock_sql)
 
+    crawler.row_to_protein(row, "GH147", None, 'bacteria', "session")
 
-def test_row_to_protein_no_gb(protein_with_no_gb):
+
+def test_row_to_protein_no_gb(protein_with_no_gb, monkeypatch):
     """Test row_to_protein when protein has no GenBank accession."""
     with open(protein_with_no_gb) as fp:
         row = BeautifulSoup(fp, features="lxml")
 
-    assert True is isinstance(
-        crawler.row_to_protein(row, "GH147"),
-        crawler.Protein
-    )
+    def mock_sql(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_protein_to_db", mock_sql)
+
+    crawler.row_to_protein(row, "GH147", None, 'bacteria', "session")
+
+
+def test_row_to_protein_no_gb_sql_error(protein_with_no_gb, monkeypatch):
+    """Test row_to_protein when protein has no GenBank accession and SQL raises an error."""
+    with open(protein_with_no_gb) as fp:
+        row = BeautifulSoup(fp, features="lxml")
+
+    def mock_sql(*args, **kwargs):
+        raise TypeError
+
+    monkeypatch.setattr(sql_interface, "add_protein_to_db", mock_sql)
+
+    crawler.row_to_protein(row, "GH147", None, 'bacteria', "session")
+
+
+def test_row_to_protein_no_uniprot_no_pdb(protein_with_no_uniprot_no_pdb, monkeypatch):
+    """Test row_to_protein when protein has no UniProt or PDB accessions."""
+    with open(protein_with_no_uniprot_no_pdb) as fp:
+        row = BeautifulSoup(fp, features="lxml")
+
+    def mock_sql(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_protein_to_db", mock_sql)
+
+    crawler.row_to_protein(row, "GH147", set(), 'bacteria', "session")
+
+
+def test_row_to_protein_no_uniprot_no_pdb_sql_error(protein_with_no_uniprot_no_pdb, monkeypatch):
+    """Test row_to_protein when protein has no UniProt or PDB accessions and SQL raises an error."""
+    with open(protein_with_no_uniprot_no_pdb) as fp:
+        row = BeautifulSoup(fp, features="lxml")
+
+    def mock_sql(*args, **kwargs):
+        raise TypeError
+
+    monkeypatch.setattr(sql_interface, "add_protein_to_db", mock_sql)
+
+    crawler.row_to_protein(row, "GH147", None, 'bacteria', "session")
+
+
+def test_row_to_protein_gb_synoymns_raise_error(protein_with_gb_synonyms, monkeypatch):
+    """Test row_to_protein when protein has GenBank synonyms, and SQL raises an error."""
+    with open(protein_with_gb_synonyms) as fp:
+        row = BeautifulSoup(fp, features="lxml")
+
+    def mock_sql(*args, **kwargs):
+        raise TypeError
+
+    monkeypatch.setattr(sql_interface, "add_protein_to_db", mock_sql)
+
+    crawler.row_to_protein(row, "GH147", None, 'bacteria', "session")
 
 
 # browser decorator and get_page
@@ -563,6 +848,189 @@ def test_row_to_protein_no_gb(protein_with_no_gb):
 
 def test_browser_decorator():
     """Test browser_decorator to ensure proper handling if unsuccessful."""
-
-    result = crawler.get_page('www.caz!!!!!!!!y.org')
+    args = {"args": Namespace(timeout=10)}
+    result = crawler.get_page('www.caz!!!!!!!!y.org', args["args"], max_tries=1)
     assert True == (result[0] is None) and (type(result[1]) is MissingSchema)
+
+
+# unit tests for parsing HTML pages labelled under 'all'
+
+
+def test_parse_fam_kingdom_all(monkeypatch, cazy_home_url, args_subfam_false, test_fam):
+    """Test parse_family() when kingdoms = 'all'."""
+
+    def mock_parse_all(*args, **kwargs):
+        return test_fam, False, "failed scrapes", "sql_failures"
+
+    monkeypatch.setattr(crawler, "parse_family_via_all_pages", mock_parse_all)
+
+    crawler.parse_family(
+        test_fam,
+        cazy_home_url,
+        None,
+        'all',
+        args_subfam_false['args'],
+        'session',
+    )
+
+
+def test_parsing_all_incorrect_url(cazy_home_url, args_subfam_false):
+    """Test parse_family_via_all_pages() when the URL format is wrong"""
+
+    test_fam = crawler.Family("GH3", "Glycoside Hydrolases (GHs)", "http://www.cssazy.org/GH1.html")
+
+    crawler.parse_family_via_all_pages(
+        test_fam,
+        cazy_home_url,
+        None,
+        args_subfam_false['args'],
+        'session'
+    )
+
+
+def test_parsing_all_no_first_paginiation(test_fam, cazy_home_url, args_subfam_true, monkeypatch):
+    """Test parse_family_via_all_pages() when no page retured for the first pagination page."""
+
+    def mock_get_page(*args, **kwargs):
+        return None, "error message"
+
+    monkeypatch.setattr(crawler, "get_page", mock_get_page)
+
+    crawler.parse_family_via_all_pages(
+        test_fam,
+        cazy_home_url,
+        None,
+        args_subfam_true['args'],
+        'session'
+    )
+
+
+def test_parsing_all_no_paginiation_urls(
+    test_fam,
+    cazy_home_url,
+    args_subfam_true,
+    monkeypatch,
+    gh1_page,
+):
+    """Test parse_family_via_all_pages() when no paginiation page URLs returned."""
+
+    with open(gh1_page) as fp:
+        soup = BeautifulSoup(fp, features="lxml")
+
+    def mock_get_pages(*args, **kwargs):
+        return soup, None
+
+    def mock_get_urls(*args, **kwargs):
+        return [], 0
+
+    monkeypatch.setattr(crawler, "get_page", mock_get_pages)
+    monkeypatch.setattr(crawler, "get_paginiation_page_urls", mock_get_urls)
+
+    crawler.parse_family_via_all_pages(
+        test_fam,
+        cazy_home_url,
+        None,
+        args_subfam_true['args'],
+        'session'
+    )
+
+
+def test_successful_parse_all(test_fam, gh1_page, monkeypatch, args_subfam_true, cazy_home_url):
+    """Test parse_family_via_all_pages() when parse is successful."""
+
+    with open(gh1_page) as fp:
+        soup = BeautifulSoup(fp, features="lxml")
+
+    def mock_get_page(*args, **kwargs):
+        return soup, None
+
+    def mock_page_urls(*args, **kwargs):
+        return ["url1", "url2"], 0
+
+    def mock_parse_proteins(*args, **kwargs):
+        return [
+            {"url": None, "error": None, "sql": None},
+            {"url": None, "error": None, "sql": None},
+        ]
+
+    monkeypatch.setattr(crawler, "get_page", mock_get_page)
+    monkeypatch.setattr(crawler, "get_paginiation_page_urls", mock_page_urls)
+    monkeypatch.setattr(crawler, "parse_proteins_from_all", mock_parse_proteins)
+
+    crawler.parse_family(
+        test_fam,
+        cazy_home_url,
+        None,
+        'all',
+        args_subfam_true['args'],
+        "session",
+    )
+
+
+def test_get_paginiation_urls(monkeypatch, cazy_home_url, gh1_page):
+    """Test get_paginiation_page_urls() when urls successfully retrieved."""
+
+    with open(gh1_page) as fp:
+        soup = BeautifulSoup(fp, features="lxml")
+
+    crawler.get_paginiation_page_urls(
+        "http://www.cazy.org/GH1_all.html",
+        soup,
+        cazy_home_url,
+        "GH147"
+    )
+
+
+def test_get_paginiation_no_last(monkeypatch, cazy_home_url, gh147_page):
+    """Test get_paginiation_page_urls() when urls successfully retrieved."""
+
+    with open(gh147_page) as fp:
+        soup = BeautifulSoup(fp, features="lxml")
+
+    crawler.get_paginiation_page_urls(
+        "http://www.cazy.org/GH147_all.html",
+        soup,
+        cazy_home_url,
+        "GH147",
+    )
+
+
+def test_parse_proteins_all_no_page(monkeypatch, args_subfam_true):
+    """Test parse_proteins_from_all() when no connection is made to CAZy."""
+
+    def mock_get_page(*args, **kwargs):
+        return None, "error message"
+
+    monkeypatch.setattr(crawler, "get_page", mock_get_page)
+
+    crawler.parse_proteins_from_all(
+        "page_url",
+        "GH147",
+        None,
+        "session",
+        args_subfam_true["args"],
+    )
+
+
+def test_parse_proteins_from_all_successfully(monkeypatch, args_subfam_true, gh147_page):
+    """Test parse_proteins_from_all() when successful."""
+
+    with open(gh147_page) as fp:
+        soup = BeautifulSoup(fp, features="lxml")
+
+    def mock_get_page(*args, **kwargs):
+        return soup, None
+
+    def mock_adding_to_db(*args, **kwargs):
+        return {"url": None, "error": None, "sql": None}
+
+    monkeypatch.setattr(crawler, "get_page", mock_get_page)
+    monkeypatch.setattr(sql_interface, "add_protein_to_db", mock_adding_to_db)
+
+    crawler.parse_proteins_from_all(
+        "http://www.cazy.org/GH147_all.html",
+        "GH147",
+        None,
+        "session",
+        args_subfam_true['args'],
+    )
diff --git a/tests/test_expand.py b/tests/test_expand.py
new file mode 100644
index 00000000..d606afe4
--- /dev/null
+++ b/tests/test_expand.py
@@ -0,0 +1,867 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Author:
+# Emma E. M. Hobbs
+
+# Contact
+# eemh1@st-andrews.ac.uk
+
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+
+# The MIT License
+
+"""Tests the module sql which builds and interacts with an SQL database.
+
+These test are intened to be run from the root of the repository using:
+pytest -v
+"""
+
+
+import pytest
+
+from argparse import Namespace, ArgumentParser
+from pathlib import Path
+
+from scraper import expand
+from scraper.expand import get_pdb_structures, get_genbank_sequences
+from scraper.sql.sql_orm import Cazyme, Cazymes_Genbanks, Genbank, Taxonomy
+from scraper.utilities import file_io, parse_configuration
+
+
+@pytest.fixture
+def db_path():
+    path_ = Path("tests")
+    path_ = path_ / "test_inputs" / "test_inputs_sql" / "unit_test_db_2021-03-01--15-06-59.db"
+    return path_
+
+
+@pytest.fixture
+def output_dir(test_dir):
+    path_ = test_dir / "test_outputs"
+    return path_
+
+
+@pytest.fixture
+def tax_filter():
+    return set(["Nonlabens"])
+
+
+@pytest.fixture
+def genbank_query(db_session):
+    query = db_session.query(Genbank, Cazymes_Genbanks, Taxonomy).\
+        join(Genbank, (Genbank.genbank_id == Cazymes_Genbanks.genbank_id)).\
+        filter(Cazymes_Genbanks.primary == True).all()
+    return query
+
+
+# tests for get_pdb_structures
+
+
+@pytest.mark.skip()
+def test_main_no_db(monkeypatch):
+    """Test main() when an the database file cannot be found."""
+
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
+
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            database=Path("--"),
+            verbose=False,
+            log=None,
+            force=False,
+            nodelete=False,
+            outdir=None,
+        )
+        return parser
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    def mock_config(*args, **kwargs):
+        return None, set()
+
+    monkeypatch.setattr(utilities, "build_pdb_structures_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(parse_configuration, "get_configuration", mock_config)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_no_return)
+
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        get_pdb_structures.main()
+    assert pytest_wrapped_e.type == SystemExit
+
+
+@pytest.mark.skip()
+def test_main_outdir_is_none(db_path, monkeypatch):
+    """Test main() when outdir=None."""
+
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
+
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            database=db_path,
+            outdir=None,
+            verbose=False,
+            log=None,
+            force=False,
+            nodelete=False,
+        )
+        return parser
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    def mock_config(*args, **kwargs):
+        return None, set()
+
+    monkeypatch.setattr(utilities, "build_pdb_structures_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(utilities, "config_logger", mock_no_return)
+    monkeypatch.setattr(parse_configuration, "get_configuration", mock_config)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_no_return)
+    monkeypatch.setattr(get_pdb_structures, "get_every_cazymes_structures", mock_no_return)
+
+    get_pdb_structures.main()
+
+
+@pytest.mark.skip()
+def test_main(db_path, output_dir, monkeypatch):
+    """Test main()."""
+
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
+
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            database=db_path,
+            outdir=output_dir,
+            verbose=False,
+            log=None,
+            force=True,
+            nodelete=True,
+        )
+        return parser
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    def mock_config(*args, **kwargs):
+        return None, set()
+
+    monkeypatch.setattr(utilities, "build_pdb_structures_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(utilities, "config_logger", mock_no_return)
+    monkeypatch.setattr(parse_configuration, "get_configuration", mock_config)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_no_return)
+    monkeypatch.setattr(get_pdb_structures, "get_every_cazymes_structures", mock_no_return)
+
+    get_pdb_structures.main()
+
+
+@pytest.mark.skip()
+def test_main_argv(db_path, output_dir, monkeypatch):
+    """Test main()."""
+
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
+
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            database=db_path,
+            outdir=output_dir,
+            verbose=False,
+            log=None,
+            force=True,
+            nodelete=True,
+        )
+        return parser
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    def mock_config(*args, **kwargs):
+        return {}, set()
+
+    monkeypatch.setattr(utilities, "build_pdb_structures_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(utilities, "config_logger", mock_no_return)
+    monkeypatch.setattr(parse_configuration, "get_configuration", mock_config)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_no_return)
+    monkeypatch.setattr(get_pdb_structures, "get_structures_for_specific_cazymes", mock_no_return)
+
+    get_pdb_structures.main()
+
+
+@pytest.mark.skip()
+def test_get_every_cazymes_structures_primary(db_session, output_dir, monkeypatch):
+    """Test get_every_cazymes_structures() when primary is True and taxonomy filter is given."""
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_pdb_structures, "download_pdb_structures", mock_no_return)
+
+    args = {"args": Namespace(primary=True)}
+    tax_filter = set(["Nonlabens"])
+
+    get_pdb_structures.get_every_cazymes_structures(
+        output_dir,
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_get_every_cazymes_structures_all(db_session, output_dir, monkeypatch):
+    """Test get_every_cazymes_structures() when primary is False and no taxonomy filter is given."""
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_pdb_structures, "download_pdb_structures", mock_no_return)
+
+    args = {"args": Namespace(primary=False)}
+    tax_filter = None
+
+    get_pdb_structures.get_every_cazymes_structures(
+        output_dir,
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_get_structures_for_specific_cazymes_primary(db_session, output_dir, monkeypatch):
+    """Test get_structures_for_specific_cazymes when primary is true and tax filter is given."""
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_pdb_structures, "download_pdb_structures", mock_no_return)
+
+    args = {"args": Namespace(primary=True)}
+    tax_filter = set(["Nonlabens"])
+    config_dict = {"classes": ["PL"], "Polysaccharide Lyases (PLs)": ["PL28"]}
+
+    get_pdb_structures.get_structures_for_specific_cazymes(
+        output_dir,
+        config_dict,
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_get_structures_for_specific_cazymes(db_session, output_dir, monkeypatch):
+    """Test get_structures_for_specific_cazymes when primary is False and tax filter not given."""
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_pdb_structures, "download_pdb_structures", mock_no_return)
+
+    args = {"args": Namespace(primary=False)}
+    tax_filter = None
+    config_dict = {
+        "classes": ["PL"],
+        "Polysaccharide Lyases (PLs)": ["PL28","GH3_1"],
+        "CAZyclass": None,
+    }
+
+    get_pdb_structures.get_structures_for_specific_cazymes(
+        output_dir,
+        config_dict,
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+# test for get_genbank_sequences
+
+
+@pytest.mark.skip()
+def test_main_no_db_genbank(monkeypatch):
+    """Test main() when an the database file cannot be found."""
+
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
+
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            database=Path("--"),
+            email="dummy_email",
+            verbose=False,
+            log=None,
+            force=False,
+            nodelete=False,
+            outdir=None,
+        )
+        return parser
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    def mock_config(*args, **kwargs):
+        return None, set()
+
+    monkeypatch.setattr(utilities, "build_genbank_sequences_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(parse_configuration, "get_configuration", mock_config)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_no_return)
+
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        get_genbank_sequences.main()
+    assert pytest_wrapped_e.type == SystemExit
+
+
+@pytest.mark.skip()
+def test_main_no_config_no_update(db_path, monkeypatch):
+    """Test main() when outdir=None."""
+
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
+
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            database=db_path,
+            email="dummy_email",
+            outdir=None,
+            verbose=False,
+            log=None,
+            force=False,
+            nodelete=False,
+            update=False,
+        )
+        return parser
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    def mock_config(*args, **kwargs):
+        return None, set()
+
+    monkeypatch.setattr(utilities, "build_genbank_sequences_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(utilities, "config_logger", mock_no_return)
+    monkeypatch.setattr(parse_configuration, "get_configuration", mock_config)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_no_return)
+    monkeypatch.setattr(
+        get_genbank_sequences,
+        "get_missing_sequences_for_everything",
+        mock_no_return,
+    )
+
+    get_genbank_sequences.main()
+
+
+@pytest.mark.skip()
+def test_main_no_config_yes_update(db_path, monkeypatch):
+    """Test main() when outdir=None."""
+
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
+
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            database=db_path,
+            email="dummy_email",
+            outdir=None,
+            verbose=False,
+            log=None,
+            force=False,
+            nodelete=False,
+            update=True,
+        )
+        return parser
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    def mock_config(*args, **kwargs):
+        return None, set()
+
+    monkeypatch.setattr(utilities, "build_genbank_sequences_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(utilities, "config_logger", mock_no_return)
+    monkeypatch.setattr(parse_configuration, "get_configuration", mock_config)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_no_return)
+    monkeypatch.setattr(
+        get_genbank_sequences,
+        "add_and_update_all_sequences",
+        mock_no_return,
+    )
+
+    get_genbank_sequences.main()
+
+
+@pytest.mark.skip()
+def test_main_yes_config_no_update(db_path, monkeypatch):
+    """Test main() when outdir=None."""
+
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
+
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            database=db_path,
+            email="dummy_email",
+            outdir=None,
+            verbose=False,
+            log=None,
+            force=False,
+            nodelete=False,
+            update=False,
+        )
+        return parser
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    def mock_config(*args, **kwargs):
+        return {}, set()
+
+    monkeypatch.setattr(utilities, "build_genbank_sequences_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(utilities, "config_logger", mock_no_return)
+    monkeypatch.setattr(parse_configuration, "get_configuration", mock_config)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_no_return)
+    monkeypatch.setattr(
+        get_genbank_sequences,
+        "get_missing_sequences_for_specific_records",
+        mock_no_return,
+    )
+
+    get_genbank_sequences.main()
+
+
+@pytest.mark.skip()
+def test_main_yes_config_yes_update(db_path, monkeypatch):
+    """Test main() when outdir=None."""
+
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
+
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            database=db_path,
+            email="dummy_email",
+            outdir=None,
+            verbose=False,
+            log=None,
+            force=False,
+            nodelete=False,
+            update=True,
+        )
+        return parser
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    def mock_config(*args, **kwargs):
+        return {}, set()
+
+    monkeypatch.setattr(utilities, "build_genbank_sequences_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(utilities, "config_logger", mock_no_return)
+    monkeypatch.setattr(parse_configuration, "get_configuration", mock_config)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_no_return)
+    monkeypatch.setattr(
+        get_genbank_sequences,
+        "update_sequences_for_specific_records",
+        mock_no_return,
+    )
+
+    get_genbank_sequences.main()
+
+
+@pytest.mark.skip()
+def test_get_missing_sequences_for_everything_primary(db_session, monkeypatch):
+    """Tests get_missing_sequences_for_everything() when primary is True and tax filter is given."""
+
+    def mock_accession(*args, **kwargs):
+        return []
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_genbank_sequences, "extract_accessions", mock_accession)
+    monkeypatch.setattr(get_genbank_sequences, "get_sequences_add_to_db", mock_no_return)
+
+    args = {"args": Namespace(primary=True)}
+    tax_filter = set(["Nonlabens"])
+
+    get_genbank_sequences.get_missing_sequences_for_everything(
+        "date",
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_get_missing_sequences_for_everything(db_session, monkeypatch):
+    """Tests get_missing_sequences_for_everything() when primary is False and tax filter is None."""
+
+    def mock_accession(*args, **kwargs):
+        return ["acc1", "acc2"]
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_genbank_sequences, "extract_accessions", mock_accession)
+    monkeypatch.setattr(get_genbank_sequences, "get_accession_chunks", mock_accession)
+    monkeypatch.setattr(get_genbank_sequences, "get_sequences_add_to_db", mock_no_return)
+
+    args = {"args": Namespace(primary=True, epost=200)}
+    tax_filter = None
+
+    get_genbank_sequences.get_missing_sequences_for_everything(
+        "date",
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_add_and_update_all_sequences_primary(db_session, monkeypatch):
+    """Tests add_and_update_all_sequences() when primary is True and tax filter is given."""
+
+    def mock_accession(*args, **kwargs):
+        return {}
+
+    monkeypatch.setattr(get_genbank_sequences, "extract_accessions_and_dates", mock_accession)
+
+    args = {"args": Namespace(primary=True, epost=200)}
+    tax_filter = set(["Nonlabens"])
+
+    get_genbank_sequences.add_and_update_all_sequences(
+        "date",
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_add_and_update_all_sequences_no_updates(db_session, monkeypatch):
+    """Tests get_missing_sequences_for_everything() when there are no seq to update."""
+
+    def mock_accession(*args, **kwargs):
+        return {"acc1":0, "acc2":1}
+
+    def mock_no_acc(*args, **kwargs):
+        return []
+
+    monkeypatch.setattr(get_genbank_sequences, "extract_accessions_and_dates", mock_accession)
+    monkeypatch.setattr(get_genbank_sequences, "get_accessions_for_new_sequences", mock_no_acc)
+
+    args = {"args": Namespace(primary=True, epost=200)}
+    tax_filter = None
+
+    get_genbank_sequences.add_and_update_all_sequences(
+        "date",
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_add_and_update_all_sequences(db_session, monkeypatch):
+    """Tests get_missing_sequences_for_everything() when primary is False and tax filter is None."""
+
+    def mock_accession(*args, **kwargs):
+        return {"acc1":1, "acc2":2}
+
+    def mock_acc(*args, **kwargs):
+        return ["acc", "acc1"]
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_genbank_sequences, "extract_accessions_and_dates", mock_accession)
+    monkeypatch.setattr(get_genbank_sequences, "get_accessions_for_new_sequences", mock_acc)
+    monkeypatch.setattr(get_genbank_sequences, "get_accession_chunks", mock_acc)
+    monkeypatch.setattr(get_genbank_sequences, "get_sequences_add_to_db", mock_no_return)
+
+    args = {"args": Namespace(primary=True, epost=200)}
+    tax_filter = None
+
+    get_genbank_sequences.add_and_update_all_sequences(
+        "date",
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_get_missing_sequences_for_specific_records_primary(db_session, monkeypatch):
+    """Tests get_missing_sequences_for_specific_records, primary is True, tax filter isn't None."""
+
+    def mock_accession(*args, **kwargs):
+        return []
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_genbank_sequences, "extract_accessions", mock_accession)
+    monkeypatch.setattr(get_genbank_sequences, "get_sequences_add_to_db", mock_no_return)
+
+    args = {"args": Namespace(primary=True, epost=150)}
+    tax_filter = None
+    config = {"classes":["PL"], "PL": ["PL28", "PL29_1"], "GH": None}
+
+    get_genbank_sequences.get_missing_sequences_for_specific_records(
+        "date",
+        config,
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_get_missing_sequences_for_specific_records(db_session, monkeypatch):
+    """Tests get_missing_sequences_for_specific_records, primary is False, tax filter isn't None."""
+
+    def mock_accession(*args, **kwargs):
+        return ["acc", "acc1"]
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_genbank_sequences, "extract_accessions", mock_accession)
+    monkeypatch.setattr(get_genbank_sequences, "get_sequences_add_to_db", mock_no_return)
+
+    args = {"args": Namespace(primary=False, epost=150)}
+    tax_filter = set(["Nonlabens"])
+    config = {"classes":["PL"], "PL": ["PL28", "PL29_1"], "GH": None}
+
+    get_genbank_sequences.get_missing_sequences_for_specific_records(
+        "date",
+        config,
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_update_sequences_for_specific_records_primary_no_acc1(db_session, monkeypatch):
+    """Test update_sequences_for_specific_records, primary is True, tax filter not given."""
+
+    def mock_accession(*args, **kwargs):
+        return {}
+
+    def mock_acc(*args, **kwargs):
+        return []
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_genbank_sequences, "extract_accessions_and_dates", mock_accession)
+    monkeypatch.setattr(get_genbank_sequences, "get_accessions_for_new_sequences", mock_acc)
+    monkeypatch.setattr(get_genbank_sequences, "get_accession_chunks", mock_acc)
+    monkeypatch.setattr(get_genbank_sequences, "get_sequences_add_to_db", mock_no_return)
+
+    args = {"args": Namespace(primary=True, epost=200)}
+    tax_filter = None
+    config = {"classes": ["PL"], "PL": ["PL28", "PL29_1"], "GH": None}
+
+    get_genbank_sequences.update_sequences_for_specific_records(
+        "date",
+        config,
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_update_sequences_for_specific_records_primary_no_acc2(db_session, monkeypatch):
+    """Test update_sequences_for_specific_records, primary is True, tax filter not given."""
+
+    def mock_accession(*args, **kwargs):
+        return {"acc1": 1, "acc2": 2}
+
+    def mock_acc(*args, **kwargs):
+        return []
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_genbank_sequences, "extract_accessions_and_dates", mock_accession)
+    monkeypatch.setattr(get_genbank_sequences, "get_accessions_for_new_sequences", mock_acc)
+    monkeypatch.setattr(get_genbank_sequences, "get_accession_chunks", mock_acc)
+    monkeypatch.setattr(get_genbank_sequences, "get_sequences_add_to_db", mock_no_return)
+
+    args = {"args": Namespace(primary=True, epost=200)}
+    tax_filter = None
+    config = {"classes": ["PL"], "PL": ["PL28", "PL29_1"], "GH": None}
+
+    get_genbank_sequences.update_sequences_for_specific_records(
+        "date",
+        config,
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_update_sequences_for_specific_records_primary_false(db_session, monkeypatch):
+    """Test update_sequences_for_specific_records, primary is False, tax filter given."""
+
+    def mock_accession(*args, **kwargs):
+        return {"acc1": 1, "acc2": 2}
+
+    def mock_acc(*args, **kwargs):
+        return ["acc", "acc1"]
+
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(get_genbank_sequences, "extract_accessions_and_dates", mock_accession)
+    monkeypatch.setattr(get_genbank_sequences, "get_accessions_for_new_sequences", mock_acc)
+    monkeypatch.setattr(get_genbank_sequences, "get_accession_chunks", mock_acc)
+    monkeypatch.setattr(get_genbank_sequences, "get_sequences_add_to_db", mock_no_return)
+
+    args = {"args": Namespace(primary=False, epost=200)}
+    tax_filter = set(["Nonlabens"])
+    config = {"classes": ["PL"], "PL": ["PL28", "PL29_1"], "GH": None}
+
+    get_genbank_sequences.update_sequences_for_specific_records(
+        "date",
+        config,
+        tax_filter,
+        db_session,
+        args["args"],
+    )
+
+
+@pytest.mark.skip()
+def test_extract_accessions_no_tax(genbank_query):
+    """Test extract_accessions() when no tax filter is given."""
+    get_genbank_sequences.extract_accessions(genbank_query, None)
+
+
+@pytest.mark.skip()
+def test_extract_accessions_tax_given(genbank_query, tax_filter):
+    """Test extract_accessions() when no tax filter is given."""
+    get_genbank_sequences.extract_accessions(genbank_query, tax_filter)
+
+
+@pytest.mark.skip()
+def test_extract_accessions_and_dates_no_tax(genbank_query):
+    """Test extract_accessions() when no tax filter is given."""
+    get_genbank_sequences.extract_accessions_and_dates(genbank_query, None)
+
+
+@pytest.mark.skip()
+def test_extract_accessions_and_dates_tax_given(genbank_query, tax_filter):
+    """Test extract_accessions() when no tax filter is given."""
+    get_genbank_sequences.extract_accessions_and_dates(genbank_query, tax_filter)
+
+
+@pytest.mark.skip()
+def test_get_accession_chunks():
+    """Test get_accession_chunks()"""
+    lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
+    get_genbank_sequences.get_accession_chunks(lst, 2)
+
+
+@pytest.mark.skip()
+def test_entry_retry():
+    """Test entrez_retry."""
+
+    def mock_record(*args, **kwargs):
+        return "test_record"
+
+    assert "test_record" == get_genbank_sequences.entrez_retry(mock_record)
+
+
+@pytest.mark.skip()
+def test_entrez_retry_none():
+    """Test entrez_retry when nothing is returned."""
+
+    def mock_record(*args, **kwargs):
+        return
+
+    assert get_genbank_sequences.entrez_retry(mock_record) is None 
diff --git a/tests/test_file_io.py b/tests/test_file_io.py
index 7c6fe3b1..7657bb8a 100644
--- a/tests/test_file_io.py
+++ b/tests/test_file_io.py
@@ -17,22 +17,25 @@
 
 # The MIT License
 
-"""Tests the module file_io which builds the logger and args parser.
+"""Tests the submodule file_io from utilities.
 
 These test are intened to be run from the root of the repository using:
 pytest -v
-
 """
 
-import json
+
 import pytest
+import shutil
 import sys
 
 import pandas as pd
 
 from argparse import Namespace
 
-from scraper import file_io, parse
+from Bio.Seq import Seq
+from Bio.SeqRecord import SeqRecord
+
+from scraper.utilities import file_io
 
 
 @pytest.fixture
@@ -48,12 +51,15 @@ def making_output_dir(test_output_dir):
 
 
 @pytest.fixture
-def args_config_None():
+def args_config_none():
     args_dict = {
         "args": Namespace(
             config=None,
             classes=None,
             families=None,
+            genera=None,
+            species=None,
+            strains=None,
         )
     }
     return args_dict
@@ -113,24 +119,15 @@ def args_config_file(config_file_path):
 
 
 @pytest.fixture
-def args_config_cmd(config_file_path):
+def args_config_cmd():
     args_dict = {
         "args": Namespace(
             config=None,
             classes="CE,AA",
-            families="GH14,PL15",
-        )
-    }
-    return args_dict
-
-
-@pytest.fixture
-def args_config_none(config_file_path):
-    args_dict = {
-        "args": Namespace(
-            config=None,
-            classes=None,
-            families=None,
+            families="GH14,GT1,PL15,CE6,AA10,CBM50,DD21,CBMAA1",
+            genera=None,
+            species=None,
+            strains=None,
         )
     }
     return args_dict
@@ -169,14 +166,6 @@ def testing_df():
     return df
 
 
-@pytest.fixture
-def df_output_file(test_dir):
-    df_output = (
-        test_dir / "test_targets" / "file_io_test_targets" / "test_writing_df.csv"
-    )
-    return df_output
-
-
 @pytest.fixture
 def stdout_args(test_dir):
     args_dict = {
@@ -198,335 +187,122 @@ def output_args(test_dir):
     return args_dict
 
 
-# test make_output_directory()
-
-
-def test_output_dir_creation_nd_true(making_output_dir, null_logger):
-    """Test creation of output dir when nodelete is false"""
-    file_io.make_output_directory(making_output_dir, null_logger, True, False)
-
-
-def test_output_dir_creation_nd_false(making_output_dir, null_logger):
-    """Test creation of output dir when nodelete is true"""
-    file_io.make_output_directory(making_output_dir, null_logger, True, True)
-
-
-def test_output_dir_creation_exists(test_dir, null_logger):
-    """Test creation of output dir when already exists."""
-    file_io.make_output_directory(test_dir, null_logger, False, False)
-
-
-# test parse_configuration()
-
-
-def test_parse_config_file_cmd(
-    args_config_file_cmd,
-    cazy_dictionary,
-    file_io_path,
-    null_logger,
-    monkeypatch,
-):
-    """Test parse_config when only config file is given."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    std_classes = list(cazy_dict.keys())
-
-    def mock_cazy_dict(*args, **kwargs):
-        return cazy_dict, std_classes
-
-    monkeypatch.setattr(file_io, "get_cazy_dict_std_names", mock_cazy_dict)
-
-    excluded_classes, config_dict, cazy_dict = file_io.parse_configuration(
-        file_io_path,
-        args_config_file_cmd["args"],
-        null_logger,
-    )
-
-    expected_excluded_classes = [
-        '<strong>GlycosylTransferases (GTs)</strong>',
-        '<strong>Carbohydrate-Binding Modules (CBMs)</strong>',
-    ]
-    expected_config_dict = {
-        'classes': [
-            'Glycoside Hydrolases (GHs)',
-            'Polysaccharide Lyases (PLs)',
-            'Carbohydrate Esterases (CEs)',
-            'Auxiliary Activities (AAs)',
-        ],
-        'Glycoside Hydrolases (GHs)': ['GH147', 'GH14'],
-        'GlycosylTransferases (GTs)': None,
-        'Polysaccharide Lyases (PLs)': ['PL17', 'PL15'],
-        'Carbohydrate Esterases (CEs)': None,
-        'Auxiliary Activities (AAs)': None,
-        'Carbohydrate-Binding Modules (CBMs)': None,
+@pytest.fixture
+def tax_no_yaml_args():
+    args_dict = {
+        "args": Namespace(
+            config="fake_yaml",
+            genera="Bacillus,Priestia",
+            species="Arabidopsis thaliana",
+            strains="Bathycoccus prasinos RCC1105,Cyanidioschyzon merolae strain 10D",
+        )
     }
-
-    # assert expected_excluded_classes == excluded_classes
-    # assert expected_config_dict == config_dict
-
-
-def test_parse_config_file_only(args_config_file, cazy_dictionary, null_logger, monkeypatch):
-    """Test parse_configuration when only configuration file is given."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    std_classes = list(cazy_dict.keys())
-
-    def mock_cazy_dict(*args, **kwargs):
-        return cazy_dict, std_classes
-
-    monkeypatch.setattr(file_io, "get_cazy_dict_std_names", mock_cazy_dict)
-
-    excluded_classes, config_dict, cazy_dict = file_io.parse_configuration(
-        file_io_path,
-        args_config_file["args"],
-        null_logger,
-    )
-
-
-def test_parse_config_cmd_only(args_config_cmd, cazy_dictionary, null_logger, monkeypatch):
-    """Test parse_configuration when only cmd-line configuration is given."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    std_classes = list(cazy_dict.keys())
-
-    def mock_cazy_dict(*args, **kwargs):
-        return cazy_dict, std_classes
-
-    monkeypatch.setattr(file_io, "get_cazy_dict_std_names", mock_cazy_dict)
-
-    excluded_classes, config_dict, cazy_dict = file_io.parse_configuration(
-        file_io_path,
-        args_config_cmd["args"],
-        null_logger,
-    )
-
-
-def test_parse_config_no_config(args_config_none, cazy_dictionary, null_logger, monkeypatch):
-    """Test parse_configuration when no configuration is given."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    std_classes = list(cazy_dict.keys())
-
-    def mock_cazy_dict(*args, **kwargs):
-        return cazy_dict, std_classes
-
-    monkeypatch.setattr(file_io, "get_cazy_dict_std_names", mock_cazy_dict)
-
-    excluded_classes, config_dict, cazy_dict = file_io.parse_configuration(
-        file_io_path,
-        args_config_none["args"],
-        null_logger,
-    )
+    return args_dict
 
 
-# test get_cazy_dict_std_names()
+@pytest.fixture
+def tax_args(config_file_path):
+    args_dict = {
+        "args": Namespace(
+            config=config_file_path,
+            genera="Bacillus,Priestia",
+            species="Arabidopsis thaliana",
+            strains="Bathycoccus prasinos RCC1105,Cyanidioschyzon merolae strain 10D",
+        )
+    }
+    return args_dict
 
 
-def test_cazy_dict_not_found(null_logger):
-    """Test get_cazy_dict_std_names() when the cazy_dictionary file cannot be found."""
-    fake_path = parse.__file__
+# test make_output_directory()
 
-    with pytest.raises(SystemExit) as pytest_wrapped_err:
-        file_io.get_cazy_dict_std_names(fake_path, null_logger)
-    assert pytest_wrapped_err.type == SystemExit
 
+def test_making_new_dir_1(making_output_dir):
+    """Test making a new directory."""
+    path_ = making_output_dir / "test_build"
+    file_io.make_output_directory(path_, True, True)
+    shutil.rmtree(path_)
 
-def test_cazy_dict_success(null_logger):
-    """Test get_cazy_dict_std_names() when the retrieval of the data is successful."""
-    path = file_io.__file__
 
-    file_io.get_cazy_dict_std_names(path, null_logger)
+def test_making_new_dir_2(making_output_dir):
+    """Test making a new directory."""
+    path_ = making_output_dir / "test_build"
+    file_io.make_output_directory(path_, False, True)
+    shutil.rmtree(path_)
 
 
-# test get_yaml_configuration
+def test_output_dir_creation_nd_true(making_output_dir):
+    """Test creation of output dir when nodelete is false"""
+    file_io.make_output_directory(making_output_dir, True, False)
 
 
-def test_get_yaml_not_found(empty_config_dict, cazy_dictionary, args_no_yaml, null_logger):
-    """Test get_yaml_configuration when the configuration cannot be found."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
+def test_output_dir_creation_nd_false(making_output_dir):
+    """Test creation of output dir when nodelete is true"""
+    file_io.make_output_directory(making_output_dir, True, True)
 
-    std_classes = list(cazy_dict.keys())
 
+def test_output_dir_creation_exists(test_dir):
+    """Test creation of output dir when already exists."""
     with pytest.raises(SystemExit) as pytest_wrapped_err:
-        file_io.get_yaml_configuration(
-            empty_config_dict,
-            cazy_dict,
-            std_classes,
-            args_no_yaml["args"],
-            null_logger,
-        )
+        file_io.make_output_directory(test_dir, False, False)
     assert pytest_wrapped_err.type == SystemExit
 
 
-def test_get_yaml_success(empty_config_dict, cazy_dictionary, args_config_file, null_logger):
-    """Test get_yaml_configuration when successfully retrieves and parses data from yaml file."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    std_classes = list(cazy_dict.keys())
-
-    file_io.get_yaml_configuration(
-        empty_config_dict,
-        cazy_dict,
-        std_classes,
-        args_config_file["args"],
-        null_logger,
-    )
-
-
-# test get_yaml_cazy_classes
-
-
-def test_get_yaml_classes_no(cazy_dictionary, null_logger):
-    """Test get_yaml_cazy_classes when classes key cannot be found."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    std_classes = list(cazy_dict.keys())
-    yaml_dict = {"Glycoside Hydrolases (GHs)":["GH1","GH2"]}
-
-    file_io.get_yaml_cazy_classes(yaml_dict, cazy_dict, std_classes, null_logger)
-
-
-def test_get_yaml_classes_none(cazy_dictionary, null_logger):
-    """Test get_yaml_cazy_classes when classes key has the value of None."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    std_classes = list(cazy_dict.keys())
-    yaml_dict = {"classes": None, "Glycoside Hydrolases (GHs)":["GH1","GH2"]}
-
-    file_io.get_yaml_cazy_classes(yaml_dict, cazy_dict, std_classes, null_logger)
-
-
-def test_get_yaml_classes_success(cazy_dictionary, null_logger):
-    """Test get_yaml_cazy_classes when classes key has the value of CAZy classes."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    std_classes = list(cazy_dict.keys())
-    yaml_dict = {"classes": ["PL","CE"], "Glycoside Hydrolases (GHs)":["GH1","GH2"]}
-
-    file_io.get_yaml_cazy_classes(yaml_dict, cazy_dict, std_classes, null_logger)
-
-
-# test parse_user_cazy_classes()
-
-
-def test_parse_user_cazy_classes(cazy_dictionary, null_logger):
-    """Test parse_user_cazy_classes to standardise the CAZy classes written by the user."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    cazy_classes = ['GH', 'pl']
-    class_name = [
-        'Glycoside Hydrolases (GHs)',
-        'GlycosylTransferases (GTs)',
-        'Polysaccharide Lyases (PLs)',
-        'Carbohydrate Esterases (CEs)',
-        'Auxiliary Activities (AAs)',
-        'Carbohydrate-Binding Modules (CBMs)',
-    ]
-
-    exepected = ['Glycoside Hydrolases (GHs)', 'Polysaccharide Lyases (PLs)']
-
-    assert exepected == file_io.parse_user_cazy_classes(
-        cazy_classes,
-        cazy_dict,
-        class_name,
-        null_logger,
-    )
+# test write_out_failed_scrapes
 
 
-def test_cannot_standardise_user_classes(cazy_dictionary, null_logger):
-    """Test when cannot standardise a name listed in the configuration file."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    cazy_classes = ['GH', 'pl', 'testtesttest']
-    class_name = [
-        'Glycoside Hydrolases (GHs)',
-        'GlycosylTransferases (GTs)',
-        'Polysaccharide Lyases (PLs)',
-        'Carbohydrate Esterases (CEs)',
-        'Auxiliary Activities (AAs)',
-        'Carbohydrate-Binding Modules (CBMs)',
-    ]
-
-    exepected = ['Glycoside Hydrolases (GHs)', 'Polysaccharide Lyases (PLs)']
-
-    assert exepected == file_io.parse_user_cazy_classes(
-        cazy_classes,
-        cazy_dict,
-        class_name,
-        null_logger,
+def test_write_out_failed_scrapes_stdout(stdout_args):
+    """Test write_out_failed_scrapes when args.output is sys.STDOUT"""
+    file_io.write_out_failed_scrapes(
+        ["url_1 - message", "url_2 - fail reason"],
+        "time_stamp",
+        stdout_args["args"],
     )
 
 
-# test get_cmd_defined_fams_classes()
-
-
-def get_cmd_configuration(args_config_cmd, cazy_dictionary, null_logger):
-    """Test get_cmd_defined_fams_classes."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    std_classes = list(cazy_dict.keys())
-    file_io.get_cmd_defined_fams_classes(
-        cazy_dict,
-        std_classes,
-        args_config_cmd["args"],
-        null_logger,
+def test_write_out_failed_scrapes(output_args):
+    """Test write_out_failed_scrapes when args.output is sys.STDOUT"""
+    file_io.write_out_failed_scrapes(
+        ["url_1 - message", "url_2 - fail reason"],
+        "time_stamp",
+        output_args["args"],
     )
 
 
-# test write_out_df()
+# test write_out_failed_proteins()
 
 
-def test_writing_named_df_f_true(testing_df, null_logger, making_output_dir):
-    """Tests function for writing out a prenamed dataframe"""
-    file_io.write_out_df(
-        testing_df, "test_writing_df.csv", making_output_dir, null_logger, True
-    )
-
-
-def test_writing_named_df_f_false(testing_df, null_logger, making_output_dir):
-    """Tests function for writing out a prenamed dataframe"""
-    file_io.write_out_df(
-        testing_df, "test_writing_df.csv", making_output_dir, null_logger, False
+def test_write_out_failed_proteins_stdout(stdout_args):
+    """Test write_out_failed_proteins when args.output is sys.STDOUT"""
+    file_io.write_out_failed_proteins(
+        ["sql_1 - message", "sql_2 - fail reason"],
+        "time_stamp",
+        stdout_args["args"],
     )
 
 
-def test_writing_df_exists(testing_df, null_logger, making_output_dir):
-    """Tests function for writing out a prenamed dataframe"""
-    file_io.write_out_df(
-        testing_df, "test_writing_existing_df", making_output_dir, null_logger, True
+def test_write_out_failed_proteins(output_args):
+    """Test write_out_failed_proteins when args.output is sys.STDOUT"""
+    file_io.write_out_failed_proteins(
+        ["sql_1 - message", "sql_2 - fail reason"],
+        "time_stamp",
+        output_args["args"],
     )
 
 
-# test write_out_failed_scrapes
+# test writing out FASTA files
 
 
-def test_write_out_failed_scrapes_stdout(stdout_args, null_logger):
-    """Test write_out_failed_scrapes when args.output is sys.STDOUT"""
-    file_io.write_out_failed_scrapes(
-        ["url_1 - message", "url_2 - fail reason"],
-        "time_stamp",
-        stdout_args["args"],
-        null_logger,
-    )
-
-
-def test_write_out_failed_scrapes(output_args, null_logger):
-    """Test write_out_failed_scrapes when args.output is sys.STDOUT"""
-    file_io.write_out_failed_scrapes(
-        ["url_1 - message", "url_2 - fail reason"],
-        "time_stamp",
-        output_args["args"],
-        null_logger,
+def test_write_out_fasta(making_output_dir):
+    """Test writing out FASTA file."""
+    path_ = making_output_dir / "fasta_test"
+    file_io.make_output_directory(path_, True, True)
+    genbank_accession = "test_accession"
+    record = SeqRecord(
+        Seq("MKQHKAMIVALIVTAVVAALVTRKDLCEHIRTGQTEVAVAVF"),
+        id="fake_protein.1",
+        name="fake",
+        description="test protein record",
     )
+    args = {"args": Namespace(write=path_)}
+    file_io.write_out_fasta(record, genbank_accession, args["args"])
+    shutil.rmtree(path_)
diff --git a/tests/test_inputs/test_inputs_crawler/cazy_classpage.html b/tests/test_inputs/test_inputs_crawler/cazy_classpage.html
index 726a8a3a..34d93569 100644
--- a/tests/test_inputs/test_inputs_crawler/cazy_classpage.html
+++ b/tests/test_inputs/test_inputs_crawler/cazy_classpage.html
@@ -43,21 +43,21 @@
 <script src="prive/javascript/ajaxCallback.js" type="text/javascript"></script>
 
 <script src="prive/javascript/jquery.cookie.js" type="text/javascript"></script>
-<script type="text/javascript">/*<![CDATA[*/
-var _gaq = _gaq || [];
-_gaq.push(["_setAccount", "UA-12604774-1"]);
-_gaq.push(["_trackPageview"]);
-(function() {
-	var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;
-	ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
-	var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);
-})();
+<script type="text/javascript">/*<![CDATA[*/
+var _gaq = _gaq || [];
+_gaq.push(["_setAccount", "UA-12604774-1"]);
+_gaq.push(["_trackPageview"]);
+(function() {
+	var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;
+	ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
+	var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);
+})();
 /*]]>*/</script>
-<script type="text/javascript">/* <![CDATA[ */
-var box_settings = {tt_img:true,sel_g:"#documents_portfolio a[type='image/jpeg'],#documents_portfolio a[type='image/png'],#documents_portfolio a[type='image/gif']",sel_c:".mediabox",trans:"elastic",speed:"200",ssSpeed:"2500",maxW:"90%",maxH:"90%",minW:"400px",minH:"",opa:"0.9",str_ssStart:"Diaporama",str_ssStop:"Arrêter",str_cur:"{current}/{total}",str_prev:"Précédent",str_next:"Suivant",str_close:"Fermer",splash_url:""};
+<script type="text/javascript">/* <![CDATA[ */
+var box_settings = {tt_img:true,sel_g:"#documents_portfolio a[type='image/jpeg'],#documents_portfolio a[type='image/png'],#documents_portfolio a[type='image/gif']",sel_c:".mediabox",trans:"elastic",speed:"200",ssSpeed:"2500",maxW:"90%",maxH:"90%",minW:"400px",minH:"",opa:"0.9",str_ssStart:"Diaporama",str_ssStop:"Arrêter",str_cur:"{current}/{total}",str_prev:"Précédent",str_next:"Suivant",str_close:"Fermer",splash_url:""};
 /* ]]> */</script>
-<!-- insert_head_css --><link rel="stylesheet" href="plugins-dist/mediabox/colorbox/black-striped/colorbox.css" type="text/css" media="all" /><!-- insert_head -->
-	<script src="plugins-dist/mediabox/javascript/jquery.colorbox.js?1337524663" type="text/javascript"></script>
+<!-- insert_head_css --><link rel="stylesheet" href="plugins-dist/mediabox/colorbox/black-striped/colorbox.css" type="text/css" media="all" /><!-- insert_head -->
+	<script src="plugins-dist/mediabox/javascript/jquery.colorbox.js?1337524663" type="text/javascript"></script>
 	<script src="plugins-dist/mediabox/javascript/spip.mediabox.js?1337524663" type="text/javascript"></script><link rel='stylesheet' type='text/css' media='all' href='plugins-dist/porte_plume/css/barre_outils.css' />
 <link rel='stylesheet' type='text/css' media='all' href='spip.php?page=barre_outils_icones.css' />
 <script type='text/javascript' src='plugins-dist/porte_plume/javascript/jquery.markitup_pour_spip.js'></script>
@@ -219,7 +219,7 @@ <h1 class="crayon article-titre-3 entry-title">Glycoside Hydrolase family classi
 </div>
 <div class="paragraphe"><h3 class="spip">Tables for Direct Access</h3>
 <p><img src="local/cache-vignettes/L8xH11/puce-cebf5.gif" width='8' height='11' class='puce' alt="-" style='' />&nbsp;<strong>GH Family Number</strong></p>
-<table><tr><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH1.html">1</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH2.html">2</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH3.html">3</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH4.html">4</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH5.html">5</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH6.html">6</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH7.html">7</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH8.html">8</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH9.html">9</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH10.html">10</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH11.html">11</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH12.html">12</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH13.html">13</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH14.html">14</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH15.html">15</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH16.html">16</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH17.html">17</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH18.html">18</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH19.html">19</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH20.html">20</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH21.html">21</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH22.html">22</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH23.html">23</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH24.html">24</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH25.html">25</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH26.html">26</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH27.html">27</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH28.html">28</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH29.html">29</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH30.html">30</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH31.html">31</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH32.html">32</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH33.html">33</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH34.html">34</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH35.html">35</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH36.html">36</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH37.html">37</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH38.html">38</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH39.html">39</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH40.html">40</a></td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH41.html">41</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH42.html">42</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH43.html">43</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH44.html">44</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH45.html">45</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH46.html">46</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH47.html">47</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH48.html">48</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH49.html">49</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH50.html">50</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH51.html">51</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH52.html">52</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH53.html">53</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH54.html">54</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH55.html">55</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH56.html">56</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH57.html">57</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH58.html">58</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH59.html">59</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH60.html">60</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH61.html">61</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH62.html">62</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH63.html">63</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH64.html">64</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH65.html">65</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH66.html">66</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH67.html">67</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH68.html">68</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH69.html">69</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH70.html">70</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH71.html">71</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH72.html">72</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH73.html">73</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH74.html">74</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH75.html">75</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH76.html">76</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH77.html">77</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH78.html">78</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH79.html">79</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH80.html">80</a></td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH81.html">81</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH82.html">82</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH83.html">83</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH84.html">84</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH85.html">85</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH86.html">86</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH87.html">87</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH88.html">88</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH89.html">89</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH90.html">90</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH91.html">91</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH92.html">92</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH93.html">93</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH94.html">94</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH95.html">95</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH96.html">96</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH97.html">97</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH98.html">98</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH99.html">99</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH100.html">100</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH101.html">101</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH102.html">102</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH103.html">103</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH104.html">104</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH105.html">105</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH106.html">106</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH107.html">107</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH108.html">108</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH109.html">109</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH110.html">110</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH111.html">111</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH112.html">112</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH113.html">113</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH114.html">114</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH115.html">115</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH116.html">116</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH117.html">117</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH118.html">118</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH119.html">119</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH120.html">120</a></td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH121.html">121</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH122.html">122</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH123.html">123</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH124.html">124</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH125.html">125</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH126.html">126</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH127.html">127</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH128.html">128</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH129.html">129</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH130.html">130</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH131.html">131</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH132.html">132</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH133.html">133</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH134.html">134</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH135.html">135</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH136.html">136</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH137.html">137</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH138.html">138</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH139.html">139</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH140.html">140</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH141.html">141</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH142.html">142</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH143.html">143</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH144.html">144</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH145.html">145</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH146.html">146</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH147.html">147</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH148.html">148</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH149.html">149</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH150.html">150</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH151.html">151</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH152.html">152</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH153.html">153</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH154.html">154</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH155.html">155</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH156.html">156</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH157.html">157</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH158.html">158</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH159.html">159</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH160.html">160</a></td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH161.html">161</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH162.html">162</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH163.html">163</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH164.html">164</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH165.html">165</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH166.html">166</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH167.html">167</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH168.html">168</a></td></tr></table><table><tr><td style="padding-left:15px;"><a href="GH0.html">Non-Classified Sequences</a></td></tr></table>
+<table><tr><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH1.html">1</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH2aaa.html">2</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH3.html">3</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH4.html">4</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH5.html">5</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH6.html">6</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH7.html">7</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH8.html">8</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH9.html">9</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH10.html">10</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH11.html">11</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH12.html">12</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH13.html">13</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH14.html">14</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH15.html">15</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH16.html">16</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH17.html">17</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH18.html">18</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH19.html">19</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH20.html">20</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH21.html">21</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH22.html">22</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH23.html">23</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH24.html">24</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH25.html">25</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH26.html">26</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH27.html">27</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH28.html">28</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH29.html">29</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH30.html">30</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH31.html">31</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH32.html">32</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH33.html">33</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH34.html">34</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH35.html">35</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH36.html">36</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH37.html">37</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH38.html">38</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH39.html">39</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH40.html">40</a></td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH41.html">41</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH42.html">42</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH43.html">43</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH44.html">44</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH45.html">45</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH46.html">46</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH47.html">47</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH48.html">48</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH49.html">49</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH50.html">50</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH51.html">51</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH52.html">52</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH53.html">53</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH54.html">54</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH55.html">55</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH56.html">56</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH57.html">57</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH58.html">58</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH59.html">59</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH60.html">60</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH61.html">61</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH62.html">62</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH63.html">63</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH64.html">64</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH65.html">65</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH66.html">66</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH67.html">67</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH68.html">68</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH69.html">69</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH70.html">70</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH71.html">71</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH72.html">72</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH73.html">73</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH74.html">74</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH75.html">75</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH76.html">76</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH77.html">77</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH78.html">78</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH79.html">79</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH80.html">80</a></td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH81.html">81</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH82.html">82</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH83.html">83</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH84.html">84</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH85.html">85</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH86.html">86</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH87.html">87</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH88.html">88</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH89.html">89</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH90.html">90</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH91.html">91</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH92.html">92</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH93.html">93</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH94.html">94</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH95.html">95</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH96.html">96</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH97.html">97</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH98.html">98</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH99.html">99</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH100.html">100</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH101.html">101</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH102.html">102</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH103.html">103</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH104.html">104</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH105.html">105</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH106.html">106</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH107.html">107</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH108.html">108</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH109.html">109</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH110.html">110</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH111.html">111</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH112.html">112</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH113.html">113</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH114.html">114</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH115.html">115</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH116.html">116</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH117.html">117</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH118.html">118</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH119.html">119</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH120.html">120</a></td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH121.html">121</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH122.html">122</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH123.html">123</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH124.html">124</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH125.html">125</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH126.html">126</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH127.html">127</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH128.html">128</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH129.html">129</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH130.html">130</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH131.html">131</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH132.html">132</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH133.html">133</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH134.html">134</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH135.html">135</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH136.html">136</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH137.html">137</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH138.html">138</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH139.html">139</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH140.html">140</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH141.html">141</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH142.html">142</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH143.html">143</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH144.html">144</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH145.html">145</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH146.html">146</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH147.html">147</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH148.html">148</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH149.html">149</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH150.html">150</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH151.html">151</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH152.html">152</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH153.html">153</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH154.html">154</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH155.html">155</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH156.html">156</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH157.html">157</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH158.html">158</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH159.html">159</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH160.html">160</a></td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH161.html">161</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH162.html">162</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH163.html">163</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH164.html">164</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH165.html">165</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH166.html">166</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH167.html">167</a></td><td width="30" align="right" style="background-color:#F0F8FF;"><a href="GH168.html">168</a></td></tr></table><table><tr><td style="padding-left:15px;"><a href="GH0.html">Non-Classified Sequences</a></td></tr></table>
 <p><img src="local/cache-vignettes/L8xH11/puce-cebf5.gif" width='8' height='11' class='puce' alt="-" style='' />&nbsp;<strong>GH SubFamily Number</strong></p>
 <table  border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">GH5</th><td width="15" class="ec"  align="center"><a id="separ_subfam" href="GH5_1.html">1</a><a id="separ_subfam" href="GH5_2.html">2</a><a id="separ_subfam" href="GH5_4.html">4</a><a id="separ_subfam" href="GH5_5.html">5</a><a id="separ_subfam" href="GH5_7.html">7</a><a id="separ_subfam" href="GH5_8.html">8</a><a id="separ_subfam" href="GH5_9.html">9</a><a id="separ_subfam" href="GH5_10.html">10</a><a id="separ_subfam" href="GH5_11.html">11</a><a id="separ_subfam" href="GH5_12.html">12</a><a id="separ_subfam" href="GH5_13.html">13</a><a id="separ_subfam" href="GH5_14.html">14</a><a id="separ_subfam" href="GH5_15.html">15</a><a id="separ_subfam" href="GH5_16.html">16</a><a id="separ_subfam" href="GH5_17.html">17</a><a id="separ_subfam" href="GH5_18.html">18</a><a id="separ_subfam" href="GH5_19.html">19</a><a id="separ_subfam" href="GH5_20.html">20</a><a id="separ_subfam" href="GH5_21.html">21</a><a id="separ_subfam" href="GH5_22.html">22</a><a id="separ_subfam" href="GH5_23.html">23</a><a id="separ_subfam" href="GH5_24.html">24</a><a id="separ_subfam" href="GH5_25.html">25</a><a id="separ_subfam" href="GH5_26.html">26</a><a id="separ_subfam" href="GH5_27.html">27</a><a id="separ_subfam" href="GH5_28.html">28</a><a id="separ_subfam" href="GH5_29.html">29</a><a id="separ_subfam" href="GH5_30.html">30</a><a id="separ_subfam" href="GH5_31.html">31</a><a id="separ_subfam" href="GH5_32.html">32</a><a id="separ_subfam" href="GH5_33.html">33</a><a id="separ_subfam" href="GH5_34.html">34</a><a id="separ_subfam" href="GH5_35.html">35</a><a id="separ_subfam" href="GH5_36.html">36</a><a id="separ_subfam" href="GH5_37.html">37</a><a id="separ_subfam" href="GH5_38.html">38</a><a id="separ_subfam" href="GH5_39.html">39</a><a id="separ_subfam" href="GH5_40.html">40</a><a id="separ_subfam" href="GH5_41.html">41</a><a id="separ_subfam" href="GH5_42.html">42</a><a id="separ_subfam" href="GH5_43.html">43</a><a id="separ_subfam" href="GH5_44.html">44</a><a id="separ_subfam" href="GH5_45.html">45</a><a id="separ_subfam" href="GH5_46.html">46</a><a id="separ_subfam" href="GH5_47.html">47</a><a id="separ_subfam" href="GH5_48.html">48</a><a id="separ_subfam" href="GH5_49.html">49</a><a id="separ_subfam" href="GH5_50.html">50</a><a id="separ_subfam" href="GH5_51.html">51</a><a id="separ_subfam" href="GH5_52.html">52</a><a id="separ_subfam" href="GH5_53.html">53</a><a id="separ_subfam" href="GH5_54.html">54</a><a id="separ_subfam" href="GH5_55.html">55</a><a id="separ_subfam" href="GH5_56.html">56</a></td></tr></table><table  border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">GH13</th><td width="15" class="ec"  align="center"><a id="separ_subfam" href="GH13_1.html">1</a><a id="separ_subfam" href="GH13_2.html">2</a><a id="separ_subfam" href="GH13_3.html">3</a><a id="separ_subfam" href="GH13_4.html">4</a><a id="separ_subfam" href="GH13_5.html">5</a><a id="separ_subfam" href="GH13_6.html">6</a><a id="separ_subfam" href="GH13_7.html">7</a><a id="separ_subfam" href="GH13_8.html">8</a><a id="separ_subfam" href="GH13_9.html">9</a><a id="separ_subfam" href="GH13_10.html">10</a><a id="separ_subfam" href="GH13_11.html">11</a><a id="separ_subfam" href="GH13_12.html">12</a><a id="separ_subfam" href="GH13_13.html">13</a><a id="separ_subfam" href="GH13_14.html">14</a><a id="separ_subfam" href="GH13_15.html">15</a><a id="separ_subfam" href="GH13_16.html">16</a><a id="separ_subfam" href="GH13_17.html">17</a><a id="separ_subfam" href="GH13_18.html">18</a><a id="separ_subfam" href="GH13_19.html">19</a><a id="separ_subfam" href="GH13_20.html">20</a><a id="separ_subfam" href="GH13_21.html">21</a><a id="separ_subfam" href="GH13_22.html">22</a><a id="separ_subfam" href="GH13_23.html">23</a><a id="separ_subfam" href="GH13_24.html">24</a><a id="separ_subfam" href="GH13_25.html">25</a><a id="separ_subfam" href="GH13_26.html">26</a><a id="separ_subfam" href="GH13_27.html">27</a><a id="separ_subfam" href="GH13_28.html">28</a><a id="separ_subfam" href="GH13_29.html">29</a><a id="separ_subfam" href="GH13_30.html">30</a><a id="separ_subfam" href="GH13_31.html">31</a><a id="separ_subfam" href="GH13_32.html">32</a><a id="separ_subfam" href="GH13_33.html">33</a><a id="separ_subfam" href="GH13_34.html">34</a><a id="separ_subfam" href="GH13_35.html">35</a><a id="separ_subfam" href="GH13_36.html">36</a><a id="separ_subfam" href="GH13_37.html">37</a><a id="separ_subfam" href="GH13_38.html">38</a><a id="separ_subfam" href="GH13_39.html">39</a><a id="separ_subfam" href="GH13_40.html">40</a><a id="separ_subfam" href="GH13_41.html">41</a><a id="separ_subfam" href="GH13_42.html">42</a></td></tr></table><table  border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">GH16</th><td width="15" class="ec"  align="center"><a id="separ_subfam" href="GH16_1.html">1</a><a id="separ_subfam" href="GH16_2.html">2</a><a id="separ_subfam" href="GH16_3.html">3</a><a id="separ_subfam" href="GH16_4.html">4</a><a id="separ_subfam" href="GH16_5.html">5</a><a id="separ_subfam" href="GH16_6.html">6</a><a id="separ_subfam" href="GH16_7.html">7</a><a id="separ_subfam" href="GH16_8.html">8</a><a id="separ_subfam" href="GH16_9.html">9</a><a id="separ_subfam" href="GH16_10.html">10</a><a id="separ_subfam" href="GH16_11.html">11</a><a id="separ_subfam" href="GH16_12.html">12</a><a id="separ_subfam" href="GH16_13.html">13</a><a id="separ_subfam" href="GH16_14.html">14</a><a id="separ_subfam" href="GH16_15.html">15</a><a id="separ_subfam" href="GH16_16.html">16</a><a id="separ_subfam" href="GH16_17.html">17</a><a id="separ_subfam" href="GH16_18.html">18</a><a id="separ_subfam" href="GH16_19.html">19</a><a id="separ_subfam" href="GH16_20.html">20</a><a id="separ_subfam" href="GH16_21.html">21</a><a id="separ_subfam" href="GH16_22.html">22</a><a id="separ_subfam" href="GH16_23.html">23</a><a id="separ_subfam" href="GH16_24.html">24</a><a id="separ_subfam" href="GH16_25.html">25</a><a id="separ_subfam" href="GH16_26.html">26</a><a id="separ_subfam" href="GH16_27.html">27</a></td></tr></table><table  border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">GH30</th><td width="15" class="ec"  align="center"><a id="separ_subfam" href="GH30_1.html">1</a><a id="separ_subfam" href="GH30_2.html">2</a><a id="separ_subfam" href="GH30_3.html">3</a><a id="separ_subfam" href="GH30_4.html">4</a><a id="separ_subfam" href="GH30_5.html">5</a><a id="separ_subfam" href="GH30_6.html">6</a><a id="separ_subfam" href="GH30_7.html">7</a><a id="separ_subfam" href="GH30_8.html">8</a><a id="separ_subfam" href="GH30_9.html">9</a></td></tr></table><table  border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">GH43</th><td width="15" class="ec"  align="center"><a id="separ_subfam" href="GH43_1.html">1</a><a id="separ_subfam" href="GH43_2.html">2</a><a id="separ_subfam" href="GH43_3.html">3</a><a id="separ_subfam" href="GH43_4.html">4</a><a id="separ_subfam" href="GH43_5.html">5</a><a id="separ_subfam" href="GH43_6.html">6</a><a id="separ_subfam" href="GH43_7.html">7</a><a id="separ_subfam" href="GH43_8.html">8</a><a id="separ_subfam" href="GH43_9.html">9</a><a id="separ_subfam" href="GH43_10.html">10</a><a id="separ_subfam" href="GH43_11.html">11</a><a id="separ_subfam" href="GH43_12.html">12</a><a id="separ_subfam" href="GH43_13.html">13</a><a id="separ_subfam" href="GH43_14.html">14</a><a id="separ_subfam" href="GH43_15.html">15</a><a id="separ_subfam" href="GH43_16.html">16</a><a id="separ_subfam" href="GH43_17.html">17</a><a id="separ_subfam" href="GH43_18.html">18</a><a id="separ_subfam" href="GH43_19.html">19</a><a id="separ_subfam" href="GH43_20.html">20</a><a id="separ_subfam" href="GH43_21.html">21</a><a id="separ_subfam" href="GH43_22.html">22</a><a id="separ_subfam" href="GH43_23.html">23</a><a id="separ_subfam" href="GH43_24.html">24</a><a id="separ_subfam" href="GH43_25.html">25</a><a id="separ_subfam" href="GH43_26.html">26</a><a id="separ_subfam" href="GH43_27.html">27</a><a id="separ_subfam" href="GH43_28.html">28</a><a id="separ_subfam" href="GH43_29.html">29</a><a id="separ_subfam" href="GH43_30.html">30</a><a id="separ_subfam" href="GH43_31.html">31</a><a id="separ_subfam" href="GH43_32.html">32</a><a id="separ_subfam" href="GH43_33.html">33</a><a id="separ_subfam" href="GH43_34.html">34</a><a id="separ_subfam" href="GH43_35.html">35</a><a id="separ_subfam" href="GH43_36.html">36</a><a id="separ_subfam" href="GH43_37.html">37</a></td></tr></table>
 <p><img src="local/cache-vignettes/L8xH11/puce-cebf5.gif" width='8' height='11' class='puce' alt="-" style='' />&nbsp;<strong>GH Classification Statistics</strong></p>
diff --git a/tests/test_inputs/test_inputs_crawler/cazy_classpage_no_fams.html b/tests/test_inputs/test_inputs_crawler/cazy_classpage_no_fams.html
new file mode 100644
index 00000000..db153c87
--- /dev/null
+++ b/tests/test_inputs/test_inputs_crawler/cazy_classpage_no_fams.html
@@ -0,0 +1,304 @@
+
+
+
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr" dir="ltr">
+<head>
+<title>CAZy - GH</title>
+<meta name="description" content=" Introduction Glycoside hydrolases (EC 3.2.1.-) are a widespread group of enzymes which hydrolyse the glycosidic bond between two or more (...) " />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+
+<meta name="generator" content="SPIP 3.0.1 [19436]" />
+
+
+<link rel="alternate" type="application/rss+xml" title="Syndiquer tout le site" href="spip.php?page=backend" />
+
+
+<link rel="stylesheet" href="squelettes/css/section.css" type="text/css" media="projection, screen, tv" />
+
+
+<link rel="stylesheet" href="squelettes/css/main.css" type="text/css" media="projection, screen, tv" />
+
+
+<link rel="shortcut icon" type="image/x-icon" href="squelettes/images/cazy.ico" />
+
+
+<script type="text/javascript" src="squelettes/js/canevas.js"></script />
+
+
+
+="http://www.cazy.org/"><div class="logo_link"></div><
+
+
+<script src="prive/javascript/jquery.js" type="text/javascript"></script>
+
+<script src="prive/javascript/jquery.form.js" type="text/javascript"></script>
+
+<script src="prive/javascript/jquery.autosave.js" type="text/javascript"></script>
+
+<script src="prive/javascript/jquery.placeholder-label.js" type="text/javascript"></script>
+
+<script src="prive/javascript/ajaxCallback.js" type="text/javascript"></script>
+
+<script src="prive/javascript/jquery.cookie.js" type="text/javascript"></script>
+<script type="text/javascript">/*<![CDATA[*/
+var _gaq = _gaq || [];
+_gaq.push(["_setAccount", "UA-12604774-1"]);
+_gaq.push(["_trackPageview"]);
+(function() {
+	var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;
+	ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
+	var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);
+})();
+/*]]>*/</script>
+<script type="text/javascript">/* <![CDATA[ */
+var box_settings = {tt_img:true,sel_g:"#documents_portfolio a[type='image/jpeg'],#documents_portfolio a[type='image/png'],#documents_portfolio a[type='image/gif']",sel_c:".mediabox",trans:"elastic",speed:"200",ssSpeed:"2500",maxW:"90%",maxH:"90%",minW:"400px",minH:"",opa:"0.9",str_ssStart:"Diaporama",str_ssStop:"Arrêter",str_cur:"{current}/{total}",str_prev:"Précédent",str_next:"Suivant",str_close:"Fermer",splash_url:""};
+/* ]]> */</script>
+<!-- insert_head_css --><link rel="stylesheet" href="plugins-dist/mediabox/colorbox/black-striped/colorbox.css" type="text/css" media="all" /><!-- insert_head -->
+	<script src="plugins-dist/mediabox/javascript/jquery.colorbox.js?1337524663" type="text/javascript"></script>
+	<script src="plugins-dist/mediabox/javascript/spip.mediabox.js?1337524663" type="text/javascript"></script><link rel='stylesheet' type='text/css' media='all' href='plugins-dist/porte_plume/css/barre_outils.css' />
+<link rel='stylesheet' type='text/css' media='all' href='spip.php?page=barre_outils_icones.css' />
+<script type='text/javascript' src='plugins-dist/porte_plume/javascript/jquery.markitup_pour_spip.js'></script>
+<script type='text/javascript' src='plugins-dist/porte_plume/javascript/jquery.previsu_spip.js'></script>
+<script type='text/javascript' src='spip.php?page=porte_plume_start.js&amp;lang=fr'></script>
+
+<!-- CS vide -->
+
+
+<!-- Debut CS -->
+<script type="text/javascript"><!--
+var cs_prive=window.location.pathname.match(/\/ecrire\/$/)!=null;
+jQuery.fn.cs_todo=function(){return this.not('.cs_done').addClass('cs_done');};
+var cs_init = function() {
+	if(window.location.search.match(/page=forum/)!=null) jQuery("legend:contains('Vorgeschaltete Moderation')", this).next().html('Ce forum est modéré à priori : votre contribution n\'apparaîtra qu\'après avoir été validée par un administrateur du site, sauf si vous êtes identifié et autorisé à poster directement.');
+}
+if(typeof onAjaxLoad=='function') onAjaxLoad(cs_init);
+if(window.jQuery) {
+var cs_sel_jQuery=typeof jQuery(document).selector=='undefined'?'@':'';
+var cs_CookiePlugin="prive/javascript/jquery.cookie.js";
+jQuery(document).ready(function(){
+	cs_init.apply(document);
+});
+}
+// --></script>
+
+<!-- Fin CS --></head>
+
+<body onLoad="encours('ezcl')" class="bkg">
+
+
+
+<!-- cadre_haut -->
+<div class="cadre_haut"> 
+
+<div class="cadre_menu"><!-- cadre_menu -->
+
+<div onmouseout="MouseOutDeclencheSablier()" class="Menu">
+<span  id="inactif" onmouseover="MouseOverMenu(this,'home','ezcl')"><b>="Welcome-to-the-Carbohydrate-Active.html" class="linkmenu">Home<</b></span>
+<span  id="encours" onmouseover="MouseOverMenu(this,'ezcl','ezcl')"><b>Enzyme Classes</b></span>
+<span  id="inactif" onmouseover="MouseOverMenu(this,'amod','ezcl')"><b>Associated Modules</b></span>
+<span  id="inactif" onmouseover="MouseOverMenu(this,'gnom','ezcl')"><b>Genomes</b></span>
+</div>
+</div><!-- cadre_menu -->
+
+<div class="cadre_sousmenu"><!-- cadre_sousmenu -->
+
+<!-- sousmenu1 -->
+<div onmouseout="MouseOutDeclencheSablier()" onmouseover="MouseOverArretSablier()" id="home" class="SousMenuLine">
+&nbsp;
+</div>
+
+<!-- sousmenu2 -->
+<div onmouseout="MouseOutDeclencheSablier()" onmouseover="MouseOverArretSablier()" id="ezcl" class="SousMenuLine">
+="Glycoside-Hydrolases.html"  id="actif">Glycoside Hydrolases<
+="GlycosylTransferases.html">GlycosylTransferases<
+="Polysaccharide-Lyases.html">Polysaccharide Lyases<
+="Carbohydrate-Esterases.html">Carbohydrate Esterases<
+="Auxiliary-Activities.html">Auxiliary Activities<
+</div>
+
+<!-- sousmenu3 -->
+<div onmouseout="MouseOutDeclencheSablier()" onmouseover="MouseOverArretSablier()" id="amod" class="SousMenuLine">
+="Carbohydrate-Binding-Modules.html">Carbohydrate-Binding Modules<<font id="confort">&nbsp;</font>
+</div>
+
+<!-- sousmenu4 -->
+<div onmouseout="MouseOutDeclencheSablier()" onmouseover="MouseOverArretSablier()" id="gnom" class="SousMenuLine">
+="Genomes.html">Introduction<
+="http://www.cazy.org/a.html">Archaea<
+="http://www.cazy.org/b.html">Bacteria<
+="http://www.cazy.org/e.html">Eukaryota<
+="http://www.cazy.org/v.html">Viruses<<font id="confort">&nbsp;</font>
+</div>
+
+</div><!-- cadre_sousmenu --> 
+
+
+</div><!-- cadre_haut -->
+
+<!-- cadre_principal -->
+<div class="cadre_principal">
+
+    <!-- volet_gauche -->
+    <div class="volet_gauche"> 
+    </div>
+    <!-- volet_gauche -->
+
+
+    <!-- volet_droit -->
+    <div class="volet_droit">
+    </div>
+    <!-- volet_droit -->
+
+
+    <!-- volet_central -->
+    <div class="volet_central">
+      
+    
+     <div align="right"><div style="position:absolute;right:350px;"><form name="nextpage"><select name="cazypage" onchange="document.location.href='' + this.options[this.selectedIndex].value + '' ">
+    <option value="http://www.cazy.org/GH1.html">GH1</option><option value="http://www.cazy.org/GH2.html">GH2</option><option value="http://www.cazy.org/GH3.html">GH3</option><option value="http://www.cazy.org/GH4.html">GH4</option><option value="http://www.cazy.org/GH5.html">GH5</option><option value="http://www.cazy.org/GH6.html">GH6</option><option value="http://www.cazy.org/GH7.html">GH7</option><option value="http://www.cazy.org/GH8.html">GH8</option><option value="http://www.cazy.org/GH9.html">GH9</option><option value="http://www.cazy.org/GH10.html">GH10</option><option value="http://www.cazy.org/GH11.html">GH11</option><option value="http://www.cazy.org/GH12.html">GH12</option><option value="http://www.cazy.org/GH13.html">GH13</option><option value="http://www.cazy.org/GH14.html">GH14</option><option value="http://www.cazy.org/GH15.html">GH15</option><option value="http://www.cazy.org/GH16.html">GH16</option><option value="http://www.cazy.org/GH17.html">GH17</option><option value="http://www.cazy.org/GH18.html">GH18</option><option value="http://www.cazy.org/GH19.html">GH19</option><option value="http://www.cazy.org/GH20.html">GH20</option><option value="http://www.cazy.org/GH21.html">GH21</option><option value="http://www.cazy.org/GH22.html">GH22</option><option value="http://www.cazy.org/GH23.html">GH23</option><option value="http://www.cazy.org/GH24.html">GH24</option><option value="http://www.cazy.org/GH25.html">GH25</option><option value="http://www.cazy.org/GH26.html">GH26</option><option value="http://www.cazy.org/GH27.html">GH27</option><option value="http://www.cazy.org/GH28.html">GH28</option><option value="http://www.cazy.org/GH29.html">GH29</option><option value="http://www.cazy.org/GH30.html">GH30</option><option value="http://www.cazy.org/GH31.html">GH31</option><option value="http://www.cazy.org/GH32.html">GH32</option><option value="http://www.cazy.org/GH33.html">GH33</option><option value="http://www.cazy.org/GH34.html">GH34</option><option value="http://www.cazy.org/GH35.html">GH35</option><option value="http://www.cazy.org/GH36.html">GH36</option><option value="http://www.cazy.org/GH37.html">GH37</option><option value="http://www.cazy.org/GH38.html">GH38</option><option value="http://www.cazy.org/GH39.html">GH39</option><option value="http://www.cazy.org/GH40.html">GH40</option><option value="http://www.cazy.org/GH41.html">GH41</option><option value="http://www.cazy.org/GH42.html">GH42</option><option value="http://www.cazy.org/GH43.html">GH43</option><option value="http://www.cazy.org/GH44.html">GH44</option><option value="http://www.cazy.org/GH45.html">GH45</option><option value="http://www.cazy.org/GH46.html">GH46</option><option value="http://www.cazy.org/GH47.html">GH47</option><option value="http://www.cazy.org/GH48.html">GH48</option><option value="http://www.cazy.org/GH49.html">GH49</option><option value="http://www.cazy.org/GH50.html">GH50</option><option value="http://www.cazy.org/GH51.html">GH51</option><option value="http://www.cazy.org/GH52.html">GH52</option><option value="http://www.cazy.org/GH53.html">GH53</option><option value="http://www.cazy.org/GH54.html">GH54</option><option value="http://www.cazy.org/GH55.html">GH55</option><option value="http://www.cazy.org/GH56.html">GH56</option><option value="http://www.cazy.org/GH57.html">GH57</option><option value="http://www.cazy.org/GH58.html">GH58</option><option value="http://www.cazy.org/GH59.html">GH59</option><option value="http://www.cazy.org/GH60.html">GH60</option><option value="http://www.cazy.org/GH61.html">GH61</option><option value="http://www.cazy.org/GH62.html">GH62</option><option value="http://www.cazy.org/GH63.html">GH63</option><option value="http://www.cazy.org/GH64.html">GH64</option><option value="http://www.cazy.org/GH65.html">GH65</option><option value="http://www.cazy.org/GH66.html">GH66</option><option value="http://www.cazy.org/GH67.html">GH67</option><option value="http://www.cazy.org/GH68.html">GH68</option><option value="http://www.cazy.org/GH69.html">GH69</option><option value="http://www.cazy.org/GH70.html">GH70</option><option value="http://www.cazy.org/GH71.html">GH71</option><option value="http://www.cazy.org/GH72.html">GH72</option><option value="http://www.cazy.org/GH73.html">GH73</option><option value="http://www.cazy.org/GH74.html">GH74</option><option value="http://www.cazy.org/GH75.html">GH75</option><option value="http://www.cazy.org/GH76.html">GH76</option><option value="http://www.cazy.org/GH77.html">GH77</option><option value="http://www.cazy.org/GH78.html">GH78</option><option value="http://www.cazy.org/GH79.html">GH79</option><option value="http://www.cazy.org/GH80.html">GH80</option><option value="http://www.cazy.org/GH81.html">GH81</option><option value="http://www.cazy.org/GH82.html">GH82</option><option value="http://www.cazy.org/GH83.html">GH83</option><option value="http://www.cazy.org/GH84.html">GH84</option><option value="http://www.cazy.org/GH85.html">GH85</option><option value="http://www.cazy.org/GH86.html">GH86</option><option value="http://www.cazy.org/GH87.html">GH87</option><option value="http://www.cazy.org/GH88.html">GH88</option><option value="http://www.cazy.org/GH89.html">GH89</option><option value="http://www.cazy.org/GH90.html">GH90</option><option value="http://www.cazy.org/GH91.html">GH91</option><option value="http://www.cazy.org/GH92.html">GH92</option><option value="http://www.cazy.org/GH93.html">GH93</option><option value="http://www.cazy.org/GH94.html">GH94</option><option value="http://www.cazy.org/GH95.html">GH95</option><option value="http://www.cazy.org/GH96.html">GH96</option><option value="http://www.cazy.org/GH97.html">GH97</option><option value="http://www.cazy.org/GH98.html">GH98</option><option value="http://www.cazy.org/GH99.html">GH99</option><option value="http://www.cazy.org/GH100.html">GH100</option><option value="http://www.cazy.org/GH101.html">GH101</option><option value="http://www.cazy.org/GH102.html">GH102</option><option value="http://www.cazy.org/GH103.html">GH103</option><option value="http://www.cazy.org/GH104.html">GH104</option><option value="http://www.cazy.org/GH105.html">GH105</option><option value="http://www.cazy.org/GH106.html">GH106</option><option value="http://www.cazy.org/GH107.html">GH107</option><option value="http://www.cazy.org/GH108.html">GH108</option><option value="http://www.cazy.org/GH109.html">GH109</option><option value="http://www.cazy.org/GH110.html">GH110</option><option value="http://www.cazy.org/GH111.html">GH111</option><option value="http://www.cazy.org/GH112.html">GH112</option><option value="http://www.cazy.org/GH113.html">GH113</option><option value="http://www.cazy.org/GH114.html">GH114</option><option value="http://www.cazy.org/GH115.html">GH115</option><option value="http://www.cazy.org/GH116.html">GH116</option><option value="http://www.cazy.org/GH117.html">GH117</option><option value="http://www.cazy.org/GH118.html">GH118</option><option value="http://www.cazy.org/GH119.html">GH119</option><option value="http://www.cazy.org/GH120.html">GH120</option><option value="http://www.cazy.org/GH121.html">GH121</option><option value="http://www.cazy.org/GH122.html">GH122</option><option value="http://www.cazy.org/GH123.html">GH123</option><option value="http://www.cazy.org/GH124.html">GH124</option><option value="http://www.cazy.org/GH125.html">GH125</option><option value="http://www.cazy.org/GH126.html">GH126</option><option value="http://www.cazy.org/GH127.html">GH127</option><option value="http://www.cazy.org/GH128.html">GH128</option><option value="http://www.cazy.org/GH129.html">GH129</option><option value="http://www.cazy.org/GH130.html">GH130</option><option value="http://www.cazy.org/GH131.html">GH131</option><option value="http://www.cazy.org/GH132.html">GH132</option><option value="http://www.cazy.org/GH133.html">GH133</option><option value="http://www.cazy.org/GH134.html">GH134</option><option value="http://www.cazy.org/GH135.html">GH135</option><option value="http://www.cazy.org/GH136.html">GH136</option><option value="http://www.cazy.org/GH137.html">GH137</option><option value="http://www.cazy.org/GH138.html">GH138</option><option value="http://www.cazy.org/GH139.html">GH139</option><option value="http://www.cazy.org/GH140.html">GH140</option><option value="http://www.cazy.org/GH141.html">GH141</option><option value="http://www.cazy.org/GH142.html">GH142</option><option value="http://www.cazy.org/GH143.html">GH143</option><option value="http://www.cazy.org/GH144.html">GH144</option><option value="http://www.cazy.org/GH145.html">GH145</option><option value="http://www.cazy.org/GH146.html">GH146</option><option value="http://www.cazy.org/GH147.html">GH147</option><option value="http://www.cazy.org/GH148.html">GH148</option><option value="http://www.cazy.org/GH149.html">GH149</option><option value="http://www.cazy.org/GH150.html">GH150</option><option value="http://www.cazy.org/GH151.html">GH151</option><option value="http://www.cazy.org/GH152.html">GH152</option><option value="http://www.cazy.org/GH153.html">GH153</option><option value="http://www.cazy.org/GH154.html">GH154</option><option value="http://www.cazy.org/GH155.html">GH155</option><option value="http://www.cazy.org/GH156.html">GH156</option><option value="http://www.cazy.org/GH157.html">GH157</option><option value="http://www.cazy.org/GH158.html">GH158</option><option value="http://www.cazy.org/GH159.html">GH159</option><option value="http://www.cazy.org/GH160.html">GH160</option><option value="http://www.cazy.org/GH161.html">GH161</option><option value="http://www.cazy.org/GH162.html">GH162</option><option value="http://www.cazy.org/GH163.html">GH163</option><option value="http://www.cazy.org/GH164.html">GH164</option><option value="http://www.cazy.org/GH165.html">GH165</option><option value="http://www.cazy.org/GH166.html">GH166</option><option value="http://www.cazy.org/GH167.html">GH167</option><option value="http://www.cazy.org/GH168.html">GH168</option><option value="http://www.cazy.org/GH0.html">NC</option>
+     </select><input onclick="gothere()" value="Go" type="button" class="btn_deroul"></form></div><div><a name="formulaire_recherche" id="formulaire_recherche"><
+<form name="searchform" action="search" method="get" ENCTYPE="x-www-form-urlencoded">
+        <input name="page" value="recherche" type="hidden"
+/>
+        
+        <input type="text" class="forml" name="recherche" id="q" value="..." onfocus="this.value='';" />
+	 <select name="tag" id="tag">	
+	  <option value="11" >Family</option>	
+	  <option value="1" >Tax_id</option>
+	  <option value="2" >Organism name</option>
+	  <option value="3" >Protein name</option>	  
+	  <option value="4" >GenBank accession</option>
+	  <option value="10" >Uniprot accession</option>	  
+	  <option value="8" >PDB accession</option>
+	  <option value="12" >Carb_ligand</option>
+	  <option value="9" >EC number</option>	 	 	  
+	  <option value="5" >Known activities</option>
+	  <option value="6" >Mechanisms</option>
+	  <option value="7" >Clan</option>	
+	  <option value="">Site</option>
+	</select>
+	<input type="submit" class="bouton" value="Go"/>
+</form>
+
+
+
+
+
+</div></div>
+
+	  
+   	  
+	  <h1 class="crayon article-titre-3 entry-title">Glycoside Hydrolase family classification</h1>
+	  
+
+	  <div class="crayon article-texte-3 texte entry-content"><div class="paragraphe"><h3 class="spip">Introduction</h3>
+<p><strong>Glycoside hydrolases</strong> (EC 3.2.1.-) are a widespread group of enzymes which hydrolyse the glycosidic bond between two or more carbohydrates or between a carbohydrate and a non-carbohydrate moiety. The IUBMB Enzyme nomenclature of glycoside hydrolases is based on their substrate specificity and occasionally on their molecular mechanism&nbsp;; such a classification does not reflect (and was not intended to) the structural features of these enzymes. A classification of glycoside hydrolases in families based on amino acid sequence similarities has been proposed a few years ago. Because there is a direct relationship between sequence and folding similarities, such a classification&nbsp;:</p>
+
+<p>(i) reflects the structural features of these enzymes better than their sole substrate specificity,</p>
+
+<p>(ii) helps to reveal the evolutionary relationships between these enzymes,</p>
+
+<p>(iii) provides a convenient tool to derive mechanistic information<span class="spip_note_ref">&nbsp;[='#nb1' class='spip_note' rel='footnote' title='Henrissat B (1991) A classification of glycosyl hydrolases based on&nbsp;(...)' id='nh1'>1<]</span><span class="spip_note_ref">&nbsp;[='#nb2' class='spip_note' rel='footnote' title='Henrissat B, Bairoch A (1993) New families in the classification of&nbsp;(...)' id='nh2'>2<]</span></p>
+
+<p>(iv) illustrates the difficulty of deriving relationships between family membership and substrate specificity</p>
+
+<p> The Carbohydrate-Active Enzymes database (<strong><font color=#5CA2A8>CAZy</font></strong>) provides a continuously updated list of the glycoside hydrolase families. Because the fold of proteins is better conserved than their sequences, some of the families can be grouped in <strong>&#8217;clans&#8217;</strong>&nbsp;: <br class='autobr' />
+(i) when new sequences are found to be related to more than one family,<br class='autobr' />
+(ii) when the sensitivity of sequence comparison methods is increased or<br class='autobr' />
+(iii) when structural determinations demonstrate the resemblance between members of different families<span class="spip_note_ref">&nbsp;[='#nb3' class='spip_note' rel='footnote' title='Henrissat B, Bairoch A (1996) Updating the sequence-based classification of&nbsp;(...)' id='nh3'>3<]</span></p>
+
+<p>The established <strong>&#8217;clans&#8217;</strong> are given in form of a table below.</p>
+</div>
+<div class="paragraphe"><h3 class="spip">Catalytic Mechanism</h3>
+<p> In most cases, the hydrolysis of the glycosidic bond is catalyzed by two amino acid residues of the enzyme&nbsp;: a general acid (proton donor) and a nucleophile/base<span class="spip_note_ref">&nbsp;[='#nb4' class='spip_note' rel='footnote' title='Davies G, Henrissat B (1995) Structures and mechanisms of glycosyl&nbsp;(...)' id='nh4'>4<]</span>. Depending on the spatial position of these catalytic residues, hydrolysis occurs via overall retention or overall inversion of the anomeric configuration. For each family listed in the <strong><font color=#5CA2A8>CAZy</font></strong> database, we indicate (when it is known) the stereochemical outcome of the reaction catalyzed as well as the type of amino-acid residues acting as a nucleophile/base and as a proton donor. In some cases, the catalytic nucleophile is not borne by the enzyme, and is replaced by the acetamido group at C-2 of the substrate<span class="spip_note_ref">&nbsp;[='#nb5' class='spip_note' rel='footnote' title='Terwisscha van Scheltinga A, Armand S, Kalk KH, Isogai A, Henrissat B,&nbsp;(...)' id='nh5'>5<]</span>. A completely unrelated mechanism has been demonstrated recently for two families of glycosidases utilizing NAD+ as a cofactor<span class="spip_note_ref">&nbsp;[='#nb6' class='spip_note' rel='footnote' title='Rajan SS, Yang X, Collart F, Yip VL, Withers SG, Varrot A, Thompson J,&nbsp;(...)' id='nh6'>6<]</span><span class="spip_note_ref">&nbsp;[='#nb7' class='spip_note' rel='footnote' title='Liu QP, Sulzenbacher G, Yuan H, Bennett EP, Pietz G, Saunders K, Spence J,&nbsp;(...)' id='nh7'>7<]</span>.</p>
+
+<p>For a detailed description of the catalytic mechanism (and variations thereof) of glycoside hydrolases, please visit <strong>="http://www.cazypedia.org/index.php/Glycoside_Hydrolases" class='spip_out' rel='external'><strong>CAZypedia</strong><</strong>.</p>
+</div>
+<div class="paragraphe"><h3 class="spip">Tables for Direct Access</h3>
+<p><img src="local/cache-vignettes/L8xH11/puce-cebf5.gif" width='8' height='11' class='puce' alt="-" style='' />&nbsp;<strong>GH Family Number</strong></p>
+<table><tr><td width="30" align="right" style="background-color:#F0F8FF;">="GH1.html">1<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH2.html">2<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH3.html">3<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH4.html">4<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH5.html">5<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH6.html">6<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH7.html">7<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH8.html">8<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH9.html">9<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH10.html">10<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH11.html">11<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH12.html">12<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH13.html">13<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH14.html">14<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH15.html">15<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH16.html">16<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH17.html">17<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH18.html">18<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH19.html">19<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH20.html">20<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH21.html">21<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH22.html">22<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH23.html">23<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH24.html">24<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH25.html">25<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH26.html">26<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH27.html">27<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH28.html">28<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH29.html">29<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH30.html">30<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH31.html">31<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH32.html">32<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH33.html">33<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH34.html">34<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH35.html">35<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH36.html">36<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH37.html">37<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH38.html">38<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH39.html">39<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH40.html">40<</td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;">="GH41.html">41<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH42.html">42<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH43.html">43<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH44.html">44<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH45.html">45<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH46.html">46<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH47.html">47<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH48.html">48<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH49.html">49<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH50.html">50<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH51.html">51<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH52.html">52<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH53.html">53<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH54.html">54<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH55.html">55<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH56.html">56<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH57.html">57<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH58.html">58<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH59.html">59<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH60.html">60<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH61.html">61<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH62.html">62<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH63.html">63<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH64.html">64<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH65.html">65<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH66.html">66<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH67.html">67<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH68.html">68<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH69.html">69<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH70.html">70<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH71.html">71<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH72.html">72<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH73.html">73<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH74.html">74<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH75.html">75<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH76.html">76<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH77.html">77<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH78.html">78<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH79.html">79<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH80.html">80<</td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;">="GH81.html">81<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH82.html">82<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH83.html">83<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH84.html">84<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH85.html">85<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH86.html">86<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH87.html">87<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH88.html">88<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH89.html">89<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH90.html">90<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH91.html">91<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH92.html">92<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH93.html">93<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH94.html">94<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH95.html">95<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH96.html">96<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH97.html">97<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH98.html">98<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH99.html">99<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH100.html">100<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH101.html">101<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH102.html">102<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH103.html">103<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH104.html">104<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH105.html">105<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH106.html">106<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH107.html">107<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH108.html">108<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH109.html">109<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH110.html">110<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH111.html">111<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH112.html">112<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH113.html">113<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH114.html">114<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH115.html">115<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH116.html">116<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH117.html">117<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH118.html">118<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH119.html">119<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH120.html">120<</td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;">="GH121.html">121<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH122.html">122<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH123.html">123<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH124.html">124<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH125.html">125<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH126.html">126<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH127.html">127<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH128.html">128<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH129.html">129<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH130.html">130<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH131.html">131<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH132.html">132<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH133.html">133<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH134.html">134<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH135.html">135<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH136.html">136<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH137.html">137<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH138.html">138<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH139.html">139<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH140.html">140<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH141.html">141<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH142.html">142<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH143.html">143<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH144.html">144<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH145.html">145<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH146.html">146<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH147.html">147<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH148.html">148<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH149.html">149<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH150.html">150<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH151.html">151<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH152.html">152<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH153.html">153<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH154.html">154<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH155.html">155<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH156.html">156<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH157.html">157<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH158.html">158<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH159.html">159<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH160.html">160<</td></tr><tr><td width="30" align="right" style="background-color:#F0F8FF;">="GH161.html">161<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH162.html">162<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH163.html">163<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH164.html">164<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH165.html">165<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH166.html">166<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH167.html">167<</td><td width="30" align="right" style="background-color:#F0F8FF;">="GH168.html">168<</td></tr></table><table><tr><td style="padding-left:15px;">="GH0.html">Non-Classified Sequences<</td></tr></table>
+<p><img src="local/cache-vignettes/L8xH11/puce-cebf5.gif" width='8' height='11' class='puce' alt="-" style='' />&nbsp;<strong>GH SubFamily Number</strong></p>
+<table  border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">GH5</th><td width="15" class="ec"  align="center"><a id="separ_subfam" href="GH5_1.html">1<<a id="separ_subfam" href="GH5_2.html">2<<a id="separ_subfam" href="GH5_4.html">4<<a id="separ_subfam" href="GH5_5.html">5<<a id="separ_subfam" href="GH5_7.html">7<<a id="separ_subfam" href="GH5_8.html">8<<a id="separ_subfam" href="GH5_9.html">9<<a id="separ_subfam" href="GH5_10.html">10<<a id="separ_subfam" href="GH5_11.html">11<<a id="separ_subfam" href="GH5_12.html">12<<a id="separ_subfam" href="GH5_13.html">13<<a id="separ_subfam" href="GH5_14.html">14<<a id="separ_subfam" href="GH5_15.html">15<<a id="separ_subfam" href="GH5_16.html">16<<a id="separ_subfam" href="GH5_17.html">17<<a id="separ_subfam" href="GH5_18.html">18<<a id="separ_subfam" href="GH5_19.html">19<<a id="separ_subfam" href="GH5_20.html">20<<a id="separ_subfam" href="GH5_21.html">21<<a id="separ_subfam" href="GH5_22.html">22<<a id="separ_subfam" href="GH5_23.html">23<<a id="separ_subfam" href="GH5_24.html">24<<a id="separ_subfam" href="GH5_25.html">25<<a id="separ_subfam" href="GH5_26.html">26<<a id="separ_subfam" href="GH5_27.html">27<<a id="separ_subfam" href="GH5_28.html">28<<a id="separ_subfam" href="GH5_29.html">29<<a id="separ_subfam" href="GH5_30.html">30<<a id="separ_subfam" href="GH5_31.html">31<<a id="separ_subfam" href="GH5_32.html">32<<a id="separ_subfam" href="GH5_33.html">33<<a id="separ_subfam" href="GH5_34.html">34<<a id="separ_subfam" href="GH5_35.html">35<<a id="separ_subfam" href="GH5_36.html">36<<a id="separ_subfam" href="GH5_37.html">37<<a id="separ_subfam" href="GH5_38.html">38<<a id="separ_subfam" href="GH5_39.html">39<<a id="separ_subfam" href="GH5_40.html">40<<a id="separ_subfam" href="GH5_41.html">41<<a id="separ_subfam" href="GH5_42.html">42<<a id="separ_subfam" href="GH5_43.html">43<<a id="separ_subfam" href="GH5_44.html">44<<a id="separ_subfam" href="GH5_45.html">45<<a id="separ_subfam" href="GH5_46.html">46<<a id="separ_subfam" href="GH5_47.html">47<<a id="separ_subfam" href="GH5_48.html">48<<a id="separ_subfam" href="GH5_49.html">49<<a id="separ_subfam" href="GH5_50.html">50<<a id="separ_subfam" href="GH5_51.html">51<<a id="separ_subfam" href="GH5_52.html">52<<a id="separ_subfam" href="GH5_53.html">53<<a id="separ_subfam" href="GH5_54.html">54<<a id="separ_subfam" href="GH5_55.html">55<<a id="separ_subfam" href="GH5_56.html">56<</td></tr></table><table  border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">GH13</th><td width="15" class="ec"  align="center"><a id="separ_subfam" href="GH13_1.html">1<<a id="separ_subfam" href="GH13_2.html">2<<a id="separ_subfam" href="GH13_3.html">3<<a id="separ_subfam" href="GH13_4.html">4<<a id="separ_subfam" href="GH13_5.html">5<<a id="separ_subfam" href="GH13_6.html">6<<a id="separ_subfam" href="GH13_7.html">7<<a id="separ_subfam" href="GH13_8.html">8<<a id="separ_subfam" href="GH13_9.html">9<<a id="separ_subfam" href="GH13_10.html">10<<a id="separ_subfam" href="GH13_11.html">11<<a id="separ_subfam" href="GH13_12.html">12<<a id="separ_subfam" href="GH13_13.html">13<<a id="separ_subfam" href="GH13_14.html">14<<a id="separ_subfam" href="GH13_15.html">15<<a id="separ_subfam" href="GH13_16.html">16<<a id="separ_subfam" href="GH13_17.html">17<<a id="separ_subfam" href="GH13_18.html">18<<a id="separ_subfam" href="GH13_19.html">19<<a id="separ_subfam" href="GH13_20.html">20<<a id="separ_subfam" href="GH13_21.html">21<<a id="separ_subfam" href="GH13_22.html">22<<a id="separ_subfam" href="GH13_23.html">23<<a id="separ_subfam" href="GH13_24.html">24<<a id="separ_subfam" href="GH13_25.html">25<<a id="separ_subfam" href="GH13_26.html">26<<a id="separ_subfam" href="GH13_27.html">27<<a id="separ_subfam" href="GH13_28.html">28<<a id="separ_subfam" href="GH13_29.html">29<<a id="separ_subfam" href="GH13_30.html">30<<a id="separ_subfam" href="GH13_31.html">31<<a id="separ_subfam" href="GH13_32.html">32<<a id="separ_subfam" href="GH13_33.html">33<<a id="separ_subfam" href="GH13_34.html">34<<a id="separ_subfam" href="GH13_35.html">35<<a id="separ_subfam" href="GH13_36.html">36<<a id="separ_subfam" href="GH13_37.html">37<<a id="separ_subfam" href="GH13_38.html">38<<a id="separ_subfam" href="GH13_39.html">39<<a id="separ_subfam" href="GH13_40.html">40<<a id="separ_subfam" href="GH13_41.html">41<<a id="separ_subfam" href="GH13_42.html">42<</td></tr></table><table  border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">GH16</th><td width="15" class="ec"  align="center"><a id="separ_subfam" href="GH16_1.html">1<<a id="separ_subfam" href="GH16_2.html">2<<a id="separ_subfam" href="GH16_3.html">3<<a id="separ_subfam" href="GH16_4.html">4<<a id="separ_subfam" href="GH16_5.html">5<<a id="separ_subfam" href="GH16_6.html">6<<a id="separ_subfam" href="GH16_7.html">7<<a id="separ_subfam" href="GH16_8.html">8<<a id="separ_subfam" href="GH16_9.html">9<<a id="separ_subfam" href="GH16_10.html">10<<a id="separ_subfam" href="GH16_11.html">11<<a id="separ_subfam" href="GH16_12.html">12<<a id="separ_subfam" href="GH16_13.html">13<<a id="separ_subfam" href="GH16_14.html">14<<a id="separ_subfam" href="GH16_15.html">15<<a id="separ_subfam" href="GH16_16.html">16<<a id="separ_subfam" href="GH16_17.html">17<<a id="separ_subfam" href="GH16_18.html">18<<a id="separ_subfam" href="GH16_19.html">19<<a id="separ_subfam" href="GH16_20.html">20<<a id="separ_subfam" href="GH16_21.html">21<<a id="separ_subfam" href="GH16_22.html">22<<a id="separ_subfam" href="GH16_23.html">23<<a id="separ_subfam" href="GH16_24.html">24<<a id="separ_subfam" href="GH16_25.html">25<<a id="separ_subfam" href="GH16_26.html">26<<a id="separ_subfam" href="GH16_27.html">27<</td></tr></table><table  border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">GH30</th><td width="15" class="ec"  align="center"><a id="separ_subfam" href="GH30_1.html">1<<a id="separ_subfam" href="GH30_2.html">2<<a id="separ_subfam" href="GH30_3.html">3<<a id="separ_subfam" href="GH30_4.html">4<<a id="separ_subfam" href="GH30_5.html">5<<a id="separ_subfam" href="GH30_6.html">6<<a id="separ_subfam" href="GH30_7.html">7<<a id="separ_subfam" href="GH30_8.html">8<<a id="separ_subfam" href="GH30_9.html">9<</td></tr></table><table  border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">GH43</th><td width="15" class="ec"  align="center"><a id="separ_subfam" href="GH43_1.html">1<<a id="separ_subfam" href="GH43_2.html">2<<a id="separ_subfam" href="GH43_3.html">3<<a id="separ_subfam" href="GH43_4.html">4<<a id="separ_subfam" href="GH43_5.html">5<<a id="separ_subfam" href="GH43_6.html">6<<a id="separ_subfam" href="GH43_7.html">7<<a id="separ_subfam" href="GH43_8.html">8<<a id="separ_subfam" href="GH43_9.html">9<<a id="separ_subfam" href="GH43_10.html">10<<a id="separ_subfam" href="GH43_11.html">11<<a id="separ_subfam" href="GH43_12.html">12<<a id="separ_subfam" href="GH43_13.html">13<<a id="separ_subfam" href="GH43_14.html">14<<a id="separ_subfam" href="GH43_15.html">15<<a id="separ_subfam" href="GH43_16.html">16<<a id="separ_subfam" href="GH43_17.html">17<<a id="separ_subfam" href="GH43_18.html">18<<a id="separ_subfam" href="GH43_19.html">19<<a id="separ_subfam" href="GH43_20.html">20<<a id="separ_subfam" href="GH43_21.html">21<<a id="separ_subfam" href="GH43_22.html">22<<a id="separ_subfam" href="GH43_23.html">23<<a id="separ_subfam" href="GH43_24.html">24<<a id="separ_subfam" href="GH43_25.html">25<<a id="separ_subfam" href="GH43_26.html">26<<a id="separ_subfam" href="GH43_27.html">27<<a id="separ_subfam" href="GH43_28.html">28<<a id="separ_subfam" href="GH43_29.html">29<<a id="separ_subfam" href="GH43_30.html">30<<a id="separ_subfam" href="GH43_31.html">31<<a id="separ_subfam" href="GH43_32.html">32<<a id="separ_subfam" href="GH43_33.html">33<<a id="separ_subfam" href="GH43_34.html">34<<a id="separ_subfam" href="GH43_35.html">35<<a id="separ_subfam" href="GH43_36.html">36<<a id="separ_subfam" href="GH43_37.html">37<</td></tr></table>
+<p><img src="local/cache-vignettes/L8xH11/puce-cebf5.gif" width='8' height='11' class='puce' alt="-" style='' />&nbsp;<strong>GH Classification Statistics</strong></p>
+<table>
+<tr><td>Modules in present families</td><td class="ec"> 874712</td></tr>
+<tr><td>Non-Classified modules</td><td class="ec" align=right> 17797</td></tr>
+</table>
+<p><img src="local/cache-vignettes/L8xH11/puce-cebf5.gif" width='8' height='11' class='puce' alt="-" style='' />&nbsp;<strong>GH Clans of Related Families</strong></p>
+<table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-A</th><td class="tdclan" align="center">(&beta;/&alpha;)<sub>8</sub></td><td class="clan">="GH1.html" id="separ">1<	="GH2.html" id="separ">2<	="GH5.html" id="separ">5<	="GH10.html" id="separ">10<	="GH17.html" id="separ">17<	="GH26.html" id="separ">26<	="GH30.html" id="separ">30<	="GH35.html" id="separ">35<	="GH39.html" id="separ">39<	="GH42.html" id="separ">42<	="GH50.html" id="separ">50<	="GH51.html" id="separ">51<	="GH53.html" id="separ">53<	="GH59.html" id="separ">59<	="GH72.html" id="separ">72<	="GH79.html" id="separ">79<	="GH86.html" id="separ">86<	="GH113.html" id="separ">113<	="GH128.html" id="separ">128<	="GH147.html" id="separ">147<	="GH148.html" id="separ">148<	="GH157.html" id="separ">157<	="GH158.html" id="separ">158<	="GH167.html" id="separ">167</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-B</th><td class="tdclan" align="center">&beta;-jelly roll</td><td class="clan">="GH7.html" id="separ">7<	="GH16.html" id="separ">16</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-C</th><td class="tdclan" align="center">&beta;-jelly roll</td><td class="clan">="GH11.html" id="separ">11<	="GH12.html" id="separ">12</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-D</th><td class="tdclan" align="center">(&beta;/&alpha;)<sub>8</sub></td><td class="clan">="GH27.html" id="separ">27<	="GH31.html" id="separ">31<	="GH36.html" id="separ">36</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-E</th><td class="tdclan" align="center">6-fold &beta;-propeller</td><td class="clan">="GH33.html" id="separ">33<	="GH34.html" id="separ">34<	="GH83.html" id="separ">83<	="GH93.html" id="separ">93</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-F</th><td class="tdclan" align="center">5-fold &beta;-propeller</td><td class="clan">="GH43.html" id="separ">43<	="GH62.html" id="separ">62<	="GH117.html" id="separ">117</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-G</th><td class="tdclan" align="center">(&alpha;/&alpha;)<sub>6</sub></td><td class="clan">="GH37.html" id="separ">37<	="GH63.html" id="separ">63<	="GH100.html" id="separ">100<	="GH125.html" id="separ">125</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-H</th><td class="tdclan" align="center">(&beta;/&alpha;)<sub>8</sub></td><td class="clan">="GH13.html" id="separ">13<	="GH70.html" id="separ">70<	="GH77.html" id="separ">77</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-I</th><td class="tdclan" align="center">&alpha;+&beta;</td><td class="clan">="GH24.html" id="separ">24<	="GH80.html" id="separ">80</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-J</th><td class="tdclan" align="center">5-fold &beta;-propeller</td><td class="clan">="GH32.html" id="separ">32<	="GH68.html" id="separ">68</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-K</th><td class="tdclan" align="center">(&beta;/&alpha;)<sub>8</sub></td><td class="clan">="GH18.html" id="separ">18<	="GH20.html" id="separ">20<	="GH85.html" id="separ">85</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-L</th><td class="tdclan" align="center">(&alpha;/&alpha;)<sub>6</sub></td><td class="clan">="GH15.html" id="separ">15<	="GH65.html" id="separ">65</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-M</th><td class="tdclan" align="center">(&alpha;/&alpha;)<sub>6</sub></td><td class="clan">="GH8.html" id="separ">8<	="GH48.html" id="separ">48</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-N</th><td class="tdclan" align="center">&beta;-helix</td><td class="clan">="GH28.html" id="separ">28<	="GH49.html" id="separ">49</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-O</th><td class="tdclan" align="center">(&alpha;/&alpha;)<sub>6</sub></td><td class="clan">="GH52.html" id="separ">52<	="GH116.html" id="separ">116</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-P</th><td class="tdclan" align="center">(&alpha;/&alpha;)<sub>6</sub></td><td class="clan">="GH127.html" id="separ">127<	="GH146.html" id="separ">146</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-Q</th><td class="tdclan" align="center">(&alpha;/&alpha;)<sub>6</sub></td><td class="clan">="GH94.html" id="separ">94<	="GH149.html" id="separ">149<	="GH161.html" id="separ">161</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thclan">GH-R</th><td class="tdclan" align="center">(&beta;/&alpha;)<sub>8</sub></td><td class="clan">="GH29.html" id="separ">29<	="GH107.html" id="separ">107</td></tr></table>
+<p><img src="local/cache-vignettes/L8xH11/puce-cebf5.gif" width='8' height='11' class='puce' alt="-" style='' />&nbsp;<strong>EC Activities found in GH families</strong></p>
+
+<p>Caution&nbsp;: Because of the modular nature of CAZymes, these activities may not be directly associated with the family but simply borne by adjacent modules.</p>
+<table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=1.14.99.53">1.14.99.53<</th><td class="ec"> =GH18.html id="separ">18< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.*">2.4.1.-<</th><td class="ec"> =GH1.html id="separ">1<   =GH3.html id="separ">3<   =GH5.html id="separ">5<   =GH13.html id="separ">13<   =GH16.html id="separ">16<   =GH17.html id="separ">17<   =GH20.html id="separ">20<   =GH27.html id="separ">27<   =GH31.html id="separ">31<   =GH32.html id="separ">32<   =GH33.html id="separ">33<   =GH35.html id="separ">35<   =GH39.html id="separ">39<   =GH65.html id="separ">65<   =GH70.html id="separ">70<   =GH72.html id="separ">72<   =GH94.html id="separ">94<   =GH130.html id="separ">130<   =GH0.html id="separ">NC< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.2">2.4.1.2<</th><td class="ec"> =GH15.html id="separ">15< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.4">2.4.1.4<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.5">2.4.1.5<</th><td class="ec"> =GH70.html id="separ">70< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.7">2.4.1.7<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.8">2.4.1.8<</th><td class="ec"> =GH65.html id="separ">65< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.9">2.4.1.9<</th><td class="ec"> =GH68.html id="separ">68< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.10">2.4.1.10<</th><td class="ec"> =GH32.html id="separ">32<   =GH68.html id="separ">68< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.12">2.4.1.12<</th><td class="ec"> =GH6.html id="separ">6< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.18">2.4.1.18<</th><td class="ec"> =GH13.html id="separ">13<   =GH57.html id="separ">57< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.19">2.4.1.19<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.20">2.4.1.20<</th><td class="ec"> =GH94.html id="separ">94< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.25">2.4.1.25<</th><td class="ec"> =GH13.html id="separ">13<   =GH57.html id="separ">57<   =GH77.html id="separ">77<   =GH133.html id="separ">133< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.30">2.4.1.30<</th><td class="ec"> =GH149.html id="separ">149< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.31">2.4.1.31<</th><td class="ec"> =GH94.html id="separ">94< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.49">2.4.1.49<</th><td class="ec"> =GH94.html id="separ">94< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.64">2.4.1.64<</th><td class="ec"> =GH65.html id="separ">65< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.67">2.4.1.67<</th><td class="ec"> =GH36.html id="separ">36< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.82">2.4.1.82<</th><td class="ec"> =GH36.html id="separ">36< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.97">2.4.1.97<</th><td class="ec"> =GH149.html id="separ">149<   =GH161.html id="separ">161< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.99">2.4.1.99<</th><td class="ec"> =GH32.html id="separ">32< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.100">2.4.1.100<</th><td class="ec"> =GH32.html id="separ">32< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.140">2.4.1.140<</th><td class="ec"> =GH70.html id="separ">70< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.161">2.4.1.161<</th><td class="ec"> =GH13.html id="separ">13<   =GH31.html id="separ">31< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.183">2.4.1.183<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.207">2.4.1.207<</th><td class="ec"> =GH16.html id="separ">16< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.211">2.4.1.211<</th><td class="ec"> =GH112.html id="separ">112< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.216">2.4.1.216<</th><td class="ec"> =GH65.html id="separ">65< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.230">2.4.1.230<</th><td class="ec"> =GH65.html id="separ">65< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.243">2.4.1.243<</th><td class="ec"> =GH32.html id="separ">32< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.247">2.4.1.247<</th><td class="ec"> =GH112.html id="separ">112< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.248">2.4.1.248<</th><td class="ec"> =GH66.html id="separ">66< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.279">2.4.1.279<</th><td class="ec"> =GH65.html id="separ">65< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.281">2.4.1.281<</th><td class="ec"> =GH130.html id="separ">130< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.282">2.4.1.282<</th><td class="ec"> =GH65.html id="separ">65< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.319">2.4.1.319<</th><td class="ec"> =GH130.html id="separ">130< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.320">2.4.1.320<</th><td class="ec"> =GH130.html id="separ">130< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.321">2.4.1.321<</th><td class="ec"> =GH94.html id="separ">94< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.329">2.4.1.329<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.333">2.4.1.333<</th><td class="ec"> =GH94.html id="separ">94<   =GH0.html id="separ">NC< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.334">2.4.1.334<</th><td class="ec"> =GH65.html id="separ">65< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.339">2.4.1.339<</th><td class="ec"> =GH130.html id="separ">130< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.340">2.4.1.340<</th><td class="ec"> =GH130.html id="separ">130< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.352">2.4.1.352<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.1.359">2.4.1.359<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.2.*">2.4.2.-<</th><td class="ec"> =GH10.html id="separ">10< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=2.4.99.16">2.4.99.16<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.1.1.*">3.1.1.-<</th><td class="ec"> =GH5.html id="separ">5<   =GH106.html id="separ">106< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.1.1.72">3.1.1.72<</th><td class="ec"> =GH5.html id="separ">5<   =GH11.html id="separ">11<   =GH62.html id="separ">62< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.1.1.73">3.1.1.73<</th><td class="ec"> =GH10.html id="separ">10<   =GH62.html id="separ">62<   =GH78.html id="separ">78< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.*">3.2.1.-<</th><td class="ec"> =GH1.html id="separ">1<   =GH2.html id="separ">2<   =GH3.html id="separ">3<   =GH5.html id="separ">5<   =GH6.html id="separ">6<   =GH8.html id="separ">8<   =GH9.html id="separ">9<   =GH10.html id="separ">10<   =GH11.html id="separ">11<   =GH13.html id="separ">13<   =GH16.html id="separ">16<   =GH17.html id="separ">17<   =GH18.html id="separ">18<   =GH19.html id="separ">19<   =GH20.html id="separ">20<   =GH26.html id="separ">26<   =GH28.html id="separ">28<   =GH30.html id="separ">30<   =GH32.html id="separ">32<   =GH33.html id="separ">33<   =GH35.html id="separ">35<   =GH38.html id="separ">38<   =GH39.html id="separ">39<   =GH42.html id="separ">42<   =GH43.html id="separ">43<   =GH44.html id="separ">44<   =GH48.html id="separ">48<   =GH4</td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.1">3.2.1.1<</th><td class="ec"> =GH13.html id="separ">13<   =GH14.html id="separ">14<   =GH57.html id="separ">57<   =GH119.html id="separ">119< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.2">3.2.1.2<</th><td class="ec"> =GH13.html id="separ">13<   =GH14.html id="separ">14< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.3">3.2.1.3<</th><td class="ec"> =GH15.html id="separ">15<   =GH97.html id="separ">97< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.4">3.2.1.4<</th><td class="ec"> =GH5.html id="separ">5<   =GH6.html id="separ">6<   =GH7.html id="separ">7<   =GH8.html id="separ">8<   =GH9.html id="separ">9<   =GH10.html id="separ">10<   =GH12.html id="separ">12<   =GH26.html id="separ">26<   =GH44.html id="separ">44<   =GH45.html id="separ">45<   =GH48.html id="separ">48<   =GH51.html id="separ">51<   =GH74.html id="separ">74<   =GH124.html id="separ">124<   =GH148.html id="separ">148<   =GH0.html id="separ">NC< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.6">3.2.1.6<</th><td class="ec"> =GH9.html id="separ">9<   =GH16.html id="separ">16< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.7">3.2.1.7<</th><td class="ec"> =GH32.html id="separ">32< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.8">3.2.1.8<</th><td class="ec"> =GH3.html id="separ">3<   =GH5.html id="separ">5<   =GH6.html id="separ">6<   =GH8.html id="separ">8<   =GH9.html id="separ">9<   =GH10.html id="separ">10<   =GH11.html id="separ">11<   =GH16.html id="separ">16<   =GH26.html id="separ">26<   =GH30.html id="separ">30<   =GH43.html id="separ">43<   =GH44.html id="separ">44<   =GH51.html id="separ">51<   =GH62.html id="separ">62<   =GH98.html id="separ">98<   =GH141.html id="separ">141< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.10">3.2.1.10<</th><td class="ec"> =GH13.html id="separ">13<   =GH31.html id="separ">31< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.11">3.2.1.11<</th><td class="ec"> =GH31.html id="separ">31<   =GH49.html id="separ">49<   =GH66.html id="separ">66< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.14">3.2.1.14<</th><td class="ec"> =GH18.html id="separ">18<   =GH19.html id="separ">19<   =GH23.html id="separ">23<   =GH48.html id="separ">48< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.15">3.2.1.15<</th><td class="ec"> =GH28.html id="separ">28< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.17">3.2.1.17<</th><td class="ec"> =GH18.html id="separ">18<   =GH19.html id="separ">19<   =GH22.html id="separ">22<   =GH23.html id="separ">23<   =GH24.html id="separ">24<   =GH25.html id="separ">25<   =GH73.html id="separ">73<   =GH108.html id="separ">108<   =GH0.html id="separ">NC< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.18">3.2.1.18<</th><td class="ec"> =GH1.html id="separ">1<   =GH33.html id="separ">33<   =GH34.html id="separ">34<   =GH83.html id="separ">83<   =GH156.html id="separ">156<   =GH0.html id="separ">NC< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.20">3.2.1.20<</th><td class="ec"> =GH4.html id="separ">4<   =GH13.html id="separ">13<   =GH31.html id="separ">31<   =GH63.html id="separ">63<   =GH76.html id="separ">76<   =GH97.html id="separ">97<   =GH122.html id="separ">122< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.21">3.2.1.21<</th><td class="ec"> =GH1.html id="separ">1<   =GH2.html id="separ">2<   =GH3.html id="separ">3<   =GH5.html id="separ">5<   =GH9.html id="separ">9<   =GH16.html id="separ">16<   =GH30.html id="separ">30<   =GH39.html id="separ">39<   =GH116.html id="separ">116<   =GH0.html id="separ">NC< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.22">3.2.1.22<</th><td class="ec"> =GH4.html id="separ">4<   =GH27.html id="separ">27<   =GH31.html id="separ">31<   =GH36.html id="separ">36<   =GH57.html id="separ">57<   =GH97.html id="separ">97<   =GH110.html id="separ">110< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.23">3.2.1.23<</th><td class="ec"> =GH1.html id="separ">1<   =GH2.html id="separ">2<   =GH3.html id="separ">3<   =GH35.html id="separ">35<   =GH39.html id="separ">39<   =GH42.html id="separ">42<   =GH50.html id="separ">50<   =GH147.html id="separ">147<   =GH163.html id="separ">163<   =GH165.html id="separ">165<   =GH0.html id="separ">NC< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.24">3.2.1.24<</th><td class="ec"> =GH31.html id="separ">31<   =GH38.html id="separ">38<   =GH92.html id="separ">92< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.25">3.2.1.25<</th><td class="ec"> =GH1.html id="separ">1<   =GH2.html id="separ">2<   =GH5.html id="separ">5<   =GH113.html id="separ">113<   =GH164.html id="separ">164< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.26">3.2.1.26<</th><td class="ec"> =GH32.html id="separ">32<   =GH68.html id="separ">68<   =GH100.html id="separ">100< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.28">3.2.1.28<</th><td class="ec"> =GH13.html id="separ">13<   =GH15.html id="separ">15<   =GH37.html id="separ">37<   =GH65.html id="separ">65< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.31">3.2.1.31<</th><td class="ec"> =GH1.html id="separ">1<   =GH2.html id="separ">2<   =GH30.html id="separ">30<   =GH79.html id="separ">79<   =GH137.html id="separ">137<   =GH154.html id="separ">154< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.32">3.2.1.32<</th><td class="ec"> =GH8.html id="separ">8<   =GH26.html id="separ">26< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.33">3.2.1.33<</th><td class="ec"> =GH13.html id="separ">13<   =GH133.html id="separ">133< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.35">3.2.1.35<</th><td class="ec"> =GH16.html id="separ">16<   =GH56.html id="separ">56<   =GH84.html id="separ">84< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.36">3.2.1.36<</th><td class="ec"> =GH79.html id="separ">79< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.37">3.2.1.37<</th><td class="ec"> =GH1.html id="separ">1<   =GH2.html id="separ">2<   =GH3.html id="separ">3<   =GH5.html id="separ">5<   =GH10.html id="separ">10<   =GH30.html id="separ">30<   =GH39.html id="separ">39<   =GH43.html id="separ">43<   =GH51.html id="separ">51<   =GH52.html id="separ">52<   =GH54.html id="separ">54<   =GH116.html id="separ">116<   =GH120.html id="separ">120< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.38">3.2.1.38<</th><td class="ec"> =GH1.html id="separ">1<   =GH3.html id="separ">3<   =GH30.html id="separ">30<   =GH35.html id="separ">35< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.39">3.2.1.39<</th><td class="ec"> =GH5.html id="separ">5<   =GH16.html id="separ">16<   =GH17.html id="separ">17<   =GH55.html id="separ">55<   =GH64.html id="separ">64<   =GH81.html id="separ">81<   =GH128.html id="separ">128<   =GH152.html id="separ">152<   =GH157.html id="separ">157<   =GH158.html id="separ">158< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.40">3.2.1.40<</th><td class="ec"> =GH33.html id="separ">33<   =GH78.html id="separ">78<   =GH106.html id="separ">106< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.41">3.2.1.41<</th><td class="ec"> =GH13.html id="separ">13<   =GH57.html id="separ">57< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.45">3.2.1.45<</th><td class="ec"> =GH3.html id="separ">3<   =GH5.html id="separ">5<   =GH30.html id="separ">30<   =GH116.html id="separ">116< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.46">3.2.1.46<</th><td class="ec"> =GH5.html id="separ">5<   =GH59.html id="separ">59< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.48">3.2.1.48<</th><td class="ec"> =GH13.html id="separ">13<   =GH31.html id="separ">31< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.49">3.2.1.49<</th><td class="ec"> =GH27.html id="separ">27<   =GH31.html id="separ">31<   =GH36.html id="separ">36<   =GH109.html id="separ">109<   =GH129.html id="separ">129< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.50">3.2.1.50<</th><td class="ec"> =GH89.html id="separ">89< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.51">3.2.1.51<</th><td class="ec"> =GH29.html id="separ">29<   =GH141.html id="separ">141<   =GH151.html id="separ">151<   =GH0.html id="separ">NC< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.52">3.2.1.52<</th><td class="ec"> =GH3.html id="separ">3<   =GH5.html id="separ">5<   =GH18.html id="separ">18<   =GH20.html id="separ">20<   =GH84.html id="separ">84<   =GH109.html id="separ">109<   =GH116.html id="separ">116< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.53">3.2.1.53<</th><td class="ec"> =GH123.html id="separ">123< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.54">3.2.1.54<</th><td class="ec"> =GH13.html id="separ">13<   =GH57.html id="separ">57< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.55">3.2.1.55<</th><td class="ec"> =GH2.html id="separ">2<   =GH3.html id="separ">3<   =GH5.html id="separ">5<   =GH10.html id="separ">10<   =GH39.html id="separ">39<   =GH43.html id="separ">43<   =GH51.html id="separ">51<   =GH54.html id="separ">54<   =GH62.html id="separ">62< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.57">3.2.1.57<</th><td class="ec"> =GH49.html id="separ">49< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.58">3.2.1.58<</th><td class="ec"> =GH5.html id="separ">5<   =GH16.html id="separ">16<   =GH55.html id="separ">55< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.59">3.2.1.59<</th><td class="ec"> =GH71.html id="separ">71<   =GH87.html id="separ">87< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.60">3.2.1.60<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.61">3.2.1.61<</th><td class="ec"> =GH87.html id="separ">87< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.62">3.2.1.62<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.63">3.2.1.63<</th><td class="ec"> =GH29.html id="separ">29<   =GH95.html id="separ">95< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.64">3.2.1.64<</th><td class="ec"> =GH32.html id="separ">32< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.65">3.2.1.65<</th><td class="ec"> =GH32.html id="separ">32< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.67">3.2.1.67<</th><td class="ec"> =GH4.html id="separ">4<   =GH28.html id="separ">28< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.68">3.2.1.68<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.70">3.2.1.70<</th><td class="ec"> =GH13.html id="separ">13<   =GH15.html id="separ">15< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.71">3.2.1.71<</th><td class="ec"> =GH144.html id="separ">144<   =GH162.html id="separ">162< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.73">3.2.1.73<</th><td class="ec"> =GH5.html id="separ">5<   =GH6.html id="separ">6<   =GH7.html id="separ">7<   =GH8.html id="separ">8<   =GH9.html id="separ">9<   =GH11.html id="separ">11<   =GH12.html id="separ">12<   =GH16.html id="separ">16<   =GH17.html id="separ">17<   =GH26.html id="separ">26<   =GH51.html id="separ">51< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.74">3.2.1.74<</th><td class="ec"> =GH1.html id="separ">1<   =GH3.html id="separ">3<   =GH5.html id="separ">5<   =GH9.html id="separ">9< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.75">3.2.1.75<</th><td class="ec"> =GH5.html id="separ">5<   =GH30.html id="separ">30< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.76">3.2.1.76<</th><td class="ec"> =GH39.html id="separ">39< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.78">3.2.1.78<</th><td class="ec"> =GH5.html id="separ">5<   =GH9.html id="separ">9<   =GH26.html id="separ">26<   =GH44.html id="separ">44<   =GH45.html id="separ">45<   =GH113.html id="separ">113<   =GH134.html id="separ">134< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.80">3.2.1.80<</th><td class="ec"> =GH32.html id="separ">32< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.81">3.2.1.81<</th><td class="ec"> =GH16.html id="separ">16<   =GH50.html id="separ">50<   =GH86.html id="separ">86<   =GH118.html id="separ">118< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.82">3.2.1.82<</th><td class="ec"> =GH28.html id="separ">28< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.83">3.2.1.83<</th><td class="ec"> =GH16.html id="separ">16< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.84">3.2.1.84<</th><td class="ec"> =GH31.html id="separ">31<   =GH63.html id="separ">63< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.85">3.2.1.85<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.86">3.2.1.86<</th><td class="ec"> =GH1.html id="separ">1<   =GH4.html id="separ">4< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.88">3.2.1.88<</th><td class="ec"> =GH27.html id="separ">27<   =GH36.html id="separ">36<   =GH97.html id="separ">97< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.89">3.2.1.89<</th><td class="ec"> =GH53.html id="separ">53<   =GH147.html id="separ">147< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.91">3.2.1.91<</th><td class="ec"> =GH5.html id="separ">5<   =GH6.html id="separ">6<   =GH9.html id="separ">9< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.93">3.2.1.93<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.94">3.2.1.94<</th><td class="ec"> =GH27.html id="separ">27< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.95">3.2.1.95<</th><td class="ec"> =GH49.html id="separ">49< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.96">3.2.1.96<</th><td class="ec"> =GH18.html id="separ">18<   =GH20.html id="separ">20<   =GH73.html id="separ">73<   =GH85.html id="separ">85< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.97">3.2.1.97<</th><td class="ec"> =GH101.html id="separ">101< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.98">3.2.1.98<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.99">3.2.1.99<</th><td class="ec"> =GH43.html id="separ">43< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.100">3.2.1.100<</th><td class="ec"> =GH5.html id="separ">5<   =GH26.html id="separ">26< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.101">3.2.1.101<</th><td class="ec"> =GH76.html id="separ">76< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.102">3.2.1.102<</th><td class="ec"> =GH98.html id="separ">98< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.103">3.2.1.103<</th><td class="ec"> =GH16.html id="separ">16< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.104">3.2.1.104<</th><td class="ec"> =GH5.html id="separ">5< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.105">3.2.1.105<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.106">3.2.1.106<</th><td class="ec"> =GH63.html id="separ">63< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.107">3.2.1.107<</th><td class="ec"> =GH65.html id="separ">65< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.108">3.2.1.108<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.109">3.2.1.109<</th><td class="ec"> =GH114.html id="separ">114< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.111">3.2.1.111<</th><td class="ec"> =GH29.html id="separ">29< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.113">3.2.1.113<</th><td class="ec"> =GH38.html id="separ">38<   =GH47.html id="separ">47<   =GH92.html id="separ">92< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.114">3.2.1.114<</th><td class="ec"> =GH38.html id="separ">38<   =GH92.html id="separ">92< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.116">3.2.1.116<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.117">3.2.1.117<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.118">3.2.1.118<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.119">3.2.1.119<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.120">3.2.1.120<</th><td class="ec"> =GH3.html id="separ">3< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.122">3.2.1.122<</th><td class="ec"> =GH4.html id="separ">4< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.123">3.2.1.123<</th><td class="ec"> =GH5.html id="separ">5< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.125">3.2.1.125<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.126">3.2.1.126<</th><td class="ec"> =GH3.html id="separ">3< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.129">3.2.1.129<</th><td class="ec"> =GH58.html id="separ">58< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.130">3.2.1.130<</th><td class="ec"> =GH99.html id="separ">99< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.131">3.2.1.131<</th><td class="ec"> =GH67.html id="separ">67<   =GH115.html id="separ">115< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.132">3.2.1.132<</th><td class="ec"> =GH3.html id="separ">3<   =GH5.html id="separ">5<   =GH7.html id="separ">7<   =GH8.html id="separ">8<   =GH46.html id="separ">46<   =GH75.html id="separ">75<   =GH80.html id="separ">80< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.133">3.2.1.133<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.135">3.2.1.135<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.136">3.2.1.136<</th><td class="ec"> =GH30.html id="separ">30< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.139">3.2.1.139<</th><td class="ec"> =GH4.html id="separ">4<   =GH67.html id="separ">67< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.140">3.2.1.140<</th><td class="ec"> =GH20.html id="separ">20<   =GH136.html id="separ">136< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.141">3.2.1.141<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.145">3.2.1.145<</th><td class="ec"> =GH43.html id="separ">43< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.146">3.2.1.146<</th><td class="ec"> =GH2.html id="separ">2<   =GH5.html id="separ">5<   =GH43.html id="separ">43<   =GH117.html id="separ">117<   =GH159.html id="separ">159< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.147">3.2.1.147<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.149">3.2.1.149<</th><td class="ec"> =GH1.html id="separ">1<   =GH5.html id="separ">5< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.150">3.2.1.150<</th><td class="ec"> =GH74.html id="separ">74< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.151">3.2.1.151<</th><td class="ec"> =GH5.html id="separ">5<   =GH9.html id="separ">9<   =GH12.html id="separ">12<   =GH16.html id="separ">16<   =GH26.html id="separ">26<   =GH44.html id="separ">44<   =GH45.html id="separ">45<   =GH48.html id="separ">48<   =GH74.html id="separ">74< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.152">3.2.1.152<</th><td class="ec"> =GH2.html id="separ">2< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.153">3.2.1.153<</th><td class="ec"> =GH32.html id="separ">32< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.154">3.2.1.154<</th><td class="ec"> =GH32.html id="separ">32< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.155">3.2.1.155<</th><td class="ec"> =GH3.html id="separ">3< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.156">3.2.1.156<</th><td class="ec"> =GH8.html id="separ">8< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.157">3.2.1.157<</th><td class="ec"> =GH82.html id="separ">82< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.158">3.2.1.158<</th><td class="ec"> =GH96.html id="separ">96< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.159">3.2.1.159<</th><td class="ec"> =GH117.html id="separ">117< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.161">3.2.1.161<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.162">3.2.1.162<</th><td class="ec"> =GH150.html id="separ">150< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.164">3.2.1.164<</th><td class="ec"> =GH5.html id="separ">5<   =GH30.html id="separ">30< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.165">3.2.1.165<</th><td class="ec"> =GH2.html id="separ">2<   =GH9.html id="separ">9<   =GH35.html id="separ">35< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.166">3.2.1.166<</th><td class="ec"> =GH79.html id="separ">79< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.167">3.2.1.167<</th><td class="ec"> =GH79.html id="separ">79< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.169">3.2.1.169<</th><td class="ec"> =GH84.html id="separ">84< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.170">3.2.1.170<</th><td class="ec"> =GH63.html id="separ">63< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.171">3.2.1.171<</th><td class="ec"> =GH28.html id="separ">28< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.172">3.2.1.172<</th><td class="ec"> =GH105.html id="separ">105< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.173">3.2.1.173<</th><td class="ec"> =GH138.html id="separ">138< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.174">3.2.1.174<</th><td class="ec"> =GH78.html id="separ">78<   =GH106.html id="separ">106< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.175">3.2.1.175<</th><td class="ec"> =GH1.html id="separ">1<   =GH17.html id="separ">17< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.176">3.2.1.176<</th><td class="ec"> =GH7.html id="separ">7<   =GH9.html id="separ">9<   =GH48.html id="separ">48< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.177">3.2.1.177<</th><td class="ec"> =GH31.html id="separ">31< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.178">3.2.1.178<</th><td class="ec"> =GH16.html id="separ">16<   =GH86.html id="separ">86< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.181">3.2.1.181<</th><td class="ec"> =GH16.html id="separ">16< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.182">3.2.1.182<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.185">3.2.1.185<</th><td class="ec"> =GH2.html id="separ">2<   =GH127.html id="separ">127<   =GH137.html id="separ">137<   =GH142.html id="separ">142<   =GH143.html id="separ">143<   =GH146.html id="separ">146< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.197">3.2.1.197<</th><td class="ec"> =GH130.html id="separ">130< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.198">3.2.1.198<</th><td class="ec"> =GH99.html id="separ">99< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.199">3.2.1.199<</th><td class="ec"> =GH31.html id="separ">31< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.204">3.2.1.204<</th><td class="ec"> =GH31.html id="separ">31< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.205">3.2.1.205<</th><td class="ec"> =GH15.html id="separ">15< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.208">3.2.1.208<</th><td class="ec"> =GH63.html id="separ">63< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.211">3.2.1.211<</th><td class="ec"> =GH168.html id="separ">168< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.212">3.2.1.212<</th><td class="ec"> =GH107.html id="separ">107< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.2.1.17_or_4.2.2.n1">3.2.1.17_or_4.2.2.n1<</th><td class="ec"> =GH23.html id="separ">23< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.5.1.*">3.5.1.-<</th><td class="ec"> =GH153.html id="separ">153< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=3.5.2.17">3.5.2.17<</th><td class="ec"> =GH1.html id="separ">1< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=4.2.2.n1">4.2.2.n1<</th><td class="ec"> =GH23.html id="separ">23<   =GH102.html id="separ">102<   =GH103.html id="separ">103<   =GH104.html id="separ">104<   =GH0.html id="separ">NC< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=4.2.2.13">4.2.2.13<</th><td class="ec"> =GH31.html id="separ">31< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=4.2.2.15">4.2.2.15<</th><td class="ec"> =GH33.html id="separ">33< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=4.2.2.16">4.2.2.16<</th><td class="ec"> =GH32.html id="separ">32< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=4.2.2.17">4.2.2.17<</th><td class="ec"> =GH91.html id="separ">91< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=4.2.2.18">4.2.2.18<</th><td class="ec"> =GH91.html id="separ">91< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=5.4.99.11">5.4.99.11<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=5.4.99.15">5.4.99.15<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table><table border="0" cellpadding="0" cellspacing="1"><tr><th class="thec">="http://www.enzyme-database.org/query.php?ec=5.4.99.16">5.4.99.16<</th><td class="ec"> =GH13.html id="separ">13< </td></tr></table></div></div>
+	
+          
+        
+     	  <div class="ps surlignable"><h2 class="pas_surlignable">Note</h2><div class="crayon article-ps-3 "><p>Some glycoside hydrolases are multifunctional enzymes that contain catalytic domains that belong to different GH families.</p></div></div>
+
+          <div class="notes surlignable"><h2 class="pas_surlignable">Notes</h2><div id='nb1'>
+<p><span class="spip_note_ref">[='#nh1' class='spip_note' title='Notes 1' rev='footnote'>1<]&nbsp;</span> Henrissat B (1991) A classification of glycosyl hydrolases based on amino-acid sequence similarities. <strong>Biochem. J.</strong> 280:309-316 [PMID&nbsp;: ="http://www.ncbi.nlm.nih.gov/sites/entrez?db=pubmed&amp;cmd=search&amp;term=1747104" class='spip_out' rel='external'>1747104<].</p>
+</div><div id='nb2'>
+<p><span class="spip_note_ref">[='#nh2' class='spip_note' title='Notes 2' rev='footnote'>2<]&nbsp;</span> Henrissat B, Bairoch A (1993) New families in the classification of glycosyl hydrolases based on amino- acid sequence similarities. <strong>Biochem. J.</strong> 293:781-788 [PMID&nbsp;: ="http://www.ncbi.nlm.nih.gov/sites/entrez?db=pubmed&amp;cmd=search&amp;term=8352747" class='spip_out' rel='external'>8352747<].</p>
+</div><div id='nb3'>
+<p><span class="spip_note_ref">[='#nh3' class='spip_note' title='Notes 3' rev='footnote'>3<]&nbsp;</span> Henrissat B, Bairoch A (1996) Updating the sequence-based classification of glycosyl hydrolases. <strong>Biochem. J.</strong> 316:695-696 [PMID&nbsp;: ="http://www.ncbi.nlm.nih.gov/sites/entrez?db=pubmed&amp;cmd=search&amp;term=8687420" class='spip_out' rel='external'>8687420<].</p>
+</div><div id='nb4'>
+<p><span class="spip_note_ref">[='#nh4' class='spip_note' title='Notes 4' rev='footnote'>4<]&nbsp;</span> Davies G, Henrissat B (1995) Structures and mechanisms of glycosyl hydrolases. <strong>Structure</strong> 3:853-859 [PMID&nbsp;: ="http://www.ncbi.nlm.nih.gov/sites/entrez?db=pubmed&amp;cmd=search&amp;term=8535779" class='spip_out' rel='external'>8535779<].</p>
+</div><div id='nb5'>
+<p><span class="spip_note_ref">[='#nh5' class='spip_note' title='Notes 5' rev='footnote'>5<]&nbsp;</span> Terwisscha van Scheltinga A, Armand S, Kalk KH, Isogai A, Henrissat B, Dijkstra BW (1995) Stereochemistry of chitin hydrolysis by a plant chitinase/lysozyme and x-ray structure of a complex with allosamidin. Evidence for substrate assisted catalysis. <strong>Biochemistry</strong> 34:15619-15623<br class='autobr' />
+[PMID&nbsp;: ="http://www.ncbi.nlm.nih.gov/sites/entrez?db=pubmed&amp;cmd=search&amp;term=7495789" class='spip_out' rel='external'>7495789<].</p>
+</div><div id='nb6'>
+<p><span class="spip_note_ref">[='#nh6' class='spip_note' title='Notes 6' rev='footnote'>6<]&nbsp;</span> Rajan SS, Yang X, Collart F, Yip VL, Withers SG, Varrot A, Thompson J, Davies GJ, Anderson WF (2004) Novel catalytic mechanism of glycoside hydrolysis based on the structure of an NAD+/Mn2+ -dependent phospho-alpha-glucosidase from <i>Bacillus subtilis</i>. <strong>Structure</strong>. 12:1619-1629<br class='autobr' />
+[PMID&nbsp;: ="http://www.ncbi.nlm.nih.gov/sites/entrez?db=pubmed&amp;cmd=search&amp;term=15341727" class='spip_out' rel='external'>15341727<].</p>
+</div><div id='nb7'>
+<p><span class="spip_note_ref">[='#nh7' class='spip_note' title='Notes 7' rev='footnote'>7<]&nbsp;</span> Liu QP, Sulzenbacher G, Yuan H, Bennett EP, Pietz G, Saunders K, Spence J, Nudelman E, Levery SB, White T, Neveu JM, Lane WS, Bourne Y, Olsson ML, Henrissat B, Clausen H (2007) Bacterial glycosidases for the production of universal red blood cells. <strong>Nature Biotechnol.</strong> 25:454-464<br class='autobr' />
+[PMID&nbsp;: ="http://www.ncbi.nlm.nih.gov/sites/entrez?db=pubmed&amp;cmd=search&amp;term=17401360" class='spip_out' rel='external'>17401360<].</p>
+</div></div>
+
+          <div class="cadre_bas"><!-- cadre_pied -->
+	  Last update: <b>2020-11-08</b>
+
+&copy; Copyright <b>1998-2020</b><br>="http://www.afmb.univ-mrs.fr/" target="_blank">AFMB - CNRS - Université d'Aix-Marseille<	  
+	  </div><!-- cadre_pied -->
+	  
+	  <p class="bas_de_page">
+
+    </div>
+    <!-- volet_central -->
+
+</div>
+<!-- cadre_principal -->
+
+<script type="text/javascript">
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script type="text/javascript">
+try {
+var pageTracker = _gat._getTracker("UA-12604774-1");
+pageTracker._trackPageview();
+} catch(err) {}</script>
+</body>
+</html>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/test_inputs/test_inputs_crawler/pagination_page.html b/tests/test_inputs/test_inputs_crawler/pagination_page.html
new file mode 100644
index 00000000..b484d51c
--- /dev/null
+++ b/tests/test_inputs/test_inputs_crawler/pagination_page.html
@@ -0,0 +1,1448 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html dir="ltr" lang="fr" xml:lang="fr" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>CAZy - GH1</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
+<meta content="SPIP 3.0.1 [19436]" name="generator"/>
+<link href="spip.php?page=backend" rel="alternate" title="Syndiquer tout le site" type="application/rss+xml"/>
+<link href="squelettes/css/section.css" media="projection, screen, tv" rel="stylesheet" type="text/css"/>
+<link href="squelettes/css/main.css" media="projection, screen, tv" rel="stylesheet" type="text/css"/>
+<link href="squelettes/images/cazy.ico" rel="shortcut icon" type="image/x-icon"/>
+<script src="squelettes/js/canevas.js" type="text/javascript"></script>
+</head><body><a href="http://www.cazy.org/"><div class="logo_link"></div></a>
+<script src="prive/javascript/jquery.js" type="text/javascript"></script>
+<script src="prive/javascript/jquery.form.js" type="text/javascript"></script>
+<script src="prive/javascript/jquery.autosave.js" type="text/javascript"></script>
+<script src="prive/javascript/jquery.placeholder-label.js" type="text/javascript"></script>
+<script src="prive/javascript/ajaxCallback.js" type="text/javascript"></script>
+<script src="prive/javascript/jquery.cookie.js" type="text/javascript"></script>
+<script type="text/javascript">/*<![CDATA[*/
+var _gaq = _gaq || [];
+_gaq.push(["_setAccount", "UA-12604774-1"]);
+_gaq.push(["_trackPageview"]);
+(function() {
+	var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;
+	ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
+	var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);
+})();
+/*]]>*/</script>
+<script type="text/javascript">/* <![CDATA[ */
+var box_settings = {tt_img:true,sel_g:"#documents_portfolio a[type='image/jpeg'],#documents_portfolio a[type='image/png'],#documents_portfolio a[type='image/gif']",sel_c:".mediabox",trans:"elastic",speed:"200",ssSpeed:"2500",maxW:"90%",maxH:"90%",minW:"400px",minH:"",opa:"0.9",str_ssStart:"Diaporama",str_ssStop:"Arrêter",str_cur:"{current}/{total}",str_prev:"Précédent",str_next:"Suivant",str_close:"Fermer",splash_url:""};
+/* ]]> */</script>
+<!-- insert_head_css --><link href="plugins-dist/mediabox/colorbox/black-striped/colorbox.css" media="all" rel="stylesheet" type="text/css"/><!-- insert_head -->
+<script src="plugins-dist/mediabox/javascript/jquery.colorbox.js?1337524663" type="text/javascript"></script>
+<script src="plugins-dist/mediabox/javascript/spip.mediabox.js?1337524663" type="text/javascript"></script><link href="plugins-dist/porte_plume/css/barre_outils.css" media="all" rel="stylesheet" type="text/css"/>
+<link href="spip.php?page=barre_outils_icones.css" media="all" rel="stylesheet" type="text/css"/>
+<script src="plugins-dist/porte_plume/javascript/jquery.markitup_pour_spip.js" type="text/javascript"></script>
+<script src="plugins-dist/porte_plume/javascript/jquery.previsu_spip.js" type="text/javascript"></script>
+<script src="spip.php?page=porte_plume_start.js&amp;lang=fr" type="text/javascript"></script>
+<!-- CS vide -->
+<!-- Debut CS -->
+<script type="text/javascript"><!--
+var cs_prive=window.location.pathname.match(/\/ecrire\/$/)!=null;
+jQuery.fn.cs_todo=function(){return this.not('.cs_done').addClass('cs_done');};
+var cs_init = function() {
+	if(window.location.search.match(/page=forum/)!=null) jQuery("legend:contains('検査したコメントのみ表示')", this).next().html('Ce forum est modéré à priori : votre contribution n\'apparaîtra qu\'après avoir été validée par un administrateur du site, sauf si vous êtes identifié et autorisé à poster directement.');
+}
+if(typeof onAjaxLoad=='function') onAjaxLoad(cs_init);
+if(window.jQuery) {
+var cs_sel_jQuery=typeof jQuery(document).selector=='undefined'?'@':'';
+var cs_CookiePlugin="prive/javascript/jquery.cookie.js";
+jQuery(document).ready(function(){
+	cs_init.apply(document);
+});
+}
+// --></script>
+<!-- Fin CS -->
+<!-- cadre_haut -->
+<div class="cadre_haut">
+<div class="cadre_menu"><!-- cadre_menu -->
+<div class="Menu" onmouseout="MouseOutDeclencheSablier()">
+<span id="inactif" onmouseover="MouseOverMenu(this,'home','ezcl')"><b><a class="linkmenu" href="Welcome-to-the-Carbohydrate-Active.html">Home</a></b></span>
+<span id="encours" onmouseover="MouseOverMenu(this,'ezcl','ezcl')"><b>Enzyme Classes</b></span>
+<span id="inactif" onmouseover="MouseOverMenu(this,'amod','ezcl')"><b>Associated Modules</b></span>
+<span id="inactif" onmouseover="MouseOverMenu(this,'gnom','ezcl')"><b>Genomes</b></span>
+</div>
+</div><!-- cadre_menu -->
+<div class="cadre_sousmenu"><!-- cadre_sousmenu -->
+<!-- sousmenu1 -->
+<div class="SousMenuLine" id="home" onmouseout="MouseOutDeclencheSablier()" onmouseover="MouseOverArretSablier()">
+ 
+</div>
+<!-- sousmenu2 -->
+<div class="SousMenuLine" id="ezcl" onmouseout="MouseOutDeclencheSablier()" onmouseover="MouseOverArretSablier()">
+<a href="Glycoside-Hydrolases.html" id="actif">Glycoside Hydrolases</a>
+<a href="GlycosylTransferases.html">GlycosylTransferases</a>
+<a href="Polysaccharide-Lyases.html">Polysaccharide Lyases</a>
+<a href="Carbohydrate-Esterases.html">Carbohydrate Esterases</a>
+<a href="Auxiliary-Activities.html">Auxiliary Activities</a>
+</div>
+<!-- sousmenu3 -->
+<div class="SousMenuLine" id="amod" onmouseout="MouseOutDeclencheSablier()" onmouseover="MouseOverArretSablier()">
+<a href="Carbohydrate-Binding-Modules.html">Carbohydrate-Binding Modules</a><font id="confort"> </font>
+</div>
+<!-- sousmenu4 -->
+<div class="SousMenuLine" id="gnom" onmouseout="MouseOutDeclencheSablier()" onmouseover="MouseOverArretSablier()">
+<a href="Genomes.html">Introduction</a>
+<a href="http://www.cazy.org/a.html">Archaea</a>
+<a href="http://www.cazy.org/b.html">Bacteria</a>
+<a href="http://www.cazy.org/e.html">Eukaryota</a>
+<a href="http://www.cazy.org/v.html">Viruses</a><font id="confort"> </font>
+</div>
+</div><!-- cadre_sousmenu -->
+</div><!-- cadre_haut -->
+<!-- cadre_principal -->
+<div class="cadre_principal">
+<!-- volet_central -->
+<div class="volet_central">
+<div align="right">
+<div style="position:absolute;right:460px;">
+<form name="nextpage">
+<select name="cazypage" onchange="document.location.href='' + this.options[this.selectedIndex].value + ''">
+<option selected="" value="http://www.cazy.org/GH1.html">GH1</option>
+<option value="http://www.cazy.org/GH2.html">GH2</option>
+<option value="http://www.cazy.org/GH3.html">GH3</option>
+<option value="http://www.cazy.org/GH4.html">GH4</option>
+<option value="http://www.cazy.org/GH5.html">GH5</option>
+<option value="http://www.cazy.org/GH6.html">GH6</option>
+<option value="http://www.cazy.org/GH7.html">GH7</option>
+<option value="http://www.cazy.org/GH8.html">GH8</option>
+<option value="http://www.cazy.org/GH9.html">GH9</option>
+<option value="http://www.cazy.org/GH10.html">GH10</option>
+<option value="http://www.cazy.org/GH11.html">GH11</option>
+<option value="http://www.cazy.org/GH12.html">GH12</option>
+<option value="http://www.cazy.org/GH13.html">GH13</option>
+<option value="http://www.cazy.org/GH14.html">GH14</option>
+<option value="http://www.cazy.org/GH15.html">GH15</option>
+<option value="http://www.cazy.org/GH16.html">GH16</option>
+<option value="http://www.cazy.org/GH17.html">GH17</option>
+<option value="http://www.cazy.org/GH18.html">GH18</option>
+<option value="http://www.cazy.org/GH19.html">GH19</option>
+<option value="http://www.cazy.org/GH20.html">GH20</option>
+<option value="http://www.cazy.org/GH21.html">GH21</option>
+<option value="http://www.cazy.org/GH22.html">GH22</option>
+<option value="http://www.cazy.org/GH23.html">GH23</option>
+<option value="http://www.cazy.org/GH24.html">GH24</option>
+<option value="http://www.cazy.org/GH25.html">GH25</option>
+<option value="http://www.cazy.org/GH26.html">GH26</option>
+<option value="http://www.cazy.org/GH27.html">GH27</option>
+<option value="http://www.cazy.org/GH28.html">GH28</option>
+<option value="http://www.cazy.org/GH29.html">GH29</option>
+<option value="http://www.cazy.org/GH30.html">GH30</option>
+<option value="http://www.cazy.org/GH31.html">GH31</option>
+<option value="http://www.cazy.org/GH32.html">GH32</option>
+<option value="http://www.cazy.org/GH33.html">GH33</option>
+<option value="http://www.cazy.org/GH34.html">GH34</option>
+<option value="http://www.cazy.org/GH35.html">GH35</option>
+<option value="http://www.cazy.org/GH36.html">GH36</option>
+<option value="http://www.cazy.org/GH37.html">GH37</option>
+<option value="http://www.cazy.org/GH38.html">GH38</option>
+<option value="http://www.cazy.org/GH39.html">GH39</option>
+<option value="http://www.cazy.org/GH40.html">GH40</option>
+<option value="http://www.cazy.org/GH41.html">GH41</option>
+<option value="http://www.cazy.org/GH42.html">GH42</option>
+<option value="http://www.cazy.org/GH43.html">GH43</option>
+<option value="http://www.cazy.org/GH44.html">GH44</option>
+<option value="http://www.cazy.org/GH45.html">GH45</option>
+<option value="http://www.cazy.org/GH46.html">GH46</option>
+<option value="http://www.cazy.org/GH47.html">GH47</option>
+<option value="http://www.cazy.org/GH48.html">GH48</option>
+<option value="http://www.cazy.org/GH49.html">GH49</option>
+<option value="http://www.cazy.org/GH50.html">GH50</option>
+<option value="http://www.cazy.org/GH51.html">GH51</option>
+<option value="http://www.cazy.org/GH52.html">GH52</option>
+<option value="http://www.cazy.org/GH53.html">GH53</option>
+<option value="http://www.cazy.org/GH54.html">GH54</option>
+<option value="http://www.cazy.org/GH55.html">GH55</option>
+<option value="http://www.cazy.org/GH56.html">GH56</option>
+<option value="http://www.cazy.org/GH57.html">GH57</option>
+<option value="http://www.cazy.org/GH58.html">GH58</option>
+<option value="http://www.cazy.org/GH59.html">GH59</option>
+<option value="http://www.cazy.org/GH60.html">GH60</option>
+<option value="http://www.cazy.org/GH61.html">GH61</option>
+<option value="http://www.cazy.org/GH62.html">GH62</option>
+<option value="http://www.cazy.org/GH63.html">GH63</option>
+<option value="http://www.cazy.org/GH64.html">GH64</option>
+<option value="http://www.cazy.org/GH65.html">GH65</option>
+<option value="http://www.cazy.org/GH66.html">GH66</option>
+<option value="http://www.cazy.org/GH67.html">GH67</option>
+<option value="http://www.cazy.org/GH68.html">GH68</option>
+<option value="http://www.cazy.org/GH69.html">GH69</option>
+<option value="http://www.cazy.org/GH70.html">GH70</option>
+<option value="http://www.cazy.org/GH71.html">GH71</option>
+<option value="http://www.cazy.org/GH72.html">GH72</option>
+<option value="http://www.cazy.org/GH73.html">GH73</option>
+<option value="http://www.cazy.org/GH74.html">GH74</option>
+<option value="http://www.cazy.org/GH75.html">GH75</option>
+<option value="http://www.cazy.org/GH76.html">GH76</option>
+<option value="http://www.cazy.org/GH77.html">GH77</option>
+<option value="http://www.cazy.org/GH78.html">GH78</option>
+<option value="http://www.cazy.org/GH79.html">GH79</option>
+<option value="http://www.cazy.org/GH80.html">GH80</option>
+<option value="http://www.cazy.org/GH81.html">GH81</option>
+<option value="http://www.cazy.org/GH82.html">GH82</option>
+<option value="http://www.cazy.org/GH83.html">GH83</option>
+<option value="http://www.cazy.org/GH84.html">GH84</option>
+<option value="http://www.cazy.org/GH85.html">GH85</option>
+<option value="http://www.cazy.org/GH86.html">GH86</option>
+<option value="http://www.cazy.org/GH87.html">GH87</option>
+<option value="http://www.cazy.org/GH88.html">GH88</option>
+<option value="http://www.cazy.org/GH89.html">GH89</option>
+<option value="http://www.cazy.org/GH90.html">GH90</option>
+<option value="http://www.cazy.org/GH91.html">GH91</option>
+<option value="http://www.cazy.org/GH92.html">GH92</option>
+<option value="http://www.cazy.org/GH93.html">GH93</option>
+<option value="http://www.cazy.org/GH94.html">GH94</option>
+<option value="http://www.cazy.org/GH95.html">GH95</option>
+<option value="http://www.cazy.org/GH96.html">GH96</option>
+<option value="http://www.cazy.org/GH97.html">GH97</option>
+<option value="http://www.cazy.org/GH98.html">GH98</option>
+<option value="http://www.cazy.org/GH99.html">GH99</option>
+<option value="http://www.cazy.org/GH100.html">GH100</option>
+<option value="http://www.cazy.org/GH101.html">GH101</option>
+<option value="http://www.cazy.org/GH102.html">GH102</option>
+<option value="http://www.cazy.org/GH103.html">GH103</option>
+<option value="http://www.cazy.org/GH104.html">GH104</option>
+<option value="http://www.cazy.org/GH105.html">GH105</option>
+<option value="http://www.cazy.org/GH106.html">GH106</option>
+<option value="http://www.cazy.org/GH107.html">GH107</option>
+<option value="http://www.cazy.org/GH108.html">GH108</option>
+<option value="http://www.cazy.org/GH109.html">GH109</option>
+<option value="http://www.cazy.org/GH110.html">GH110</option>
+<option value="http://www.cazy.org/GH111.html">GH111</option>
+<option value="http://www.cazy.org/GH112.html">GH112</option>
+<option value="http://www.cazy.org/GH113.html">GH113</option>
+<option value="http://www.cazy.org/GH114.html">GH114</option>
+<option value="http://www.cazy.org/GH115.html">GH115</option>
+<option value="http://www.cazy.org/GH116.html">GH116</option>
+<option value="http://www.cazy.org/GH117.html">GH117</option>
+<option value="http://www.cazy.org/GH118.html">GH118</option>
+<option value="http://www.cazy.org/GH119.html">GH119</option>
+<option value="http://www.cazy.org/GH120.html">GH120</option>
+<option value="http://www.cazy.org/GH121.html">GH121</option>
+<option value="http://www.cazy.org/GH122.html">GH122</option>
+<option value="http://www.cazy.org/GH123.html">GH123</option>
+<option value="http://www.cazy.org/GH124.html">GH124</option>
+<option value="http://www.cazy.org/GH125.html">GH125</option>
+<option value="http://www.cazy.org/GH126.html">GH126</option>
+<option value="http://www.cazy.org/GH127.html">GH127</option>
+<option value="http://www.cazy.org/GH128.html">GH128</option>
+<option value="http://www.cazy.org/GH129.html">GH129</option>
+<option value="http://www.cazy.org/GH130.html">GH130</option>
+<option value="http://www.cazy.org/GH131.html">GH131</option>
+<option value="http://www.cazy.org/GH132.html">GH132</option>
+<option value="http://www.cazy.org/GH133.html">GH133</option>
+<option value="http://www.cazy.org/GH134.html">GH134</option>
+<option value="http://www.cazy.org/GH135.html">GH135</option>
+<option value="http://www.cazy.org/GH136.html">GH136</option>
+<option value="http://www.cazy.org/GH137.html">GH137</option>
+<option value="http://www.cazy.org/GH138.html">GH138</option>
+<option value="http://www.cazy.org/GH139.html">GH139</option>
+<option value="http://www.cazy.org/GH140.html">GH140</option>
+<option value="http://www.cazy.org/GH141.html">GH141</option>
+<option value="http://www.cazy.org/GH142.html">GH142</option>
+<option value="http://www.cazy.org/GH143.html">GH143</option>
+<option value="http://www.cazy.org/GH144.html">GH144</option>
+<option value="http://www.cazy.org/GH145.html">GH145</option>
+<option value="http://www.cazy.org/GH146.html">GH146</option>
+<option value="http://www.cazy.org/GH147.html">GH147</option>
+<option value="http://www.cazy.org/GH148.html">GH148</option>
+<option value="http://www.cazy.org/GH149.html">GH149</option>
+<option value="http://www.cazy.org/GH150.html">GH150</option>
+<option value="http://www.cazy.org/GH151.html">GH151</option>
+<option value="http://www.cazy.org/GH152.html">GH152</option>
+<option value="http://www.cazy.org/GH153.html">GH153</option>
+<option value="http://www.cazy.org/GH154.html">GH154</option>
+<option value="http://www.cazy.org/GH155.html">GH155</option>
+<option value="http://www.cazy.org/GH156.html">GH156</option>
+<option value="http://www.cazy.org/GH157.html">GH157</option>
+<option value="http://www.cazy.org/GH158.html">GH158</option>
+<option value="http://www.cazy.org/GH159.html">GH159</option>
+<option value="http://www.cazy.org/GH160.html">GH160</option>
+<option value="http://www.cazy.org/GH161.html">GH161</option>
+<option value="http://www.cazy.org/GH162.html">GH162</option>
+<option value="http://www.cazy.org/GH163.html">GH163</option>
+<option value="http://www.cazy.org/GH164.html">GH164</option>
+<option value="http://www.cazy.org/GH165.html">GH165</option>
+<option value="http://www.cazy.org/GH166.html">GH166</option>
+<option value="http://www.cazy.org/GH167.html">GH167</option>
+<option value="http://www.cazy.org/GH168.html">GH168</option>
+<option value="http://www.cazy.org/GH169.html">GH169</option>
+<option value="http://www.cazy.org/GH170.html">GH170</option>
+<option value="http://www.cazy.org/GH0.html">NC</option>
+</select><input class="btn_deroul" onclick="gothere()" type="button" value="Go"/>
+</form>
+</div>
+<div style="position:absolute;right:50px;"><a id="formulaire_recherche" name="formulaire_recherche"></a>
+<form action="search" enctype="x-www-form-urlencoded" method="get" name="searchform">
+<input name="page" type="hidden" value="recherche"/>
+<input class="forml" id="q" name="recherche" onfocus="this.value='';" type="text" value="..."/>
+<select id="tag" name="tag">
+<option value="11">Family</option>
+<option value="1">Tax_id</option>
+<option value="2">Organism name</option>
+<option value="3">Protein name</option>
+<option value="4">GenBank accession</option>
+<option value="10">Uniprot accession</option>
+<option value="8">PDB accession</option>
+<option value="12">Carb_ligand</option>
+<option value="9">EC number</option>
+<option value="5">Known activities</option>
+<option value="6">Mechanisms</option>
+<option value="7">Clan</option>
+<option value="">Site</option>
+</select>
+<input class="bouton" type="submit" value="Go"/>
+</form>
+</div>
+</div>
+<div><h1 style="color:#00688B;">Glycoside Hydrolase Family 1 
+</h1></div>
+<table border="0" cellpadding="1" cellspacing="1">
+<tr><th align="left" class="thsum" valign="top"> Activities in Family</th><td class="tdsum">β-glucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.21" target="_link">3.2.1.21</a>); β-galactosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.23" target="_link">3.2.1.23</a>); β-mannosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.25" target="_link">3.2.1.25</a>); β-glucuronidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.31" target="_link">3.2.1.31</a>); β-xylosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.37" target="_link">3.2.1.37</a>); β-D-fucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.38" target="_link">3.2.1.38</a>); phlorizin hydrolase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.62" target="_link">3.2.1.62</a>); exo-β-1,4-glucanase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.74" target="_link">3.2.1.74</a>); 6-phospho-β-galactosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.85" target="_link">3.2.1.85</a>); 6-phospho-β-glucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.86" target="_link">3.2.1.86</a>); strictosidine β-glucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.105" target="_link">3.2.1.105</a>); lactase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.108" target="_link">3.2.1.108</a>); amygdalin β-glucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.117" target="_link">3.2.1.117</a>); prunasin β-glucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.118" target="_link">3.2.1.118</a>); vicianin hydrolase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.119" target="_link">3.2.1.119</a>); raucaffricine β-glucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.125" target="_link">3.2.1.125</a>); thioglucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.147" target="_link">3.2.1.147</a>); β-primeverosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.149" target="_link">3.2.1.149</a>); isoflavonoid 7-O-β-apiosyl-β-glucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.161" target="_link">3.2.1.161</a>); ABA-specific β-glucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.175" target="_link">3.2.1.175</a>); DIMBOA β-glucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.182" target="_link">3.2.1.182</a>); β-glycosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.*" target="_link">3.2.1.-</a>); hydroxyisourate hydrolase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.*.*.*" target="_link">3.-.-.-</a>); β-rutinosidase /α-L-rhamnose-(1,6)-β-D-glucosidase (EC <a class="nav5" href="http://www.enzyme-database.org/query.php?ec=3.2.1.*" target="_link">3.2.1.-</a>)</td></tr>
+<tr><th align="left" class="thsum" valign="top">Mechanism</th> <td class="tdsum">Retaining</td></tr>
+<tr><th align="left" class="thsum" valign="top">Clan</th><td class="tdsum">GH-A</td></tr>
+<tr><th align="left" class="thsum" valign="top">3D Structure Status</th><td class="tdsum">( β / α ) <sub>8</sub> barrel</td></tr>
+<tr><th align="left" class="thsum" valign="top">Catalytic Nucleophile/Base</th><td class="tdsum">Glu (experimental)</td></tr>
+<tr><th align="left" class="thsum" valign="top">Catalytic Proton Donor</th><td class="tdsum">Glu (experimental); absent in plant myrosinases</td></tr>
+<tr><th align="left" class="thsum" valign="top">External resources</th><td class="tdsum"><a href="http://www.cazypedia.org/index.php/Glycoside_Hydrolase_Family_1" target="link"><b><font class="color1">CAZypedia</font></b></a>; <a href="http://mizuguchilab.org/cgi-bin/homstrad/showpage.cgi?family=ghf1" target="link">HOMSTRAD</a>; <a href="http://www.bioinf.man.ac.uk/cgi-bin/dbbrowser/PRINTS/DoPRINTS.pl?cmd_a=Display&amp;qua_a=/Full&amp;fun_a=Code&amp;qst_a=GLHYDRLASE1" target="link">PRINTS</a>; <a href="http://prosite.expasy.org/PDOC00495" target="link">PROSITE</a>; </td></tr>
+<tr><th align="left" class="thsum" valign="top">Commercial Enzyme Provider(s)</th><td class="tdsum"><a href="http://secure.megazyme.com/enzymes/carbohydrate-active-enzymes/glycoside-hydrolases/gh1" target="link">MEGAZYME</a>; <a href="https://www.nzytech.com/site/GH1" target="link">NZYTech</a>; <a href="http://www.prozomix.com/products/CAZy/GH/1" target="link">PROZOMIX</a>; </td></tr>
+<tr><th align="left" class="thsum" valign="top">Statistics</th><td class="tdsum"> GenBank accession (44751); Uniprot accession (2300);   PDB accession (284); 3D entries (75); cryst (0)</td></tr>
+</table>
+<div class="afficher_par">
+<div class="pos_sum">
+<span class="summary" id="line_inactif"><a href="http://www.cazy.org/GH1.html">Summary</a></span>
+</div>
+<div class="pos_choix">
+<span class="choix"><a href="http://www.cazy.org/GH1_all.html">All</a> (42647)</span>
+<span class="choix"><a href="http://www.cazy.org/GH1_archaea.html">Archaea</a> (173)</span>
+<span class="choix" id="line_actif"><a href="http://www.cazy.org/GH1_bacteria.html">Bacteria</a> (40393)</span>
+<span class="choix"><a href="http://www.cazy.org/GH1_eukaryota.html">Eukaryota</a> (2016)</span>
+<span class="choix"><a href="http://www.cazy.org/GH1_viruses.html">Viruses</a> (4)</span>
+<span class="choix"><a href="http://www.cazy.org/GH1_unclassified.html">unclassified</a> (61)</span>
+<span class="choix"><a href="http://www.cazy.org/GH1_structure.html">Structure</a> (75)</span>
+<span class="choix"><a href="http://www.cazy.org/GH1_characterized.html">Characterized</a> (331)</span>
+</div>
+</div>
+<table cellpadding="2" cellspacing="0" class="listing" id="pos_onglet" width="100%">
+<tr id="line_titre"><td colspan="7"><a id="pagination_TAXO" name="pagination_TAXO"></a>
+<span class="prev disabled"><strong class="on" rel="prev">&lt;</strong><span class="sep"> | </span></span><span class="pages"><strong class="on">1</strong><span class="sep"> | </span><a class="lien_pagination" href="GH1_bacteria.html?debut_TAXO=100#pagination_TAXO" rel="nofollow">2</a><span class="sep"> | </span><a class="lien_pagination" href="GH1_bacteria.html?debut_TAXO=200#pagination_TAXO" rel="nofollow">3</a><span class="sep"> | </span><a class="lien_pagination" href="GH1_bacteria.html?debut_TAXO=300#pagination_TAXO" rel="nofollow">4</a><span class="sep"> | </span><a class="lien_pagination" href="GH1_bacteria.html?debut_TAXO=400#pagination_TAXO" rel="nofollow">5</a><span class="sep"> | </span><a class="lien_pagination" href="GH1_bacteria.html?debut_TAXO=500#pagination_TAXO" rel="nofollow">6</a><span class="sep"> | </span><a class="lien_pagination" href="GH1_bacteria.html?debut_TAXO=600#pagination_TAXO" rel="nofollow">7</a><span class="sep"> | </span><a class="lien_pagination" href="GH1_bacteria.html?debut_TAXO=700#pagination_TAXO" rel="nofollow">8</a><span class="sep"> | </span><a class="lien_pagination" href="GH1_bacteria.html?debut_TAXO=800#pagination_TAXO" rel="nofollow">9</a><span class="tbc"><span class="sep"> | </span>...<span class="sep"> | </span></span><a class="lien_pagination" href="GH1_bacteria.html?debut_TAXO=40300#pagination_TAXO" rel="nofollow">404</a></span><span class="next"><span class="sep"> | </span><a class="lien_pagination" href="GH1_bacteria.html?debut_TAXO=100#pagination_TAXO" rel="next">&gt;</a></span></td></tr>
+<tr class="royaume"><td class="separateur1" colspan="7"><span class="tabulation">Bacteria</span></td></tr>
+<tr id="line_titre"><td>Protein Name</td> <td>EC#</td><td>Organism</td><td>GenBank</td>
+<td>Uniprot</td><td>PDB/3D</td><td></td></tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> FOC79_02605</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b17914.html"><b>Abiotrophia defectiva FDAARGOS_785</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKH46569.1" target="_link"><b>QKH46569.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_21620</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK23259.1" target="_link"><b>BBK23259.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_22860 (Bgla_6)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK23383.1" target="_link"><b>BBK23383.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_21400</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK23237.1" target="_link"><b>BBK23237.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_17710</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK22868.1" target="_link"><b>BBK22868.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_19340 (Bgla_4)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK23031.1" target="_link"><b>BBK23031.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_19330 (Bgla_3)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK23030.1" target="_link"><b>BBK23030.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_08810 (Bgla_1)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK21978.1" target="_link"><b>BBK21978.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_17620 (Bgla_1)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK22859.1" target="_link"><b>BBK22859.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_17640 (Bgla_2)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK22861.1" target="_link"><b>BBK22861.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_17880 (Bgl2)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK22885.1" target="_link"><b>BBK22885.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_19660</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK23063.1" target="_link"><b>BBK23063.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_17720 (Bgla_2)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK22869.1" target="_link"><b>BBK22869.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_11290 (AscB)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK22226.1" target="_link"><b>BBK22226.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_19650 (Bgla_5)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK23062.1" target="_link"><b>BBK23062.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Aargi30884_17740</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b16549.html"><b>Absiella argi JCM 30884</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BBK22871.1" target="_link"><b>BBK22871.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> AM1_2790</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b650.html"><b>Acaryochloris marina MBIC11017</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=ABW27791.1" target="_link"><b>ABW27791.1</b></a></td>
+<td id="separateur2"><a href="http://www.uniprot.org/uniprot/B0C9B0" target="_link">B0C9B0</a></td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> A0U92_13925</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b7775.html"><b>Acetobacter aceti TMW2.1153</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AQS85685.1" target="_link"><b>AQS85685.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> HN018_15625</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b17883.html"><b>Acetobacteraceae bacterium PAMC 26569</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKE92698.1" target="_link"><b>QKE92698.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> HN018_01410</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b17883.html"><b>Acetobacteraceae bacterium PAMC 26569</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKE88886.1" target="_link"><b>QKE88886.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> HN018_18820 (fragment)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b17883.html"><b>Acetobacteraceae bacterium PAMC 26569</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKE91811.1" target="_link"><b>QKE91811.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> DVB37_19860</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b11900.html"><b>Achromobacter sp. B7</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AYD65923.1" target="_link"><b>AYD65923.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> PACID_18180</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b2371.html"><b>Acidipropionibacterium acidipropionici ATCC 4875</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AFV89622.1" target="_link"><b>AFV89622.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> PACID_31000</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b2371.html"><b>Acidipropionibacterium acidipropionici ATCC 4875</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AFV90860.1" target="_link"><b>AFV90860.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> AXH35_08515</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b5802.html"><b>Acidipropionibacterium acidipropionici ATCC 55737</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AMS05482.1" target="_link"><b>AMS05482.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> AXH35_01995</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b5802.html"><b>Acidipropionibacterium acidipropionici ATCC 55737</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AMS04430.1" target="_link"><b>AMS04430.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> AXH35_13535</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b5802.html"><b>Acidipropionibacterium acidipropionici ATCC 55737</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AMS06312.1" target="_link"><b>AMS06312.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ASQ49_12470</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b5196.html"><b>Acidipropionibacterium acidipropionici CGMCC 1.2230</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=ALN15937.1" target="_link"><b>ALN15937.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ASQ49_06685</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b5196.html"><b>Acidipropionibacterium acidipropionici CGMCC 1.2230</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=ALN15016.1" target="_link"><b>ALN15016.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> A8L58_03460</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b6996.html"><b>Acidipropionibacterium acidipropionici F3E8</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AOZ45925.1" target="_link"><b>AOZ45925.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> A8L58_09960</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b6996.html"><b>Acidipropionibacterium acidipropionici F3E8</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AOZ46954.1" target="_link"><b>AOZ46954.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> A8L58_14985</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b6996.html"><b>Acidipropionibacterium acidipropionici F3E8</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AOZ47766.1" target="_link"><b>AOZ47766.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> FEZ30_00740</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b14168.html"><b>Acidipropionibacterium acidipropionici FAM 19036</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QCV93992.1" target="_link"><b>QCV93992.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> DUY81_09800</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b12592.html"><b>Acidipropionibacterium acidipropionici WGS7</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AZP38059.1" target="_link"><b>AZP38059.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> DUY81_03225</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b12592.html"><b>Acidipropionibacterium acidipropionici WGS7</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AZP36953.1" target="_link"><b>AZP36953.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> DUY81_14840</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b12592.html"><b>Acidipropionibacterium acidipropionici WGS7</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AZP38895.1" target="_link"><b>AZP38895.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> BWX38_08240</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b7558.html"><b>Acidipropionibacterium acidipropionici WSH1105</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=APZ09231.1" target="_link"><b>APZ09231.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> BWX38_02430</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b7558.html"><b>Acidipropionibacterium acidipropionici WSH1105</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=APZ08315.1" target="_link"><b>APZ08315.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> FEZ32_05770</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b14169.html"><b>Acidipropionibacterium jensenii FAM 19038</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QCV87940.1" target="_link"><b>QCV87940.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> C0Z11_00970</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b12956.html"><b>Acidipropionibacterium jensenii JS279</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AZZ41094.1" target="_link"><b>AZZ41094.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> C0Z10_01085</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b12964.html"><b>Acidipropionibacterium jensenii JS280</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AZZ38576.1" target="_link"><b>AZZ38576.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> NCTC13652_01820</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b12930.html"><b>Acidipropionibacterium jensenii NCTC13652</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=VEI03613.1" target="_link"><b>VEI03613.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> JS278_02569 (BglA)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b11329.html"><b>Acidipropionibacterium virtanenii JS278</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AXE39707.1" target="_link"><b>AXE39707.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ACPOL_1431</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b11356.html"><b>Acidisarcina polymorpha SBC82</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AXC10777.1" target="_link"><b>AXC10777.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ACPOL_5891</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b11356.html"><b>Acidisarcina polymorpha SBC82</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AXC15135.1" target="_link"><b>AXC15135.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ACPOL_5708</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b11356.html"><b>Acidisarcina polymorpha SBC82</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AXC14954.1" target="_link"><b>AXC14954.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ACPOL_1889</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b11356.html"><b>Acidisarcina polymorpha SBC82</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AXC11229.1" target="_link"><b>AXC11229.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> LuPra_05070 (fragment) </td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b5904.html"><b>Acidobacteria bacterium DSM 100886</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AMY11805.1" target="_link"><b>AMY11805.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Acel_0133</td>
+<td align="left" id="separateur2"><font class="E"><a href="http://www.enzyme-database.org/query.php?ec=3.2.1.21" target="_link">3.2.1.21</a></font></td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b455.html"><b>Acidothermus cellulolyticus 11B</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=ABK51908.1" target="_link"><b>ABK51908.1</b></a></td>
+<td id="separateur2"><a href="http://www.uniprot.org/uniprot/A0LR48" target="_link">A0LR48</a></td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> HWI77_17920</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b18779.html"><b>Acinetobacter venetianus TUST-DM21</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QNH52898.1" target="_link"><b>QNH52898.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> UA74_23590</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b7433.html"><b>Actinoalloteichus fjordicus ADI127-7</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=APU16736.1" target="_link"><b>APU16736.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> UA74_21070</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b7433.html"><b>Actinoalloteichus fjordicus ADI127-7</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=APU16239.1" target="_link"><b>APU16239.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> UA74_06755</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b7433.html"><b>Actinoalloteichus fjordicus ADI127-7</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=APU13422.1" target="_link"><b>APU13422.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> UA74_11810</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b7433.html"><b>Actinoalloteichus fjordicus ADI127-7</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=APU14422.1" target="_link"><b>APU14422.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> AHOG_18020 (Bgla2) (fragment) </td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b8712.html"><b>Actinoalloteichus hoggarensis DSM 45943</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=ASO21229.1" target="_link"><b>ASO21229.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> AHOG_18590 (Bglb3)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b8712.html"><b>Actinoalloteichus hoggarensis DSM 45943</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=ASO21343.1" target="_link"><b>ASO21343.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> AHOG_11140 (Bglb2)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b8712.html"><b>Actinoalloteichus hoggarensis DSM 45943</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=ASO19871.1" target="_link"><b>ASO19871.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> AHOG_06540 (Bglb1)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b8712.html"><b>Actinoalloteichus hoggarensis DSM 45943</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=ASO18958.1" target="_link"><b>ASO18958.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> TL08_17660</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b6739.html"><b>Actinoalloteichus hymeniacidonis HPA177(T) (=DSM 45092(T))</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AOS64332.1" target="_link"><b>AOS64332.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> TL08_11125</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b6739.html"><b>Actinoalloteichus hymeniacidonis HPA177(T) (=DSM 45092(T))</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AOS63039.1" target="_link"><b>AOS63039.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> TL08_07050</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b6739.html"><b>Actinoalloteichus hymeniacidonis HPA177(T) (=DSM 45092(T))</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AOS62230.1" target="_link"><b>AOS62230.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> C1701_20965</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b9814.html"><b>Actinoalloteichus sp. AHMU CJ021</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AUS80405.1" target="_link"><b>AUS80405.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> C1701_17945</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b9814.html"><b>Actinoalloteichus sp. AHMU CJ021</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AUS79898.1" target="_link"><b>AUS79898.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> UA75_11895</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b7436.html"><b>Actinoalloteichus sp. GBA129-24</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=APU20391.1" target="_link"><b>APU20391.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> UA75_24100</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b7436.html"><b>Actinoalloteichus sp. GBA129-24</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=APU22802.1" target="_link"><b>APU22802.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> UA75_21550</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b7436.html"><b>Actinoalloteichus sp. GBA129-24</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=APU22299.1" target="_link"><b>APU22299.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> UA75_06755</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b7436.html"><b>Actinoalloteichus sp. GBA129-24</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=APU19372.1" target="_link"><b>APU19372.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Asuc_0973</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b591.html"><b>Actinobacillus succinogenes 130Z</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=ABR74341.1" target="_link"><b>ABR74341.1</b></a></td>
+<td id="separateur2"><a href="http://www.uniprot.org/uniprot/A6VMZ4" target="_link">A6VMZ4</a></td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ASU1_08285</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b3562.html"><b>Actinobacillus suis ATCC 33415</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AIJ31916.1" target="_link"><b>AIJ31916.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ASU2_08215</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b2320.html"><b>Actinobacillus suis H91-0380</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AFU19777.1" target="_link"><b>AFU19777.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> SAMEA4504061_01733 (BglH)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b8845.html"><b>Actinobacillus suis NCTC12996</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=SNV37135.1" target="_link"><b>SNV37135.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> DLE03_00925</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b18498.html"><b>Actinobacteria bacterium IMCC25003</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QLL22964.1" target="_link"><b>QLL22964.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> IMCC26256_112016</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b4661.html"><b>Actinobacteria bacterium IMCC26256</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AKL74284.1" target="_link"><b>AKL74284.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> IMCC26256_111571</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b4661.html"><b>Actinobacteria bacterium IMCC26256</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AKL73841.1" target="_link"><b>AKL73841.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> EF847_12770</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b12240.html"><b>Actinobacteria bacterium YIM 96077</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AYY13434.1" target="_link"><b>AYY13434.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> EF847_09525</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b12240.html"><b>Actinobacteria bacterium YIM 96077</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AYY12907.1" target="_link"><b>AYY12907.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Athai_43030</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b19958.html"><b>Actinocatenispora thailandica NBRC 105041</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BCJ36800.1" target="_link"><b>BCJ36800.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> Athai_35170 (BglB)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b19958.html"><b>Actinocatenispora thailandica NBRC 105041</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BCJ36014.1" target="_link"><b>BCJ36014.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> HUT06_05575</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b18344.html"><b>Actinomadura sp. NAK00032</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKW40205.1" target="_link"><b>QKW40205.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> HUT06_34125</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b18344.html"><b>Actinomadura sp. NAK00032</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKW38433.1" target="_link"><b>QKW38433.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> HUT06_02720</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b18344.html"><b>Actinomadura sp. NAK00032</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKW33080.1" target="_link"><b>QKW33080.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> HUT06_42275</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b18344.html"><b>Actinomadura sp. NAK00032</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKW39842.1" target="_link"><b>QKW39842.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> HUT06_29785</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b18344.html"><b>Actinomadura sp. NAK00032</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKW37684.1" target="_link"><b>QKW37684.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> HUT06_29735</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b18344.html"><b>Actinomadura sp. NAK00032</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKW37675.1" target="_link"><b>QKW37675.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> F7P10_06280</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b15263.html"><b>Actinomadura sp. WMMB499</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QFG26875.1" target="_link"><b>QFG26875.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> F7P10_29030</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b15263.html"><b>Actinomadura sp. WMMB499</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QFG24579.1" target="_link"><b>QFG24579.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> F7P10_14420</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b15263.html"><b>Actinomadura sp. WMMB499</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QFG22147.1" target="_link"><b>QFG22147.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> F7P10_09305</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b15263.html"><b>Actinomadura sp. WMMB499</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QFG21303.1" target="_link"><b>QFG21303.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> F7P10_14510</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b15263.html"><b>Actinomadura sp. WMMB499</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QFG22157.1" target="_link"><b>QFG22157.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> F7P10_06320</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b15263.html"><b>Actinomadura sp. WMMB499</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QFG20817.1" target="_link"><b>QFG20817.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ACTIVE_2564</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b17905.html"><b>Actinomadura verrucosospora NRRL:B18236</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKG20926.1" target="_link"><b>QKG20926.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ACTIVE_2572</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b17905.html"><b>Actinomadura verrucosospora NRRL:B18236</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKG20934.1" target="_link"><b>QKG20934.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ACTIVE_3402</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b17905.html"><b>Actinomadura verrucosospora NRRL:B18236</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKG21764.1" target="_link"><b>QKG21764.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ACTIVE_6286</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b17905.html"><b>Actinomadura verrucosospora NRRL:B18236</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKG24637.1" target="_link"><b>QKG24637.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ACTIVE_5659</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b17905.html"><b>Actinomadura verrucosospora NRRL:B18236</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKG24016.1" target="_link"><b>QKG24016.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> ACTIVE_3523</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b17905.html"><b>Actinomadura verrucosospora NRRL:B18236</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKG21885.1" target="_link"><b>QKG21885.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> NCTC11636_00151 (BglH)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b12924.html"><b>Actinomyces howellii NCTC11636</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=VEG25666.1" target="_link"><b>VEG25666.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> HPC72_05005</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b17854.html"><b>Actinomyces marmotae zg-325</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=QKD79694.1" target="_link"><b>QKD79694.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> β-glucosidase (Bg12)</td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?id=1655" target="ncbitaxid">Actinomyces naeslundii</a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=AAK33123.1" target="_link"><b>AAK33123.1</b></a><br/>ABH84884.1<br/>ACW33393.1<br/>CAD42490.1<br/>CAR96694.1<br/>CBG21233.1</td>
+<td id="separateur2"><a href="http://www.uniprot.org/uniprot/Q9AEN6" target="_link">Q9AEN6</a></td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr bgcolor="#ffffff" onmouseout="this.bgColor='#FFFFFF';" onmouseover="this.bgColor='#F8FFD5';" style="cursor: default;" valign="top">
+<td id="separateur2"> AN27039_2749 (fragment) </td>
+<td align="left" id="separateur2"> </td>
+<td id="separateur2">
+<a href="http://www.cazy.org/b6990.html"><b>Actinomyces naeslundii ATCC 27039</b></a>
+</td>
+<td id="separateur2"><a href="http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=protein&amp;val=BAV85819.1" target="_link"><b>BAV85819.1</b></a></td>
+<td id="separateur2"> </td>
+<td id="separateur2">  </td>
+<td align="center" id="separateur2"></td>
+</tr>
+<tr class="royaume"><td class="separateur1" colspan="7"><span class="tabulation"> <a href="#">Top</a></span></td></tr>
+</table>
+<br/><br/>
+	Last update: <b>2021-03-02</b>
+
+© Copyright <b>1998-2021</b><br/><a href="http://www.afmb.univ-mrs.fr/" target="_blank">AFMB - CNRS - Université d'Aix-Marseille</a> </div>
+</div>
+<!-- cadre_principal --> <script type="text/javascript">
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script> <script type="text/javascript">
+try {
+var pageTracker = _gat._getTracker("UA-12604774-1");
+pageTracker._trackPageview();
+} catch(err) {}</script>
+</body></html>
diff --git a/tests/test_inputs/test_inputs_crawler/protein_no_uniprot_no_pdb.html b/tests/test_inputs/test_inputs_crawler/protein_no_uniprot_no_pdb.html
new file mode 100644
index 00000000..d456c054
--- /dev/null
+++ b/tests/test_inputs/test_inputs_crawler/protein_no_uniprot_no_pdb.html
@@ -0,0 +1,10 @@
+<tr valign="top" onmouseover="this.bgColor='#F8FFD5';" onmouseout="this.bgColor='#FFFFFF';" style="cursor: default;" bgcolor="#ffffff">
+    <td id="separateur2">&nbsp;&beta;-glycosidase (&beta;-Gly;As&beta;-Gly;ASAC_1390)</td>
+    <td id="separateur2" align="left"><font class="E"><a href="http://www.enzyme-database.org/query.php?ec=3.2.1.*" target="_link">3.2.1.-</a></font></td>
+    <td id="separateur2"><a href="http://www.cazy.org/b8681.html"><b>Bacteroides caccae ATCC 43185</b></a></td>
+    <td id="separateur2"></td>
+    <td id="separateur2"></td>
+    <td id="separateur2"></td>
+                
+     <td id="separateur2" align="center"></td>
+</tr>
diff --git a/tests/test_inputs/test_inputs_file_io/config_all_classes.yaml b/tests/test_inputs/test_inputs_file_io/config_all_classes.yaml
deleted file mode 100644
index 9bb08691..00000000
--- a/tests/test_inputs/test_inputs_file_io/config_all_classes.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-classes:  # classes from which all proteins will be retrieved
-  - "GH"
-  - "PL"
-Glycoside Hydrolases (GHs):
-  - "GH147"
-GlycosylTransferases (GTs):
-  - "GT2"
-Polysaccharide Lyases (PLs):
-  - "PL1"
-Carbohydrate Esterases (CEs):
-  - "CE1"
-Auxiliary Activities (AAs):
-  - "AA10"
-Carbohydrate-Binding Modules (CBMs):
-  - "CBM5"
\ No newline at end of file
diff --git a/tests/test_inputs/test_inputs_file_io/config_file.yaml b/tests/test_inputs/test_inputs_file_io/config_file.yaml
deleted file mode 100644
index 235ef8cc..00000000
--- a/tests/test_inputs/test_inputs_file_io/config_file.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-# Under 'classes' list class from which all proteins will retrieved
-# Under each families respective name, list the specific families/subfamilies to be scraped
-# Write the FULL family name, e.g. 'GH1', NOT only its number, e.g. '1'
-# To list multiple families, each familiy must be on a new line starting indented once
-# relative to the parent class name, and the name written within quotation marks.
-# For more information on writing lists in Yaml please see:
-# https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html 
-classes:  # classes from which all proteins will be retrieved
-  - "GH"
-  - "PL"
-Glycoside Hydrolases (GHs):
-  - "GH147"
-GlycosylTransferases (GTs):
-Polysaccharide Lyases (PLs):
-  - "PL17"
-Carbohydrate Esterases (CEs):
-Auxiliary Activities (AAs):
-Carbohydrate-Binding Modules (CBMs):
\ No newline at end of file
diff --git a/tests/test_inputs/test_inputs_file_io/config_no_class_tag.yaml b/tests/test_inputs/test_inputs_file_io/config_no_class_tag.yaml
deleted file mode 100644
index cff92a3c..00000000
--- a/tests/test_inputs/test_inputs_file_io/config_no_class_tag.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-# Under 'classes' list class from which all proteins will retrieved
-# Under each families respective name, list the specific families/subfamilies to be scraped
-# Write the FULL family name, e.g. 'GH1', NOT only its number, e.g. '1'
-# To list multiple families, each familiy must be on a new line starting indented once
-# relative to the parent class name, and the name written within quotation marks.
-# For more information on writing lists in Yaml please see:
-# https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html 
-Glycoside Hydrolases (GHs):
-  - "GH147"
-GlycosylTransferases (GTs):
-Polysaccharide Lyases (PLs):
-Carbohydrate Esterases (CEs):
-Auxiliary Activities (AAs):
-Carbohydrate-Binding Modules (CBMs):
\ No newline at end of file
diff --git a/tests/test_inputs/test_inputs_file_io/config_no_classes.yaml b/tests/test_inputs/test_inputs_file_io/config_no_classes.yaml
deleted file mode 100644
index c9c53fa3..00000000
--- a/tests/test_inputs/test_inputs_file_io/config_no_classes.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-# Under 'classes' list class from which all proteins will retrieved
-# Under each families respective name, list the specific families/subfamilies to be scraped
-# Write the FULL family name, e.g. 'GH1', NOT only its number, e.g. '1'
-# To list multiple families, each familiy must be on a new line starting indented once
-# relative to the parent class name, and the name written within quotation marks.
-# For more information on writing lists in Yaml please see:
-# https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html 
-classes:  # classes from which all proteins will be retrieved
-Glycoside Hydrolases (GHs):
-  - "GH147"
-GlycosylTransferases (GTs):
-Polysaccharide Lyases (PLs):
-Carbohydrate Esterases (CEs):
-Auxiliary Activities (AAs):
-Carbohydrate-Binding Modules (CBMs):
\ No newline at end of file
diff --git a/tests/test_inputs/test_inputs_file_io/config_with_classes.yaml b/tests/test_inputs/test_inputs_file_io/config_with_classes.yaml
deleted file mode 100644
index df047a55..00000000
--- a/tests/test_inputs/test_inputs_file_io/config_with_classes.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-# Under 'classes' list class from which all proteins will retrieved
-# Under each families respective name, list the specific families/subfamilies to be scraped
-# Write the FULL family name, e.g. 'GH1', NOT only its number, e.g. '1'
-# To list multiple families, each familiy must be on a new line starting indented once
-# relative to the parent class name, and the name written within quotation marks.
-# For more information on writing lists in Yaml please see:
-# https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html 
-classes:  # classes from which all proteins will be retrieved
-  - "GH"
-  - "PL"
-Glycoside Hydrolases (GHs):
-  - "GH147"
-GlycosylTransferases (GTs):
-Polysaccharide Lyases (PLs):
-Carbohydrate Esterases (CEs):
-Auxiliary Activities (AAs):
-Carbohydrate-Binding Modules (CBMs):
\ No newline at end of file
diff --git a/tests/test_inputs/test_inputs_parse_configuration/config_file.yaml b/tests/test_inputs/test_inputs_parse_configuration/config_file.yaml
new file mode 100644
index 00000000..6964c7ea
--- /dev/null
+++ b/tests/test_inputs/test_inputs_parse_configuration/config_file.yaml
@@ -0,0 +1,19 @@
+classes:
+  - 'GH'
+  - 'PL'
+Glycoside Hydrolases (GHs):
+  - 'GH147'
+GlycosylTransferases (GTs):
+Polysaccharide Lyases (PLs):
+  - 'PL17'
+Carbohydrate Esterases (CEs):
+Auxiliary Activities (AAs):
+Carbohydrate-Binding Modules (CBMs):
+genera:
+  - 'Trichoderma'
+species:
+  - 'Trichoderma reesei'
+  - 'Aspergillus niger'
+strains:
+  - 'Clostridium botulinum IBCA10-7060'
+  - 'Bacillus endophyticus Hbe603'
\ No newline at end of file
diff --git a/tests/test_inputs/test_inputs_sql/.ipynb_checkpoints/Untitled-checkpoint.ipynb b/tests/test_inputs/test_inputs_sql/.ipynb_checkpoints/Untitled-checkpoint.ipynb
new file mode 100644
index 00000000..7fec5150
--- /dev/null
+++ b/tests/test_inputs/test_inputs_sql/.ipynb_checkpoints/Untitled-checkpoint.ipynb
@@ -0,0 +1,6 @@
+{
+ "cells": [],
+ "metadata": {},
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/tests/test_inputs/test_inputs_sql/unit_test_db_2021-03-01--15-06-59.db b/tests/test_inputs/test_inputs_sql/unit_test_db_2021-03-01--15-06-59.db
new file mode 100644
index 00000000..01d3edd7
Binary files /dev/null and b/tests/test_inputs/test_inputs_sql/unit_test_db_2021-03-01--15-06-59.db differ
diff --git a/tests/test_outputs/test_log b/tests/test_outputs/test_log
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/test_outputs/test_outputs_file_io/failed_cazy_scrapes_time_stamp.txt b/tests/test_outputs/test_outputs_file_io/failed_cazy_scrapes_time_stamp.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/test_outputs/test_outputs_file_io/failed_db_protein_additions_time_stamp.txt b/tests/test_outputs/test_outputs_file_io/failed_db_protein_additions_time_stamp.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/test_outputs/test_outputs_file_io/testing_making_dir/test_writing_df.csv.csv b/tests/test_outputs/test_outputs_file_io/testing_making_dir/test_writing_df.csv.csv
deleted file mode 100644
index a1c9c60f..00000000
--- a/tests/test_outputs/test_outputs_file_io/testing_making_dir/test_writing_df.csv.csv
+++ /dev/null
@@ -1,2 +0,0 @@
-,C1,C2,C3
-0,A,B,C
diff --git a/tests/test_outputs/test_outputs_sql/cazy_scrape_2021-02-08--10-58-51.db b/tests/test_outputs/test_outputs_sql/cazy_scrape_2021-02-08--10-58-51.db
new file mode 100644
index 00000000..3e192fd4
Binary files /dev/null and b/tests/test_outputs/test_outputs_sql/cazy_scrape_2021-02-08--10-58-51.db differ
diff --git a/tests/test_parse.py b/tests/test_parse.py
deleted file mode 100644
index 7b1eb751..00000000
--- a/tests/test_parse.py
+++ /dev/null
@@ -1,607 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-# Author:
-# Emma E. M. Hobbs
-
-# Contact
-# eemh1@st-andrews.ac.uk
-
-# Emma E. M. Hobbs,
-# Biomolecular Sciences Building,
-# University of St Andrews,
-# North Haugh Campus,
-# St Andrews,
-# KY16 9ST
-# Scotland,
-# UK
-
-# The MIT License
-
-"""Tests the module parse which parses the protein data to produce a dataframe.
-
-These test are intened to be run from the root of the repository using:
-pytest -v
-
-"""
-
-
-import json
-import pytest
-import sys
-
-import numpy as np
-import pandas as pd
-
-from argparse import Namespace
-from unittest.mock import patch, mock_open
-
-from Bio.PDB import PDBList
-
-from scraper import cazy_webscraper, crawler, parse
-
-
-@pytest.fixture
-def out_dir(test_dir):
-    path = test_dir / "test_outputs" / "test_outputs_parse"
-    return path
-
-
-@pytest.fixture
-def family():
-    family = crawler.Family("GH1_test", "GHtest")
-
-    protein = crawler.Protein(
-        "protein_name",
-        "GH1",
-        "1.2.3.4",
-        "organism",
-        {"GenBank": ["link1"], "UniProt": ["link2"], "PDB/3D": ["link3"]},
-        {"link1": ["A", "B", "C"]},
-    )
-    family.members.add(protein)
-
-    protein = None
-    family.members.add(protein)
-
-    protein = crawler.Protein(
-        "protein",
-        "GH1",
-        "",
-        "organism",
-        {"GenBank": ["link1"], "UniProt": ["link2"], "PDB": ["link3"]},
-    )
-    family.members.add(protein)
-
-    return family
-
-
-@pytest.fixture
-def args_ds_fam_no_subfam(out_dir):
-    args_dict = {
-        "args": Namespace(
-            subfamilies=False,
-            data_split="family",
-            output=out_dir,
-            force=False,
-            genbank="dummy_email",
-            genbank_output=out_dir,
-            pdb="pdb",
-            pdb_output=out_dir,
-        )
-    }
-    return args_dict
-
-
-@pytest.fixture
-def args_ds_class_subfam(test_dir, out_dir):
-    args_dict = {
-        "args": Namespace(
-            subfamilies=True,
-            data_split="class",
-            output=out_dir,
-            force=False,
-            genbank="dummy_email",
-            genbank_output=test_dir,
-            pdb=None,
-            pdb_output=None,
-        )
-    }
-    return args_dict
-
-
-@pytest.fixture
-def args_ds_none(test_dir, out_dir):
-    args_dict = {
-        "args": Namespace(
-            subfamilies=False,
-            data_split=None,
-            output=out_dir,
-            force=False,
-            genbank=None,
-            genbank_output=None,
-            pdb="pdb",
-            pdb_output=test_dir,
-        )
-    }
-    return args_dict
-
-
-@pytest.fixture
-def protein_df():
-    column_names = [
-        "Protein_name",
-        "CAZy_family",
-        "EC#",
-        "Source_organism",
-        "GenBank",
-        "UniProt",
-        "PDB/3D",
-    ]
-
-    df_data = [
-        ["protein_1", "GH1", "1.2.3.4", "bact", "ABC12345.1", "U1", "P1,\nP2[B]"],
-        ["protein_2", "PL2", "1.2.3.4\n2.4.5.6", "euk", "1235G", "U1", ""],
-        ["protein_3", "CE3", np.nan, "bact", np.nan, np.nan, np.nan],
-    ]
-
-    df = pd.DataFrame(df_data, columns=column_names)
-
-    return df
-
-
-@pytest.fixture
-def df_name():
-    name = "test_df_name"
-    return name
-
-
-@pytest.fixture
-def args_output_no_pdb_output(out_dir):
-    args_dict = {
-        "args": Namespace(
-            subfamilies=False,
-            data_split=None,
-            output=out_dir,
-            force=False,
-            genbank="dummy_email",
-            genbank_output=out_dir,
-            pdb="pdb",
-            pdb_output=None,
-        )
-    }
-    return args_dict
-
-
-@pytest.fixture
-def args_no_output_no_pdb_output(out_dir):
-    args_dict = {
-        "args": Namespace(
-            subfamilies=False,
-            data_split=None,
-            output=sys.stdout,
-            force=False,
-            genbank="dummy_email",
-            genbank_output=out_dir,
-            pdb="pdb",
-            pdb_output=None,
-        )
-    }
-    return args_dict
-
-
-@pytest.fixture
-def df_row_float(protein_df):
-    row = protein_df.iloc[2]
-    return row
-
-
-@pytest.fixture
-def df_row_gb_format_wrong(protein_df):
-    row = protein_df.iloc[1]
-    return row
-
-
-@pytest.fixture
-def df_row_success(protein_df):
-    row = protein_df.iloc[0]
-    return row
-
-
-@pytest.fixture
-def args_args_gen_out_stdout(test_dir, out_dir):
-    args_dict = {
-        "args": Namespace(
-            subfamilies=False,
-            data_split="family",
-            output=test_dir,
-            force=False,
-            genbank="dummy_email",
-            genbank_output=sys.stdout,
-            pdb="pdb",
-            pdb_output=out_dir,
-        )
-    }
-    return args_dict
-
-
-@pytest.fixture
-def sequence_fasta(test_dir):
-    path = test_dir / "test_inputs" / "test_inputs_parse" / "sequence.fasta"
-    return path
-
-
-# test proteins_to_dataframe() (dataframe building function)
-
-
-def test_prt_to_df_ds_fam_no_subfams(
-    time_stamp,
-    args_ds_fam_no_subfam,
-    family,
-    null_logger,
-    monkeypatch,
-):
-    """Test proteins_to_dataframe when data split is family and subfamilies is False."""
-
-    with patch("builtins.open", mock_open(read_data="data")) as mock_file:
-
-        def mock_no_return(*args, **kwargs):
-            return
-
-        monkeypatch.setattr(parse, "write_out_df", mock_no_return)
-        monkeypatch.setattr(parse, "get_structures_and_sequences", mock_no_return)
-        monkeypatch.setattr(json, "dump", mock_no_return)
-
-        parse.proteins_to_dataframe(
-            [family],
-            time_stamp,
-            args_ds_fam_no_subfam["args"],
-            null_logger,
-        )
-
-
-def test_prt_to_df_ds_class_subfams(
-    time_stamp,
-    args_ds_class_subfam,
-    family,
-    null_logger,
-    monkeypatch,
-):
-    """Test proteins_to_dataframe when data split is class and subfamilies is True."""
-
-    with patch("builtins.open", mock_open(read_data="data")) as mock_file:
-
-        def mock_no_return(*args, **kwargs):
-            return
-
-        monkeypatch.setattr(parse, "write_out_df", mock_no_return)
-        monkeypatch.setattr(parse, "get_genbank_fasta", mock_no_return)
-
-        parse.proteins_to_dataframe([family], time_stamp, args_ds_class_subfam["args"], null_logger)
-
-
-def test_prt_to_df_ds_none(time_stamp, args_ds_none, family, null_logger, monkeypatch):
-    """Test proteins_to_dataframe when data split is None."""
-
-    with patch("builtins.open", mock_open(read_data="data")) as mock_file:
-
-        def mock_no_return(*args, **kwargs):
-            return
-
-        monkeypatch.setattr(parse, "write_out_df", mock_no_return)
-        monkeypatch.setattr(parse, "get_pdb_structures", mock_no_return)
-
-        parse.proteins_to_dataframe([family], time_stamp, args_ds_none["args"], null_logger)
-
-
-# test get_structures_and_sequences()
-
-
-def test_gt_s_p_pdb_out_given(protein_df, df_name, args_ds_fam_no_subfam, null_logger, monkeypatch):
-    """Test get_structures_and_sequences when no pdb_output given."""
-
-    def mock_genbank_accessions(*args, **kwargs):
-        return("genbank_accession", "GH1")
-
-    def mock_pdb_accessions(*args, **kwargs):
-        return["pdb1", "pdb2", "pdb3"]
-
-    def mock_no_return(*args, **kwargs):
-        return
-
-    monkeypatch.setattr(parse, "get_genbank_accession", mock_genbank_accessions)
-    monkeypatch.setattr(parse, "get_pdb_accessions", mock_pdb_accessions)
-    monkeypatch.setattr(parse, "download_fasta", mock_no_return)
-    monkeypatch.setattr(PDBList, "retrieve_pdb_file", mock_no_return)
-
-    parse.get_structures_and_sequences(
-        protein_df,
-        df_name,
-        args_ds_fam_no_subfam["args"],
-        null_logger,
-    )
-
-
-def test_gt_s_p_pdb_to_output(
-    protein_df,
-    df_name,
-    args_output_no_pdb_output,
-    null_logger,
-    monkeypatch,
-):
-    """Test get_structures_and_sequences when output but not pdb_output given."""
-
-    def mock_genbank_accessions(*args, **kwargs):
-        return("genbank_accession", "GH1")
-
-    def mock_pdb_accessions(*args, **kwargs):
-        return["pdb1", "pdb2", "pdb3"]
-
-    def mock_no_return(*args, **kwargs):
-        return
-
-    monkeypatch.setattr(parse, "get_genbank_accession", mock_genbank_accessions)
-    monkeypatch.setattr(parse, "get_pdb_accessions", mock_pdb_accessions)
-    monkeypatch.setattr(parse, "download_fasta", mock_no_return)
-    monkeypatch.setattr(PDBList, "retrieve_pdb_file", mock_no_return)
-
-    parse.get_structures_and_sequences(
-        protein_df,
-        df_name,
-        args_output_no_pdb_output["args"],
-        null_logger,
-    )
-
-
-def test_gt_s_p_pdb_to_cwd(
-    protein_df,
-    df_name,
-    args_no_output_no_pdb_output,
-    null_logger,
-    monkeypatch,
-):
-    """Test get_structures_and_sequences when no pdb_output given and output is stdout."""
-
-    def mock_genbank_accessions(*args, **kwargs):
-        return("genbank_accession", "GH1")
-
-    def mock_pdb_accessions(*args, **kwargs):
-        return["pdb1", "pdb2", "pdb3"]
-
-    def mock_no_return(*args, **kwargs):
-        return
-
-    monkeypatch.setattr(parse, "get_genbank_accession", mock_genbank_accessions)
-    monkeypatch.setattr(parse, "get_pdb_accessions", mock_pdb_accessions)
-    monkeypatch.setattr(parse, "download_fasta", mock_no_return)
-    monkeypatch.setattr(PDBList, "retrieve_pdb_file", mock_no_return)
-
-    parse.get_structures_and_sequences(
-        protein_df,
-        df_name,
-        args_no_output_no_pdb_output["args"],
-        null_logger,
-    )
-
-
-# test get_genbank_accession()
-
-
-def test_gb_acc_float(df_row_float, df_name, null_logger):
-    """Test get_genbank_accession when the GenBank cell contains a float data type."""
-    row_index = 1
-
-    return_acc, returned_fam = parse.get_genbank_accession(
-        df_row_float,
-        df_name,
-        row_index,
-        null_logger,
-    )
-
-    expected_acc = None
-    expected_fam = None
-
-    assert expected_acc == return_acc
-    assert expected_fam == returned_fam
-
-
-def test_gb_acc_re_fail(df_row_gb_format_wrong, df_name, null_logger):
-    """Test get_genbank_accession when the retrieve item does not match expected GenBank format."""
-    row_index = 1
-
-    return_acc, returned_fam = parse.get_genbank_accession(
-        df_row_gb_format_wrong,
-        df_name,
-        row_index,
-        null_logger,
-    )
-
-    expected_acc = None
-    expected_fam = None
-
-    assert expected_acc == return_acc
-    assert expected_fam == returned_fam
-
-
-def test_gb_acc_successful(df_row_success, df_name, null_logger):
-    """Test get_genbank_accession when fully successful."""
-    row_index = 1
-
-    return_acc, returned_fam = parse.get_genbank_accession(
-        df_row_success,
-        df_name,
-        row_index,
-        null_logger,
-    )
-
-    expected_acc = "ABC12345.1"
-    expected_fam = "GH1"
-
-    assert expected_acc == return_acc
-    assert expected_fam == returned_fam
-
-
-# test get_pdb_accession()
-
-
-def test_pdb_acc_float(df_row_float, df_name, null_logger):
-    """Test get_pdb_accessions when value in PDB cell is a float."""
-    assert None is parse.get_pdb_accessions(df_row_float, df_name, null_logger)
-
-
-def test_pdb_acc_suss(df_row_success, df_name, null_logger):
-    """Test get_pdb_accessions when successfull."""
-    expected = ["P1", "P2"]
-    assert expected == parse.get_pdb_accessions(df_row_success, df_name, null_logger)
-
-
-# test get_pdb_structures()
-
-
-def test_pdb_struc_pdb_out_given(
-    protein_df,
-    df_name,
-    args_ds_fam_no_subfam,
-    null_logger,
-    monkeypatch,
-):
-    """Test get_pdb_structures when pdb_output is given."""
-
-    def mock_no_return(*args, **kwargs):
-        return
-
-    monkeypatch.setattr(PDBList, "retrieve_pdb_file", mock_no_return)
-
-    parse.get_pdb_structures(protein_df, df_name, args_ds_fam_no_subfam["args"], null_logger)
-
-
-def test_pdb_struc_pdb_to_output(
-    protein_df,
-    df_name,
-    args_output_no_pdb_output,
-    null_logger,
-    monkeypatch,
-):
-    """Test get_pdb_structures when output not pdb_output is given."""
-
-    def mock_no_return(*args, **kwargs):
-        return
-
-    monkeypatch.setattr(PDBList, "retrieve_pdb_file", mock_no_return)
-
-    parse.get_pdb_structures(protein_df, df_name, args_output_no_pdb_output["args"], null_logger)
-
-
-def test_pdb_struc_pdb_to_cwd(
-    protein_df,
-    df_name,
-    args_no_output_no_pdb_output,
-    null_logger,
-    monkeypatch,
-):
-    """Test get_pdb_structures when output is sys.stdout and no pdb_output is given."""
-
-    def mock_no_return(*args, **kwargs):
-        return
-
-    monkeypatch.setattr(PDBList, "retrieve_pdb_file", mock_no_return)
-
-    parse.get_pdb_structures(protein_df, df_name, args_no_output_no_pdb_output["args"], null_logger)
-
-
-# Test get_genbank_fasta()
-
-def test_get_genbank_fasta(protein_df, df_name, args_ds_fam_no_subfam, null_logger, monkeypatch):
-    """Test get_genbank_fasta."""
-
-    def mock_download_fasta(*args, **kwargs):
-        return
-
-    monkeypatch.setattr(parse, "download_fasta", mock_download_fasta)
-
-    parse.get_genbank_fasta(protein_df, df_name, args_ds_fam_no_subfam["args"], null_logger)
-
-
-# Test download_fasta()
-
-
-def test_download_fasta_file_exists(args_ds_fam_no_subfam, out_dir, null_logger, monkeypatch):
-    """Test download_fasta() when file exists."""
-    file_name = out_dir / "existing_file.txt"
-    accession = "test_accession"
-
-    def mock_efetch(*args, **kwargs):
-        return
-
-    monkeypatch.setattr(parse, "entrez_retry", mock_efetch)
-
-    parse.download_fasta(accession, file_name, args_ds_fam_no_subfam["args"], null_logger)
-
-
-def test_download_fasta_handle_none(test_dir, args_ds_fam_no_subfam, null_logger, monkeypatch):
-    """Test download_fasta() when returned handle is None."""
-    file_name = test_dir / "test_outputs" / "test_output_parse" / "novel_fasta.fasta"
-    accession = "test_accession"
-
-    def mock_efetch(*args, **kwargs):
-        return
-
-    monkeypatch.setattr(parse, "entrez_retry", mock_efetch)
-
-    parse.download_fasta(accession, file_name, args_ds_fam_no_subfam["args"], null_logger)
-
-
-def test_download_fasta_when_out_dir_given(
-    sequence_fasta,
-    out_dir,
-    args_ds_fam_no_subfam,
-    null_logger,
-    monkeypatch,
-):
-    file_name = out_dir / "novel_fasta.fasta"
-    accession = "test_accession"
-
-    def mock_efetch(*args, **kwargs):
-        return sequence_fasta
-
-    monkeypatch.setattr(parse, "entrez_retry", mock_efetch)
-
-    parse.download_fasta(accession, file_name, args_ds_fam_no_subfam["args"], null_logger)
-
-
-def test_download_fasta_when_out_stdout(
-    sequence_fasta,
-    out_dir,
-    args_args_gen_out_stdout,
-    null_logger,
-    monkeypatch,
-):
-    file_name = out_dir / "novel_fasta.fasta"
-    accession = "test_accession"
-
-    def mock_efetch(*args, **kwargs):
-        return sequence_fasta
-
-    monkeypatch.setattr(parse, "entrez_retry", mock_efetch)
-
-    parse.download_fasta(accession, file_name, args_args_gen_out_stdout["args"], null_logger)
-
-
-# test entrez_retry()
-
-
-def test_entry_retry(null_logger):
-    """Test entrez_retry."""
-
-    def mock_record(*args, **kwargs):
-        return "test_record"
-
-    assert "test_record" == parse.entrez_retry(null_logger, mock_record)
-
-
-# def test_entrez_retry_none(null_logger):
-#     """Test entrez_retry when nothing is returned."""
-
-#     def mock_record(*args, **kwargs):
-#         return
-
-#     assert parse.entrez_retry(null_logger, mock_record) is None
diff --git a/tests/test_parse_configuration.py b/tests/test_parse_configuration.py
new file mode 100644
index 00000000..bf596ec9
--- /dev/null
+++ b/tests/test_parse_configuration.py
@@ -0,0 +1,564 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Author:
+# Emma E. M. Hobbs
+
+# Contact
+# eemh1@st-andrews.ac.uk
+
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+
+# The MIT License
+
+"""Tests the submodule parse_configuration from utilities.
+
+These test are intened to be run from the root of the repository using:
+pytest -v
+"""
+
+
+import pytest
+import sys
+
+import pandas as pd
+
+from argparse import Namespace
+
+from scraper import sql
+from scraper.utilities import parse_configuration
+
+
+@pytest.fixture
+def test_output_dir(test_dir):
+    path = test_dir / "test_outputs" / "test_outputs_utilities"
+    return path
+
+
+@pytest.fixture
+def making_output_dir(test_output_dir):
+    path = test_output_dir / "testing_making_dir"
+    return path
+
+
+@pytest.fixture
+def args_config_none():
+    args_dict = {
+        "args": Namespace(
+            config=None,
+            classes=None,
+            families=None,
+            genera=None,
+            species=None,
+            strains=None,
+            kingdoms=None,
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def parse_configuration_path():
+    parse_configuration_path = parse_configuration.__file__
+    return parse_configuration_path
+
+
+@pytest.fixture
+def args_config_fake(test_dir):
+    path = test_dir / "fake_config.yaml"
+    args_dict = {
+        "args": Namespace(
+            config=path
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def input_dir(test_input_dir):
+    path = test_input_dir / "test_inputs_parse_configuration"
+    return path
+
+
+@pytest.fixture
+def config_file_path(input_dir):
+    path = input_dir / "config_file.yaml"
+    return path
+
+
+@pytest.fixture
+def args_config_file_cmd(config_file_path):
+    args_dict = {
+        "args": Namespace(
+            config=config_file_path,
+            classes="CE,AA",
+            families="GH14,PL15",
+            kingdoms="Bacteria",
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def args_config_file(config_file_path):
+    args_dict = {
+        "args": Namespace(
+            config=config_file_path,
+            classes=None,
+            families=None,
+            kingdoms="Viruses,Archaea",
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def args_config_cmd():
+    args_dict = {
+        "args": Namespace(
+            config=None,
+            classes="CE,AA",
+            families="GH14,GT1,PL15,CE6,AA10,CBM50,DD21,CBMAA1",
+            genera=None,
+            species=None,
+            strains=None,
+            kingdoms="Archaea,Bacteria"
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def empty_config_dict():
+    config_dict = {
+        'classes': [],
+        'Glycoside Hydrolases (GHs)': [],
+        'GlycosylTransferases (GTs)': [],
+        'Polysaccharide Lyases (PLs)': [],
+        'Carbohydrate Esterases (CEs)': [],
+        'Auxiliary Activities (AAs)': [],
+        'Carbohydrate-Binding Modules (CBMs)': [],
+    }
+    return config_dict
+
+
+@pytest.fixture
+def args_no_yaml():
+    args_dict = {
+        "args": Namespace(
+            config="test/test/test_yaml.yaml",
+            classes=None,
+            families=None,
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def testing_df():
+    df_data = [["A", "B", "C"]]
+    df = pd.DataFrame(df_data, columns=["C1", "C2", "C3"])
+    return df
+
+
+@pytest.fixture
+def stdout_args(test_dir):
+    args_dict = {
+        "args": Namespace(
+            output=sys.stdout,
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def output_args(test_dir):
+    path = test_dir / "test_outputs" / "test_outputs_parse_configuration"
+    args_dict = {
+        "args": Namespace(
+            output=path,
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def tax_no_yaml_args():
+    args_dict = {
+        "args": Namespace(
+            config="fake_yaml",
+            genera="Bacillus,Priestia",
+            species="Arabidopsis thaliana",
+            strains="Bathycoccus prasinos RCC1105,Cyanidioschyzon merolae strain 10D",
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def tax_args(config_file_path):
+    args_dict = {
+        "args": Namespace(
+            config=config_file_path,
+            genera="Bacillus,Priestia",
+            species="Arabidopsis thaliana",
+            strains="Bathycoccus prasinos RCC1105,Cyanidioschyzon merolae strain 10D",
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def raw_config_dict():
+    raw_config_dict = {
+        "classes": ["Carbohydrate Esterases (CEs)"],
+        "Glycoside Hydrolases (GHs)": ["GH1"],
+        "GlycosylTransferases (GTs)": ["GT1"],
+        "Polysaccharide Lyases (PLs)": ["PL2", "PL3"],
+        "Carbohydrate Esterases (CEs)": [],
+        "Auxiliary Activities (AAs)": ["AA1"],
+        "Carbohydrate-Binding Modules (CBMs)": ["CBM2"],
+        "genera": ["Trichoderma"],
+        "species": ["Aspergillus niger"],
+        "strains": ["Acidianus ambivalens LEI 10"],
+        "kingdoms": ["Archaea", "Bacteria"],
+    }
+    return raw_config_dict
+
+# test parse_configuration()
+
+
+def test_parse_config_file_cmd(
+    args_config_file_cmd,
+    cazy_dictionary,
+    parse_configuration_path,
+    monkeypatch,
+):
+    """Test parse_config when only config file is given."""
+
+    std_classes = list(cazy_dictionary.keys())
+
+    def mock_get_taxonomy_filter(*args, **kwargs):
+        return None
+
+    def mock_cazy_dict(*args, **kwargs):
+        return cazy_dictionary, std_classes
+
+    monkeypatch.setattr(parse_configuration, "get_cazy_dict_std_names", mock_cazy_dict)
+    monkeypatch.setattr(parse_configuration, "get_genera_species_strains", mock_get_taxonomy_filter)
+
+    (
+        excluded_classes,
+        config_dict,
+        cazy_dictionary,
+        tax_filter,
+        kingdoms,
+    ) = parse_configuration.parse_configuration(
+        parse_configuration_path,
+        args_config_file_cmd["args"],
+    )
+
+    expected_excluded_classes_1 = [
+        '<strong>Carbohydrate-Binding Modules (CBMs)</strong>',
+        '<strong>GlycosylTransferases (GTs)</strong>',
+    ]
+
+    expected_excluded_classes_2 = [
+        '<strong>GlycosylTransferases (GTs)</strong>',
+        '<strong>Carbohydrate-Binding Modules (CBMs)</strong>',
+    ]
+
+    expected_config_dict = {
+        'classes': [
+            'Glycoside Hydrolases (GHs)',
+            'Polysaccharide Lyases (PLs)',
+            'Carbohydrate Esterases (CEs)',
+            'Auxiliary Activities (AAs)',
+        ],
+        'Glycoside Hydrolases (GHs)': ['GH147', 'GH14'],
+        'GlycosylTransferases (GTs)': None,
+        'Polysaccharide Lyases (PLs)': ['PL17', 'PL15'],
+        'Carbohydrate Esterases (CEs)': None,
+        'Auxiliary Activities (AAs)': None,
+        'Carbohydrate-Binding Modules (CBMs)': None,
+    }
+
+    assert (expected_excluded_classes_1 == excluded_classes) or \
+           (expected_excluded_classes_2 == excluded_classes)
+    assert expected_config_dict == config_dict
+
+
+def test_parse_config_file_only(args_config_file, cazy_dictionary, monkeypatch):
+    """Test parse_configuration when only configuration file is given."""
+
+    std_classes = list(cazy_dictionary.keys())
+
+    def mock_cazy_dict(*args, **kwargs):
+        return cazy_dictionary, std_classes
+
+    def mock_get_tax_filter(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(parse_configuration, "get_cazy_dict_std_names", mock_cazy_dict)
+    monkeypatch.setattr(parse_configuration, "get_genera_species_strains", mock_get_tax_filter)
+
+    (
+        excluded_classes,
+        config_dict,
+        cazy_dictionary,
+        tax_filter,
+        kingdom,
+    ) = parse_configuration.parse_configuration(
+        parse_configuration_path,
+        args_config_file["args"],
+    )
+
+
+def test_parse_config_cmd_only(args_config_cmd, cazy_dictionary, monkeypatch):
+    """Test parse_configuration when only cmd-line configuration is given."""
+
+    std_classes = list(cazy_dictionary.keys())
+
+    def mock_cazy_dict(*args, **kwargs):
+        return cazy_dictionary, std_classes
+
+    monkeypatch.setattr(parse_configuration, "get_cazy_dict_std_names", mock_cazy_dict)
+
+    (
+        excluded_classes,
+        config_dict,
+        cazy_dictionary,
+        tax_filter,
+        kingdom,
+    ) = parse_configuration.parse_configuration(
+        parse_configuration_path,
+        args_config_cmd["args"],
+    )
+
+
+def test_parse_config_no_config(args_config_none, cazy_dictionary, monkeypatch):
+    """Test parse_configuration when no configuration is given."""
+
+    std_classes = list(cazy_dictionary.keys())
+
+    def mock_cazy_dict(*args, **kwargs):
+        return cazy_dictionary, std_classes
+
+    monkeypatch.setattr(parse_configuration, "get_cazy_dict_std_names", mock_cazy_dict)
+
+    (
+        excluded_classes,
+        config_dict,
+        cazy_dictionary,
+        tax_filter,
+        kingdom,
+    ) = parse_configuration.parse_configuration(
+        parse_configuration_path,
+        args_config_none["args"],
+    )
+
+
+# test get_cazy_dict_std_names()
+
+
+def test_cazy_dict_not_found():
+    """Test get_cazy_dict_std_names() when the cazy_dictionary file cannot be found."""
+    fake_path = sql.__file__
+
+    with pytest.raises(SystemExit) as pytest_wrapped_err:
+        parse_configuration.get_cazy_dict_std_names(fake_path)
+    assert pytest_wrapped_err.type == SystemExit
+
+
+def test_cazy_dict_success():
+    """Test get_cazy_dict_std_names() when the retrieval of the data is successful."""
+    path = parse_configuration.__file__
+
+    parse_configuration.get_cazy_dict_std_names(path)
+
+
+# test get_yaml_configuration
+
+
+def test_get_yaml_not_found(empty_config_dict, cazy_dictionary, args_no_yaml):
+    """Test get_yaml_configuration when the configuration cannot be found."""
+
+    std_classes = list(cazy_dictionary.keys())
+
+    with pytest.raises(SystemExit) as pytest_wrapped_err:
+        parse_configuration.get_yaml_configuration(
+            empty_config_dict,
+            cazy_dictionary,
+            std_classes,
+            args_no_yaml["args"],
+        )
+    assert pytest_wrapped_err.type == SystemExit
+
+
+def test_get_yaml_success(empty_config_dict, cazy_dictionary, args_config_file):
+    """Test get_yaml_configuration when successfully retrieves and parses data from yaml file."""
+
+    std_classes = list(cazy_dictionary.keys())
+
+    parse_configuration.get_yaml_configuration(
+        empty_config_dict,
+        cazy_dictionary,
+        std_classes,
+        args_config_file["args"],
+    )
+
+
+# test get_yaml_cazy_classes
+
+
+def test_get_yaml_classes_no(cazy_dictionary):
+    """Test get_yaml_cazy_classes when classes key cannot be found."""
+
+    std_classes = list(cazy_dictionary.keys())
+    yaml_dict = {"Glycoside Hydrolases (GHs)": ["GH1", "GH2"]}
+
+    parse_configuration.get_yaml_cazy_classes(yaml_dict, cazy_dictionary, std_classes)
+
+
+def test_get_yaml_classes_none(cazy_dictionary):
+    """Test get_yaml_cazy_classes when classes key has the value of None."""
+
+    std_classes = list(cazy_dictionary.keys())
+    yaml_dict = {"classes": None, "Glycoside Hydrolases (GHs)": ["GH1", "GH2"]}
+
+    parse_configuration.get_yaml_cazy_classes(yaml_dict, cazy_dictionary, std_classes)
+
+
+def test_get_yaml_classes_success(cazy_dictionary):
+    """Test get_yaml_cazy_classes when classes key has the value of CAZy classes."""
+
+    std_classes = list(cazy_dictionary.keys())
+    yaml_dict = {"classes": ["PL", "CE"], "Glycoside Hydrolases (GHs)": ["GH1", "GH2"]}
+
+    parse_configuration.get_yaml_cazy_classes(yaml_dict, cazy_dictionary, std_classes)
+
+
+# test parse_user_cazy_classes()
+
+
+def test_parse_user_cazy_classes(cazy_dictionary):
+    """Test parse_user_cazy_classes to standardise the CAZy classes written by the user."""
+
+    cazy_classes = ['GH', 'pl']
+    class_name = [
+        'Glycoside Hydrolases (GHs)',
+        'GlycosylTransferases (GTs)',
+        'Polysaccharide Lyases (PLs)',
+        'Carbohydrate Esterases (CEs)',
+        'Auxiliary Activities (AAs)',
+        'Carbohydrate-Binding Modules (CBMs)',
+    ]
+
+    exepected = ['Glycoside Hydrolases (GHs)', 'Polysaccharide Lyases (PLs)']
+
+    assert exepected == parse_configuration.parse_user_cazy_classes(
+        cazy_classes,
+        cazy_dictionary,
+        class_name,
+    )
+
+
+def test_cannot_standardise_user_classes(cazy_dictionary):
+    """Test when cannot standardise a name listed in the configuration file."""
+
+    cazy_classes = ['GH', 'pl', 'testtesttest']
+    class_name = [
+        'Glycoside Hydrolases (GHs)',
+        'GlycosylTransferases (GTs)',
+        'Polysaccharide Lyases (PLs)',
+        'Carbohydrate Esterases (CEs)',
+        'Auxiliary Activities (AAs)',
+        'Carbohydrate-Binding Modules (CBMs)',
+    ]
+
+    exepected = ['Glycoside Hydrolases (GHs)', 'Polysaccharide Lyases (PLs)']
+
+    assert exepected == parse_configuration.parse_user_cazy_classes(
+        cazy_classes,
+        cazy_dictionary,
+        class_name,
+    )
+
+
+# test get_cmd_defined_fams_classes()
+
+
+def test_get_cmd_configuration(args_config_cmd, cazy_dictionary):
+    """Test get_cmd_defined_fams_classes."""
+
+    std_classes = list(cazy_dictionary.keys())
+    parse_configuration.get_cmd_defined_fams_classes(
+        cazy_dictionary,
+        std_classes,
+        args_config_cmd["args"],
+    )
+
+
+# test get_excluded_classes
+
+
+def test_get_no_excluded_classes(cazy_dictionary):
+    """Test when no excluded classes should be returned."""
+    std_classes = list(cazy_dictionary.keys())
+    config_dict = {"classes": [
+        'Carbohydrate Esterases (CEs)',
+        'Auxiliary Activities (AAs)',
+        'GlycosylTransferases (GTs)',
+        'Glycoside Hydrolases (GHs)',
+        'Polysaccharide Lyases (PLs)',
+        'Carbohydrate-Binding Modules (CBMs)',
+    ]}
+
+    assert None is parse_configuration.get_excluded_classes(
+        std_classes,
+        config_dict,
+        cazy_dictionary,
+    )
+
+# test get_configuration() - retrieves configuraiton for the expand module
+
+
+def test_get_configuraiton_0(cazy_dictionary, parse_configuration_path, monkeypatch):
+    """Tests getting configuration for the expand module when NO tax filters are given."""
+
+    def mock_parse_config(*args, **kwargs):
+        return None, None, cazy_dictionary, {}
+
+    monkeypatch.setattr(parse_configuration, "parse_configuration", mock_parse_config)
+
+    parse_configuration.get_configuration(parse_configuration_path, "args")
+
+
+def test_get_configuraiton_1(cazy_dictionary, parse_configuration_path, monkeypatch):
+    """Tests getting configuration for the expand module when ARE tax filters are given."""
+
+    def mock_parse_config(*args, **kwargs):
+        return None, None, cazy_dictionary, {"genera": ["Trichoderma", "Aspergillus"]}
+
+    monkeypatch.setattr(parse_configuration, "parse_configuration", mock_parse_config)
+
+    parse_configuration.get_configuration(parse_configuration_path, "args")
+
+
+# test get_genera_species_strains()
+
+
+def test_get_tax_filter_no_yaml(tax_no_yaml_args, raw_config_dict):
+    """Test the get_genera_species_strains function when the config file can't be found."""
+    parse_configuration.get_genera_species_strains(tax_no_yaml_args["args"], raw_config_dict)
+
+
+def test_get_tax_filter(tax_args, raw_config_dict):
+    """Test get_genera_species_strains when cmd-line and config file are parsed."""
+    parse_configuration.get_genera_species_strains(tax_args["args"], raw_config_dict)
diff --git a/tests/test_sql.py b/tests/test_sql.py
new file mode 100644
index 00000000..8666aa1c
--- /dev/null
+++ b/tests/test_sql.py
@@ -0,0 +1,741 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Author:
+# Emma E. M. Hobbs
+
+# Contact
+# eemh1@st-andrews.ac.uk
+
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+
+# The MIT License
+
+"""Tests the module sql which builds and interacts with an SQL database.
+
+These test are intened to be run from the root of the repository using:
+pytest -v
+"""
+
+
+import pytest
+import shutil
+
+from argparse import Namespace
+from datetime import datetime
+from pathlib import Path
+
+from sqlalchemy.orm.exc import ObjectDeletedError
+
+from scraper.utilities import file_io
+from scraper.sql import sql_orm, sql_interface
+from scraper.sql.sql_orm import (
+    Cazyme,
+    CazyFamily,
+    Genbank,
+    Taxonomy,
+    Kingdom,
+    EC,
+    Uniprot,
+    Pdb,
+    Log,
+    Cazymes_Genbanks,
+)
+
+
+@pytest.fixture
+def output_dir(test_dir):
+    path = Path("test_outputs")
+    path = path / "test_sql_outputs"
+    return path
+
+
+@pytest.fixture
+def database_args(output_dir):
+    args_dict = {
+        "args": Namespace(
+            output=output_dir,
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def existing_db_args(output_dir):
+    db_path = output_dir / "cazy_scrape_2021-02-07--15-35-13.db"
+    args_dict = {
+        "args": Namespace(
+            output=output_dir,
+            database=db_path
+        )
+    }
+    return args_dict
+
+
+# Unit tests for sql_orm
+
+
+def test_regex_search(db_session):
+    """Test a regular expression search can be performed successfully."""
+
+    cazy_class = "PL"
+    class_query = db_session.query(Cazyme.cazyme_id).\
+        join(CazyFamily, Cazyme.families).\
+        filter(CazyFamily.family.regexp(rf"{cazy_class}\d+")).\
+        all()
+
+    assert len(class_query) == 24
+
+
+def test_calling_class_instances():
+    """Test calling Class instances strs and reprs."""
+    cazyme = Cazyme(cazyme_name="test_cazyme")
+    str(cazyme)
+    repr(cazyme)
+
+    tax = Taxonomy(genus="genus", species="species")
+    str(tax)
+    repr(tax)
+
+    kng = Kingdom(kingdom="kingdom")
+    str(kng)
+    repr(kng)
+
+    fam = CazyFamily(family="family")
+    str(fam)
+    repr(fam)
+
+    fam = CazyFamily(family="family", subfamily="subfamily")
+    str(fam)
+    repr(fam)
+
+    gb = Genbank(genbank_accession="accession")
+    str(gb)
+    repr(gb)
+
+    cg = Cazymes_Genbanks(cazyme_id=1, genbank_id=2)
+    str(cg)
+    repr(cg)
+
+    ec = EC(ec_number="EC1.2.3.4")
+    str(ec)
+    repr(ec)
+
+    up = Uniprot(uniprot_accession="accession")
+    str(up)
+    repr(up)
+
+    pdb = Pdb(pdb_accession="accession")
+    str(pdb)
+    repr(pdb)
+
+    log = Log(date="date", time="time", classes="classes", families="families")
+    str(log)
+    repr(log)
+
+
+def test_build_db():
+    """Test building a database."""
+    path_ = Path("tests")
+    path_ = path_ / "test_outputs" / "test_outputs_sql" / "temp_dir"
+    file_io.make_output_directory(path_, True, False)
+    args = {"args": Namespace(output=path_)}
+    sql_orm.build_db("time_stamp", args["args"])
+    shutil.rmtree(path_)
+
+
+# Unit tests for sql_interface
+
+
+def test_custom_error():
+    """Test custom error."""
+    with pytest.raises(sql_interface.SqlInterfaceException) as pytest_wrapped_err:
+        raise sql_interface.SqlInterfaceException("message")
+    assert pytest_wrapped_err.type == sql_interface.SqlInterfaceException
+
+
+def test_adding_a_new_protein(db_session):
+    """Test adding a new protein to the local database."""
+    time_stamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+
+    try:
+        sql_interface.add_protein_to_db(
+            "test_cazyme",
+            "test_fam",
+            "test_genus test_species",
+            "kingdom",
+            time_stamp,
+            db_session,
+            ["EC1.2.3.4"],
+            ["Genbank1", "Genbank2"],
+            ["Uni1P"],
+            ["UniNP1"],
+            ["PDB1", "PDB2"],
+        )
+    except ObjectDeletedError as e:
+        pass
+
+
+def test_add_data_to_an_existing_record_in_db(db_session):
+    """Test adding data to an existing CAZyme in the local database."""
+
+    sql_interface.add_protein_to_db(
+        "JCM19301_1832",
+        "PL28",
+        "pallidilutea JCM 19301",
+        "Bacteria",
+        "GAL67220.1",
+        db_session,
+        ec_numbers=["EC4.2.2.-"],
+        gbk_nonprimary=["Genbank1", "Genbank2"],
+        uni_nonprimary=["Uni1", "Uni2"],
+    )
+
+
+def test_genbank_no_cazymes(db_session, monkeypatch):
+    """test adding a protein to a database, GenBank accession is found with no linked CAZymes."""
+
+    def mock_adding_a_new_protein(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_new_protein_to_db", mock_adding_a_new_protein)
+
+    existing_genbank_with_no_cazyme = "test_genbank_no_cazyme"
+
+    sql_interface.add_protein_to_db(
+        "test_cazyme_name",
+        "cazy_family",
+        "source_genus organism",
+        "kingdom",
+        existing_genbank_with_no_cazyme,
+        db_session,
+        ec_numbers=["EC4.2.2.-"],
+    )
+
+
+def test_genbank_no_cazymes_raise_error(db_session, monkeypatch):
+    """test adding a protein to a database, GenBank accession is found with no linked CAZymes."""
+
+    def mock_adding_a_new_protein(*args, **kwargs):
+        return "error_message"
+
+    monkeypatch.setattr(sql_interface, "add_new_protein_to_db", mock_adding_a_new_protein)
+
+    existing_genbank_with_no_cazyme = "test_genbank_no_cazyme"
+
+    sql_interface.add_protein_to_db(
+        "test_cazyme_name",
+        "cazy_family",
+        "source_genus organism",
+        "kingdom",
+        existing_genbank_with_no_cazyme,
+        db_session,
+        ec_numbers=["EC4.2.2.-"],
+        gbk_nonprimary=["Genbank1", "Genbank2"],
+        uni_nonprimary=["Uni1", "Uni2"],
+    )
+
+
+def test_one_genbank_multiple_cazymes(db_session, monkeypatch):
+    """test adding protein to db when genbank is found linked to muliple CAZymes."""
+
+    def mock_add_protein_to_db(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_data_to_protein_record", mock_add_protein_to_db)
+
+    genbank_with_multiple_cazymes = "one_genbank_multi_cazymes"
+
+    sql_interface.add_protein_to_db(
+        "test_cazyme_name",
+        "cazy_family",
+        "source_genus organism",
+        "kingdom",
+        genbank_with_multiple_cazymes,
+        db_session,
+    )
+
+
+def test_multiple_genbanks_multiple_cazymes(db_session, monkeypatch):
+    """test adding protein to db when finding multiple identical CAZymes and GenBank accesisons."""
+
+    def mock_add_protein_to_db(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_data_to_protein_record", mock_add_protein_to_db)
+
+    identical_genbank_accession = "identical_accession"
+
+    sql_interface.add_protein_to_db(
+        "test_cazyme_name",
+        "cazy_family",
+        "source_genus organism",
+        "kingdom",
+        identical_genbank_accession,
+        db_session,
+    )
+
+
+def test_multiple_genbanks_one_cazyme(db_session, monkeypatch):
+    """test adding protien to db when identical GenBank accessions with one CAZyme link."""
+
+    def mock_add_protein_to_db(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_data_to_protein_record", mock_add_protein_to_db)
+
+    multiple_accession = "multiple_accession"
+
+    sql_interface.add_protein_to_db(
+        "test_cazyme_name",
+        "cazy_family",
+        "source_genus organism",
+        "kingdom",
+        multiple_accession,
+        db_session,
+    )
+
+
+def test_multiple_genbanks_no_cazymes(db_session, monkeypatch):
+    """test adding protien to db when identical GenBank accessions are linked to no CAZymes."""
+
+    identical_genbanks_no_cazymes = "multi_accession_no_caz"
+
+    def mock_add_protein_to_db(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_new_protein_to_db", mock_add_protein_to_db)
+
+    sql_interface.add_protein_to_db(
+        "test_cazyme_name",
+        "cazy_family",
+        "source_genus organism",
+        "kingdom",
+        identical_genbanks_no_cazymes,
+        db_session,
+    )
+
+
+# Unit tests for add_new_protein_to_db()
+
+
+def test_adding_new_protein_and_new_species(db_session, monkeypatch):
+    """Test add_new_protein_to_db and a new species to the database."""
+
+    def mock_return_none(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_ec_numbers", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_nonprimary_gbk_accessions", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_uniprot_accessions", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_pdb_accessions", mock_return_none)
+
+    time_stamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+    new_species = f"genus-{time_stamp} species-{time_stamp}"
+
+    sql_interface.add_new_protein_to_db(
+        "cazyme_name",
+        "GH5_1",
+        new_species,
+        "Bacteria",
+        Genbank(genbank_accession=f"primary_genbank{time_stamp}"),
+        db_session,
+        ec_numbers=["EC number", "ec number"],
+        gbk_nonprimary=["gen1", "gen2"],
+        uni_primary=["primary_uni"],
+        uni_nonprimary=["uni1", "uni2"],
+        pdb_accessions=["pdb1", "pdb2"],
+    )
+
+
+def test_adding_new_protein_and_new_species_and_fam(db_session, monkeypatch, time_stamp):
+    """Test add_new_protein_to_db and a new species to the database."""
+
+    def mock_return_none(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_ec_numbers", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_nonprimary_gbk_accessions", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_uniprot_accessions", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_pdb_accessions", mock_return_none)
+
+    new_species = f"genus-{time_stamp} species-{time_stamp}"
+
+    try:
+        sql_interface.add_new_protein_to_db(
+            "cazyme_name_test",
+            "GH5",
+            new_species,
+            f"kingdom:{time_stamp}",
+            Genbank(genbank_accession=f"primary_genbank{time_stamp}"),
+            db_session,
+            ec_numbers=["EC number", "ec number"],
+            gbk_nonprimary=["gen1", "gen2"],
+            uni_nonprimary=["uni1", "uni2"],
+            pdb_accessions=["pdb1", "pdb2"],
+        )
+    except ObjectDeletedError as e:
+        pass
+
+
+def test_addding_new_protein_with_existing_species(db_session, monkeypatch):
+    """Test add_new_protein_to_db when the species exists in the database."""
+
+    def mock_return_none(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_ec_numbers", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_nonprimary_gbk_accessions", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_uniprot_accessions", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_pdb_accessions", mock_return_none)
+
+    existing_species = "test_existing_genus test_existing_species"
+
+    gb = db_session.query(Genbank).filter(Genbank.genbank_accession == 'one_genbank_multi_cazymes')\
+        .all()[0]
+
+    sql_interface.add_new_protein_to_db(
+        cazyme_name="cazyme_name",
+        family="GH5_1",
+        source_organism=existing_species,
+        tax_kingdom='Bacteria',
+        primary_genbank_object=gb,
+        session=db_session,
+        ec_numbers=["EC number", "ec number"],
+        gbk_nonprimary=["gen1", "gen2"],
+        uni_primary=["primary_uni"],
+        uni_nonprimary=["uni1", "uni2"],
+        pdb_accessions=["pdb1", "pdb2"],
+    )
+
+
+def test_adding_new_protein_with_multiple_species(db_session, monkeypatch):
+    """Test add_new_protein_to_db when there are multiple records for the same species."""
+
+    def mock_return_none(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_ec_numbers", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_nonprimary_gbk_accessions", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_uniprot_accessions", mock_return_none)
+    monkeypatch.setattr(sql_interface, "add_pdb_accessions", mock_return_none)
+
+    duplicate_species = "duplicate_genus duplicate_species"
+    time_stamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+
+    sql_interface.add_new_protein_to_db(
+        "cazyme_name",
+        "GH5_1",
+        duplicate_species,
+        "Eukaryota",
+        Genbank(genbank_accession=f"primary_genbank{time_stamp}"),
+        db_session,
+        ec_numbers=["EC number", "ec number"],
+        gbk_nonprimary=["gen1", "gen2"],
+        uni_primary=["primary_uni"],
+        uni_nonprimary=["uni1", "uni2"],
+        pdb_accessions=["pdb1", "pdb2"],
+    )
+
+
+# test add_data_to_protein_record()
+
+
+def test_add_data_to_protein_record(db_session, monkeypatch):
+    """Test add_data_to_protein_record()."""
+    def mock_no_return(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(sql_interface, "add_cazy_family", mock_no_return)
+    monkeypatch.setattr(sql_interface, "add_pdb_accessions", mock_no_return)
+
+    sql_interface.add_data_to_protein_record(
+        Cazyme(cazyme_name="test_cazyme"),
+        "GH3",
+        db_session,
+        ec_numbers=["EC number", "ec number"],
+        gbk_nonprimary=["gen1", "gen2"],
+        uni_primary=["primary_uni"],
+        uni_nonprimary=["uni1", "uni2"],
+        pdb_accessions=["pdb1", "pdb2"],
+    )
+
+
+# Unit tests for add_cazy_family
+
+
+def test_adding_new_family(db_session):
+    """Test adding a new CAZy family to the local database."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    time_stamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+    new_fam = f"GH{time_stamp}"
+
+    sql_interface.add_cazy_family(
+        new_fam,
+        cazyme,
+        db_session,
+    )
+
+
+def test_add_existing_family(db_session):
+    """Test adding an existing family to a CAZyme record."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    existing_fam = "FamOnly"
+
+    sql_interface.add_cazy_family(
+        existing_fam,
+        cazyme,
+        db_session,
+    )
+
+
+def test_add_new_fam_cos_old_fam_has_subfam(db_session):
+    """Test adding a new family because the existing family record is a subfamily."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    existing_fam = "FamWithSubFam"
+
+    sql_interface.add_cazy_family(
+        existing_fam,
+        cazyme,
+        db_session,
+    )
+
+
+def test_duplicate_families_no_nonsubfams(db_session):
+    """Test when multiple families are found with none without subfamilies."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    duplicate_families = "dupFam"
+
+    sql_interface.add_cazy_family(
+        duplicate_families,
+        cazyme,
+        db_session,
+    )
+
+
+def test_duplicate_families_one_with_no_subfams(db_session):
+    """test when multiple families are found and one has no subfamiy submission."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    identical_fam = "identFam"
+
+    sql_interface.add_cazy_family(
+        identical_fam,
+        cazyme,
+        db_session,
+    )
+
+
+def test_duplicate_families_multiple_with_no_subfams(db_session):
+    """test when multiple families have no subfamily assoication."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    identical_fam = "IdenticalFamily"
+
+    sql_interface.add_cazy_family(
+        identical_fam,
+        cazyme,
+        db_session,
+    )
+
+
+# Unit tests for adding subfamilies
+
+
+def test_adding_new_subfamily(db_session):
+    """Test adding a new subfamily to the local database."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    time_stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
+    new_fam = f"GH{time_stamp}_1"
+
+    sql_interface.add_cazy_subfamily(
+        new_fam,
+        cazyme,
+        db_session,
+    )
+
+
+def test_adding_cazyme_to_existing_db(db_session):
+    """Test adding a CAZyme to an existing subfamily in the local database."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    existing_fam = "testGH1_53"
+
+    sql_interface.add_cazy_subfamily(
+        existing_fam,
+        cazyme,
+        db_session,
+    )
+
+
+def test_multiple_subfamilies_found(db_session):
+    """Test when multiple identical subfamilies are found in the local database."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    identical_subfam = "testident_ident123"
+
+    sql_interface.add_cazy_subfamily(
+        identical_subfam,
+        cazyme,
+        db_session,
+    )
+
+
+# Unit tests for adding non-primary GenBank accessions
+
+
+def test_adding_new_non_prim_gb_acc(db_session):
+    """Test adding a new non-primary GenBank accession."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    time_stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
+    new_acc = [f"gb_acc_{time_stamp}"]
+
+    sql_interface.add_nonprimary_gbk_accessions(
+        new_acc,
+        cazyme,
+        db_session,
+    )
+
+
+def test_duplicate_non_prim_db_acc(db_session):
+    """Test when finding multiple identical non-primary duplicate GenBank accessions."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    duplicate_acc = ["dupNonPrimGBAcc"]
+
+    sql_interface.add_nonprimary_gbk_accessions(
+        duplicate_acc,
+        cazyme,
+        db_session,
+    )
+
+
+# Unit tests for adding EC numbers
+
+
+def test_adding_new_ec_num(db_session):
+    """Testing adding a new EC# to the local database."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    time_stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
+    ec = [f"EC{time_stamp}"]
+
+    sql_interface.add_ec_numbers(
+        ec,
+        cazyme,
+        db_session,
+    )
+
+
+def test_adding_existing_ec_num(db_session):
+    """Testing adding an existing EC# to a CAZyme."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    ec = ["existing_ec"]
+
+    sql_interface.add_ec_numbers(
+        ec,
+        cazyme,
+        db_session,
+    )
+
+
+def test_finding_multiple_ecs(db_session):
+    """Testing handling when multiple duplicate EC#s are found."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    ec = ["dupEC"]
+
+    sql_interface.add_ec_numbers(
+        ec,
+        cazyme,
+        db_session,
+    )
+
+
+# Unit tests for adding primary UniProt accessions
+
+
+def test_new_primary_uniprot(db_session):
+    """Test adding a new primary UniProt accession."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    time_stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
+    new_acc = f"uni_acc_test{time_stamp}"
+
+    sql_interface.add_uniprot_accessions(
+        [new_acc],
+        cazyme,
+        True,
+        db_session,
+    )
+
+
+def test_existing_primary_uniprot(db_session):
+    """Test adding an existing primary UniProt accession to a CAZyme."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    existing_uni = "existing_acc_test"
+
+    sql_interface.add_uniprot_accessions(
+        [existing_uni],
+        cazyme,
+        True,
+        db_session,
+    )
+
+
+def test_add_nonprimery_uniprot(db_session, time_stamp):
+    """Test adding adding non-primary UniProt accessions."""
+
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+
+    sql_interface.add_uniprot_accessions(
+        [f'acc{time_stamp}', 'dupp_np'],
+        cazyme,
+        True,
+        db_session,
+    )
+
+
+# Unit tests for adding PDB accessions to the local database
+
+
+def test_adding_pdb_accessions(time_stamp, db_session):
+    """Test adding PDB accessions to the local database."""
+    cazyme = db_session.query(Cazyme).filter(Cazyme.cazyme_id == 50).all()[0]
+    accessions = [f'new_accession-{time_stamp}', 'existing_pdb', 'dupEC']
+
+    sql_interface.add_pdb_accessions(
+        accessions,
+        cazyme,
+        db_session,
+    )
diff --git a/tests/test_utilities.py b/tests/test_utilities.py
index eebeaac0..cb0605d4 100644
--- a/tests/test_utilities.py
+++ b/tests/test_utilities.py
@@ -21,14 +21,15 @@
 
 These test are intened to be run from the root of the repository using:
 pytest -v
-
 """
 
+
+import logging
 import pytest
 
 from argparse import Namespace
 
-from scraper import utilities
+from scraper.utilities import config_logger, parsers
 
 
 @pytest.fixture
@@ -53,28 +54,53 @@ def args_v_true():
     return args_dict
 
 
+# test building the parser
+
+
+def test_parser():
+    """Test building the parser when argsv is None"""
+    parsers.build_parser()
+
+
+def test_parser_arsv():
+    """Test building the parser when argsv is not None"""
+    parsers.build_parser(["-f"])
+
+
 # test building the logger
 
+
 def test_verbose_false(args_v_false):
     """Test build_logger when args.verbose and args.log are false"""
-    logger = utilities.build_logger("test", args_v_false["args"])
-    assert logger.level == 30
+    config_logger(args_v_false["args"])
 
 
 def test_verbose_true(args_v_true):
     """Test build_logger when args.verbose and args.log are true"""
-    logger = utilities.build_logger("test", args_v_true["args"])
-    assert logger.level == 20
+    config_logger(args_v_true["args"])
 
 
-# test building the parser
+# test building genbank_sequencases parser
 
 
-def test_parser():
+def test_genbank_seq_parser():
     """Test building the parser when argsv is None"""
-    utilities.build_parser()
+    parsers.build_genbank_sequences_parser()
 
 
-def test_parser_arsv():
+def test_genbank_seq_parser_arsv():
+    """Test building the parser when argsv is not None"""
+    parsers.build_genbank_sequences_parser(["database", "email"])
+
+
+# test building genbank_sequencases parser
+
+
+def test_pdb_struc_parser():
+    """Test building the parser when argsv is None"""
+    parsers.build_pdb_structures_parser()
+
+
+def test_pdb_struc_parser_arsv():
     """Test building the parser when argsv is not None"""
-    utilities.build_parser(["-f"])
+    parsers.build_pdb_structures_parser(["database", "pdb"])
diff --git a/tests/test_webscraper.py b/tests/test_webscraper.py
index f3c9b2b0..392f9667 100644
--- a/tests/test_webscraper.py
+++ b/tests/test_webscraper.py
@@ -23,14 +23,12 @@
 pytest -v
 """
 
-import json
 import pytest
-import sys
 
 from argparse import Namespace, ArgumentParser
-from requests.exceptions import MissingSchema
 
-from scraper import cazy_webscraper, crawler, file_io, parse, utilities
+from scraper import cazy_webscraper, crawler, sql, utilities
+from scraper.utilities import file_io, parse_configuration, parsers
 
 
 @pytest.fixture
@@ -46,33 +44,18 @@ def output_dir(test_dir):
 
 
 @pytest.fixture
-def get_cazy_data_args_none():
-    argsdict = {
-        "args": Namespace(
-            data_split=None,
-            subfamilies=False,
-        )
-    }
-    return argsdict
+def db_path():
+    db_path = "tests/test_inputs/test_inputs_sql/unit_test_db_2021-03-01--15-06-59.db"
+    return db_path
 
 
 @pytest.fixture
-def get_cazy_data_args_family():
+def args_get_cazy_data():
     argsdict = {
         "args": Namespace(
-            data_split="family",
-            subfamilies=True,
-        )
-    }
-    return argsdict
-
-
-@pytest.fixture
-def get_cazy_data_args_class():
-    argsdict = {
-        "args": Namespace(
-            data_split="class",
             subfamilies=True,
+            retries=2,
+            timeout=5,
         )
     }
     return argsdict
@@ -81,67 +64,126 @@ def get_cazy_data_args_class():
 @pytest.fixture
 def config_dict():
     configuration_dict = {
-        "Glycoside Hydrolases (GHs)": ["GH1"],
+        "Glycoside Hydrolases (GHs)": ["GH3"],
         "Polysaccharide Lyases (PLs)": None,
     }
     return configuration_dict
 
 
-@pytest.fixture
-def mock_family():
-    family = crawler.Family("GH1", "Glycoside_Hydrolases(GH)")
-    return family
+# test main()
 
 
-# test classes
+def test_main_invalid_db_path(output_dir, null_logger, cazy_dictionary, monkeypatch):
+    """Test function main() when an invalid db path is given.
 
+    Argv is None, logger is None, args.output is not sys.stdout, args.subfamilies is True.
+    """
 
-def test_protein_get_protein_dict():
-    """Test the Protein class __str__ and __repr__."""
-    protein = crawler.Protein(
-        "protein_name",
-        "GH1",
-        ["1.2.3.4"],
-        "organism",
-        {"GenBank": ["link1", "linka", "linkb"], "UniProt": ["link2"], "PDB/3D": ["link3"]},
-    )
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
 
-    protein_dict = protein.get_protein_dict()
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            output=output_dir,
+            subfamilies=True,
+            force=False,
+            nodelete=False,
+            retries=1,
+            database="fake_database_path",
+            verbose=False,
+            log=None,
+        )
+        return parser
 
-    expected_protein_dict = {
-        'Protein_name': ['protein_name'],
-        'CAZy_family': ['GH1'],
-        'EC#': ['1.2.3.4'],
-        'Source_organism': ['organism'],
-        'GenBank': ['link1,\nlinka,\nlinkb'],
-        'UniProt': ['link2'],
-        'PDB/3D': ['link3'],
-    }
+    def mock_config_logger(*args, **kwargs):
+        return
 
-    assert expected_protein_dict == protein_dict
+    def mock_making_output_dir(*args, **kwargs):
+        return
 
+    def mock_retrieving_configuration(*args, **kwargs):
+        return None, None, cazy_dictionary, [], []
 
-def test_family_get_name():
-    """Tests get family name for Family."""
-    family = crawler.Family("GH1", "Glycoside_Hydrolases(GH)")
+    monkeypatch.setattr(parsers, "build_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_making_output_dir)
+    monkeypatch.setattr(parse_configuration, "parse_configuration", mock_retrieving_configuration)
 
-    family_name = family.get_family_name()
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        cazy_webscraper.main()
+    assert pytest_wrapped_e.type == SystemExit
 
-    exepected_name = "GH1"
 
-    assert exepected_name == family_name
+def test_main_existing_database(output_dir, null_logger, cazy_dictionary, db_path, monkeypatch):
+    """Test function main() when passed an existing database.
 
+    Argv is not None, logger is not None, args.output is output_dir, args.subfamilies is True,
+    and valid db path is given by db_path.
+    """
 
-# test main()
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
 
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            output=output_dir,
+            subfamilies=True,
+            force=False,
+            nodelete=False,
+            retries=1,
+            database=db_path,
+            verbose=True,
+            log=None,
+        )
+        return parser
 
-def test_main_one(test_dir, output_dir, null_logger, cazy_dictionary, monkeypatch):
-    """Test function main().
+    def mock_config_logger(*args, **kwargs):
+        return
 
-    Argv is None, logger is None, args.output is not sys.stdout, args.subfamilies is True.
-    """
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
+    def mock_making_output_dir(*args, **kwargs):
+        return
+
+    def mock_retrieving_configuration(*args, **kwargs):
+        return None, None, cazy_dictionary, None, []
+
+    def mock_adding_log(*args, **kwargs):
+        return
+
+    def mock_get_filter_set(*args, **kwargs):
+        return set()
+
+    def mock_retrieving_cazy_data(*args, **kwargs):
+        return
+
+    monkeypatch.setattr(parsers, "build_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_making_output_dir)
+    monkeypatch.setattr(parse_configuration, "parse_configuration", mock_retrieving_configuration)
+    monkeypatch.setattr(cazy_webscraper, "log_scrape_in_db", mock_adding_log)
+    monkeypatch.setattr(cazy_webscraper, "get_filter_set", mock_get_filter_set)
+    monkeypatch.setattr(cazy_webscraper, "get_cazy_data", mock_retrieving_cazy_data)
+
+    cazy_webscraper.main(["argv"])
+
+
+def test_main_new_database(output_dir, null_logger, cazy_dictionary, db_path, monkeypatch):
+    """Test main() when a new database_file is created"""
 
     def mock_building_parser(*args, **kwargs):
         parser_args = ArgumentParser(
@@ -155,47 +197,53 @@ def mock_building_parser(*args, **kwargs):
 
     def mock_parser(*args, **kwargs):
         parser = Namespace(
-            output=test_dir,
+            output=output_dir,
             subfamilies=True,
             force=False,
             nodelete=False,
-            genbank="dummy_email",
-            genbank_output=output_dir,
-            pdb="pdb",
-            pdb_output=output_dir,
-            retries=0,
+            retries=1,
+            database=None,
+            verbose=False,
+            log=None,
         )
         return parser
 
-    def mock_build_logger(*args, **kwargs):
-        return null_logger
+    def mock_config_logger(*args, **kwargs):
+        return
 
     def mock_making_output_dir(*args, **kwargs):
         return
 
     def mock_retrieving_configuration(*args, **kwargs):
-        return None, None, cazy_dict
+        return None, None, cazy_dictionary, None, []
+
+    def mock_getting_db_session(*args, **kwargs):
+        return "session"
+
+    def mock_adding_log(*args, **kwargs):
+        return
+
+    def mock_tax_set(*args, **kwargs):
+        return set()
 
     def mock_retrieving_cazy_data(*args, **kwargs):
         return
 
-    monkeypatch.setattr(utilities, "build_parser", mock_building_parser)
+    monkeypatch.setattr(parsers, "build_parser", mock_building_parser)
     monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
-    monkeypatch.setattr(utilities, "build_logger", mock_build_logger)
+    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
     monkeypatch.setattr(file_io, "make_output_directory", mock_making_output_dir)
-    monkeypatch.setattr(file_io, "parse_configuration", mock_retrieving_configuration)
+    monkeypatch.setattr(parse_configuration, "parse_configuration", mock_retrieving_configuration)
+    monkeypatch.setattr(sql.sql_orm, "build_db", mock_getting_db_session)
+    monkeypatch.setattr(cazy_webscraper, "log_scrape_in_db", mock_adding_log)
+    monkeypatch.setattr(cazy_webscraper, "get_filter_set", mock_tax_set)
     monkeypatch.setattr(cazy_webscraper, "get_cazy_data", mock_retrieving_cazy_data)
 
     cazy_webscraper.main()
 
 
-def test_main_two(output_dir, null_logger, cazy_dictionary, monkeypatch):
-    """Test function main() using opposite scenariors for if statements than in test_main_one().
-
-    Argv is not None, logger is not None, args.output is sys.stdout, args.subfamilies is False.
-    """
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
+def test_main_build_sql_error(output_dir, null_logger, cazy_dictionary, db_path, monkeypatch):
+    """Test main() when an error is raised when buildin a new database."""
 
     def mock_building_parser(*args, **kwargs):
         parser_args = ArgumentParser(
@@ -209,325 +257,345 @@ def mock_building_parser(*args, **kwargs):
 
     def mock_parser(*args, **kwargs):
         parser = Namespace(
-            output=sys.stdout,
-            subfamilies=False,
+            output=1,
+            subfamilies=True,
             force=False,
             nodelete=False,
-            genbank="dummy_email",
-            genbank_output=output_dir,
-            pdb="pdb",
-            pdb_output=output_dir,
-            retries=0,
+            retries=1,
+            database=None,
+            verbose=False,
+            log=None,
         )
         return parser
 
-    def mock_build_logger(*args, **kwargs):
-        return null_logger
+    def mock_config_logger(*args, **kwargs):
+        return
 
     def mock_making_output_dir(*args, **kwargs):
         return
 
     def mock_retrieving_configuration(*args, **kwargs):
-        return None, None, cazy_dict
+        return None, None, cazy_dictionary, [], None
+
+    def mock_adding_log(*args, **kwargs):
+        return
 
     def mock_retrieving_cazy_data(*args, **kwargs):
         return
 
-    monkeypatch.setattr(utilities, "build_parser", mock_building_parser)
+    monkeypatch.setattr(parsers, "build_parser", mock_building_parser)
     monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
-    monkeypatch.setattr(utilities, "build_logger", mock_build_logger)
+    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
     monkeypatch.setattr(file_io, "make_output_directory", mock_making_output_dir)
-    monkeypatch.setattr(file_io, "parse_configuration", mock_retrieving_configuration)
+    monkeypatch.setattr(parse_configuration, "parse_configuration", mock_retrieving_configuration)
+    monkeypatch.setattr(cazy_webscraper, "log_scrape_in_db", mock_adding_log)
     monkeypatch.setattr(cazy_webscraper, "get_cazy_data", mock_retrieving_cazy_data)
 
-    cazy_webscraper.main(["argv"], null_logger)
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        cazy_webscraper.main()
+    assert pytest_wrapped_e.type == SystemExit
 
 
-# test get_cazy_data
+def test_main_get_sql_error(output_dir, null_logger, cazy_dictionary, db_path, monkeypatch):
+    """Test main() when an error is raised when buildin a new database."""
 
+    def mock_building_parser(*args, **kwargs):
+        parser_args = ArgumentParser(
+            prog="cazy_webscraper.py",
+            usage=None,
+            description="Scrape the CAZy database",
+            conflict_handler="error",
+            add_help=True,
+        )
+        return parser_args
 
-def test_get_cazy_data_no_fam_urls(
-    cazy_home_url,
-    cazy_dictionary,
-    config_dict,
-    time_stamp,
-    null_logger,
-    get_cazy_data_args_none,
-    monkeypatch
-):
-    """Test get_cazy_data."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
+    path_ = output_dir / "test_outputs_sql" / "non_sql_file.html"
+
+    def mock_parser(*args, **kwargs):
+        parser = Namespace(
+            output=output_dir,
+            subfamilies=True,
+            force=False,
+            nodelete=False,
+            retries=1,
+            database=path_,
+            verbose=True,
+            log=None,
+        )
+        return parser
 
-    def mock_get_class_urls(*args, **kwargs):
-        return [
-            ["http://www.cazy.org/Glycoside-Hydrolases.html", 0],
-            ["http://www.cazy.org/Polysaccharide-Lyases.html", 0],
-        ]
+    def mock_config_logger(*args, **kwargs):
+        return
 
-    def mock_no_return(*args, **kwargs):
+    def mock_making_output_dir(*args, **kwargs):
         return
 
-    monkeypatch.setattr(cazy_webscraper, "get_class_urls", mock_get_class_urls)
-    monkeypatch.setattr(crawler, "get_cazy_family_urls", mock_no_return)
-    monkeypatch.setattr(parse, "proteins_to_dataframe", mock_no_return)
-    monkeypatch.setattr(file_io, "write_out_failed_scrapes", mock_no_return)
+    def mock_retrieving_configuration(*args, **kwargs):
+        return None, None, cazy_dictionary, [], []
 
-    cazy_webscraper.get_cazy_data(
-        cazy_home_url,
-        None,
-        config_dict,
-        cazy_dict,
-        1,
-        time_stamp,
-        null_logger,
-        get_cazy_data_args_none["args"],
-    )
+    def mock_retrieving_cazy_data(*args, **kwargs):
+        return
 
+    def mock_getting_db_session(*args, **kwargs):
+        raise TypeError
 
-def test_get_cazy_data_no_fam_returned(
-    time_stamp,
+    monkeypatch.setattr(parsers, "build_parser", mock_building_parser)
+    monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
+    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
+    monkeypatch.setattr(file_io, "make_output_directory", mock_making_output_dir)
+    monkeypatch.setattr(parse_configuration, "parse_configuration", mock_retrieving_configuration)
+    monkeypatch.setattr(cazy_webscraper, "get_cazy_data", mock_retrieving_cazy_data)
+    monkeypatch.setattr(sql.sql_orm, "get_db_session", mock_getting_db_session)
+
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        cazy_webscraper.main()
+    assert pytest_wrapped_e.type == SystemExit
+
+
+# test get_cazy_data()
+
+
+def test_get_cazy_data_no_fam_urls(
     cazy_home_url,
     cazy_dictionary,
     config_dict,
-    null_logger,
-    get_cazy_data_args_none,
+    time_stamp,
+    args_get_cazy_data,
     monkeypatch
 ):
-    """Test get_cazy_data() when data_split is None, subfamilies is False."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    def mock_get_class_urls(*args, **kwargs):
-        return [
-            ["http://www.cazy.org/Glycoside-Hydrolases.html", 0],
-            ["http://www.cazy.org/Polysaccharide-Lyases.html", 0],
-        ]
-
-    def mock_get_family_urls(*args, **kwargs):
-        return [
-            "dddwww.cazddddy.org/GH1.html",
-            "http://www.cazy.org/GH1.html",
-            "http://www.cazy.org/PL1.html",
-        ]
+    """Test get_cazy_data() when no family URLS are retrieved, and fails to scrape families from
+    a class.
+    """
+
+    fam1 = crawler.Family("test_fam", "test_class", "test_url")
+
+    def mock_get_classes(*args, **kwargs):
+        class1 = crawler.CazyClass("test_class", "test_class_url.html", 0)
+        class2 = crawler.CazyClass("test_class2", "test_class_url2.html", 0)
+        return [class1, class2]
+
+    def mock_get_families(*args, **kwargs):
+        return None, "test error message", ["test_url1", "test_url2"]
 
     def mock_parse_family(*args, **kwargs):
-        return [None, "mock error message"]
+        return fam1, True, ["fail1", "fail2"], ["sqlFail1", "sqlFail2"]
 
     def mock_no_return(*args, **kwargs):
         return
 
-    monkeypatch.setattr(cazy_webscraper, "get_class_urls", mock_get_class_urls)
-    monkeypatch.setattr(crawler, "get_cazy_family_urls", mock_get_family_urls)
+    monkeypatch.setattr(crawler, "get_cazy_classes", mock_get_classes)
+    monkeypatch.setattr(crawler, "get_cazy_family_urls", mock_get_families)
     monkeypatch.setattr(crawler, "parse_family", mock_parse_family)
-    monkeypatch.setattr(parse, "proteins_to_dataframe", mock_no_return)
     monkeypatch.setattr(file_io, "write_out_failed_scrapes", mock_no_return)
 
     cazy_webscraper.get_cazy_data(
         cazy_home_url,
         None,
         config_dict,
-        cazy_dict,
-        1,
+        cazy_dictionary,
+        None,
+        2,
         time_stamp,
-        null_logger,
-        get_cazy_data_args_none["args"],
+        "session",
+        args_get_cazy_data["args"],
     )
 
 
-def test_get_cazy_data_subfams_split_fam(
+def test_get_cazy_data_no_config_dict(
     time_stamp,
     cazy_home_url,
     cazy_dictionary,
-    config_dict,
-    mock_family,
-    null_logger,
-    get_cazy_data_args_family,
+    args_get_cazy_data,
     monkeypatch
 ):
-    """Test get_cazy_data() when data split is family and subfamily is True."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    def mock_get_class_urls(*args, **kwargs):
-        return [
-            ["http://www.cazy.org/Glycoside-Hydrolases.html", 0],
-            ["http://www.cazy.org/Polysaccharide-Lyases.html", 0],
-        ]
-
-    def mock_get_family_urls(*args, **kwargs):
-        return [
-            "dddwww.cazddddy.org/GH1.html",
-            "http://www.cazy.org/GH1.html",
-            "http://www.cazy.org/PL1.html",
-        ]
+    """Test get_cazy_data() when some families aren't scraped, and config_dict is None."""
+
+    fam1 = crawler.Family("test_fam", "test_class", "test_url")
+
+    def mock_get_classes(*args, **kwargs):
+        class1 = crawler.CazyClass("test_class", "test_class_url.html", 0, {fam1: 0})
+        return [class1]
 
     def mock_parse_family(*args, **kwargs):
-        return [mock_family, None]
+        return fam1, True, ["fail1", "fail2"], ["sqlFail1", "sqlFail2"]
 
     def mock_no_return(*args, **kwargs):
         return
 
-    monkeypatch.setattr(cazy_webscraper, "get_class_urls", mock_get_class_urls)
-    monkeypatch.setattr(crawler, "get_cazy_family_urls", mock_get_family_urls)
+    monkeypatch.setattr(crawler, "get_cazy_classes", mock_get_classes)
     monkeypatch.setattr(crawler, "parse_family", mock_parse_family)
-    monkeypatch.setattr(parse, "proteins_to_dataframe", mock_no_return)
+    monkeypatch.setattr(file_io, "write_out_failed_proteins", mock_no_return)
     monkeypatch.setattr(file_io, "write_out_failed_scrapes", mock_no_return)
 
     cazy_webscraper.get_cazy_data(
         cazy_home_url,
         None,
-        config_dict,
-        cazy_dict,
-        1,
+        None,
+        cazy_dictionary,
+        None,
+        2,
         time_stamp,
-        null_logger,
-        get_cazy_data_args_family["args"],
+        "session",
+        args_get_cazy_data["args"],
     )
 
 
-def test_get_cazy_data_subfams_split_class(
+def test_get_cazy_data_with_config_dict(
     time_stamp,
     cazy_home_url,
     cazy_dictionary,
     config_dict,
-    mock_family,
-    null_logger,
-    get_cazy_data_args_class,
+    args_get_cazy_data,
     monkeypatch
 ):
-    """Test get_cazy_data() when data split is class and subfamily is True."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    def mock_get_class_urls(*args, **kwargs):
-        return [
-            ["http://www.cazy.org/Glycoside-Hydrolases.html", 0],
-            ["http://www.cazy.org/Polysaccharide-Lyases.html", 0],
-        ]
-
-    def mock_get_family_urls(*args, **kwargs):
-        return [
-            "dddwww.cazddddy.org/GH1.html",
-            "http://www.cazy.org/GH1.html",
-            "http://www.cazy.org/PL1.html",
-        ]
+    """Test get_cazy_data() when some families aren't scraped, and a config_dict is given."""
+
+    fam1 = crawler.Family("GH3", "Glycoside Hydrolases (GHs)", "test_url")
+
+    def mock_get_classes(*args, **kwargs):
+        class1 = crawler.CazyClass(
+            "Glycoside Hydrolases (GHs)",
+            "test_class_url.html",
+            0,
+        )
+        return [class1]
 
     def mock_parse_family(*args, **kwargs):
-        return [mock_family, None]
+        return fam1, False, [], ["sqlFail1", "sqlFail2"]
 
     def mock_no_return(*args, **kwargs):
         return
 
-    monkeypatch.setattr(cazy_webscraper, "get_class_urls", mock_get_class_urls)
-    monkeypatch.setattr(crawler, "get_cazy_family_urls", mock_get_family_urls)
+    monkeypatch.setattr(crawler, "get_cazy_classes", mock_get_classes)
     monkeypatch.setattr(crawler, "parse_family", mock_parse_family)
-    monkeypatch.setattr(parse, "proteins_to_dataframe", mock_no_return)
+    monkeypatch.setattr(file_io, "write_out_failed_proteins", mock_no_return)
     monkeypatch.setattr(file_io, "write_out_failed_scrapes", mock_no_return)
 
     cazy_webscraper.get_cazy_data(
         cazy_home_url,
         None,
         config_dict,
-        cazy_dict,
-        1,
+        cazy_dictionary,
+        None,
+        2,
         time_stamp,
-        null_logger,
-        get_cazy_data_args_class["args"],
+        "session",
+        args_get_cazy_data["args"],
     )
 
 
-def test_get_cazy_data_split_none(
+def test_get_cazy_data_witha_config_dict_subfam(
     time_stamp,
     cazy_home_url,
     cazy_dictionary,
     config_dict,
-    mock_family,
-    null_logger,
-    get_cazy_data_args_none,
+    args_get_cazy_data,
     monkeypatch
 ):
-    """Test get_cazy_data() when data split is None and subfamily is False."""
-    with open(cazy_dictionary, "r") as fh:
-        cazy_dict = json.load(fh)
-
-    def mock_get_class_urls(*args, **kwargs):
-        return [
-            ["http://www.cazy.org/Glycoside-Hydrolases.html", 0],
-            ["http://www.cazy.org/Polysaccharide-Lyases.html", 0],
-        ]
-
-    def mock_get_family_urls(*args, **kwargs):
-        return [
-            "dddwww.cazddddy.org/GH1.html",
-            "http://www.cazy.org/GH1.html",
-            "http://www.cazy.org/PL1.html",
-        ]
+    """Test get_cazy_data() when some families aren't scraped, and a config_dict is given."""
+
+    fam1 = crawler.Family("GH3_1", "Glycoside Hydrolases (GHs)", "test_url")
+
+    def mock_get_classes(*args, **kwargs):
+        class1 = crawler.CazyClass(
+            "Glycoside Hydrolases (GHs)",
+            "test_class_url.html",
+            0,
+            {fam1: 0},
+        )
+        return [class1]
 
     def mock_parse_family(*args, **kwargs):
-        return [mock_family, None]
+        return fam1, True, ["fail1", "fail2"], ["sqlFail1", "sqlFail2"]
 
     def mock_no_return(*args, **kwargs):
         return
 
-    monkeypatch.setattr(cazy_webscraper, "get_class_urls", mock_get_class_urls)
-    monkeypatch.setattr(crawler, "get_cazy_family_urls", mock_get_family_urls)
+    monkeypatch.setattr(crawler, "get_cazy_classes", mock_get_classes)
     monkeypatch.setattr(crawler, "parse_family", mock_parse_family)
-    monkeypatch.setattr(parse, "proteins_to_dataframe", mock_no_return)
+    monkeypatch.setattr(file_io, "write_out_failed_proteins", mock_no_return)
     monkeypatch.setattr(file_io, "write_out_failed_scrapes", mock_no_return)
 
     cazy_webscraper.get_cazy_data(
         cazy_home_url,
         None,
         config_dict,
-        cazy_dict,
-        1,
+        cazy_dictionary,
+        None,
+        2,
         time_stamp,
-        null_logger,
-        get_cazy_data_args_none["args"],
+        "session",
+        args_get_cazy_data["args"],
     )
 
 
-# test get_class_urls
+# tests for adding log to the local database
 
 
-def test_get_class_urls_no_urls(cazy_home_url, null_logger, monkeypatch):
-    """Test get_class_urls() when an empty list is returned."""
-
-    def mock_class_urls(*args, **kwargs):
-        return []
+def test_add_db_log_no_config(db_session):
+    config_dict = None
+    taxonomy_filters = {"genera": None, "species": None, "strains": None}
+    kingdoms = ["Archaea", "Bacteria", "Eukaryota", "Viruses", "Unclassified"]
+    args = {
+        "args": Namespace(
+            classes=None,
+            families=None,
+            genera=None,
+            species=None,
+            strains=None,
+            kingdoms=None,
+        )
+    }
 
-    monkeypatch.setattr(crawler, "get_cazy_class_urls", mock_class_urls)
+    cazy_webscraper.log_scrape_in_db(
+        "YYYY-MM-DD--HH-MM-SS",
+        config_dict,
+        taxonomy_filters,
+        kingdoms,
+        db_session,
+        args["args"],
+    )
 
-    with pytest.raises(SystemExit) as pytest_wrapped_e:
-        cazy_webscraper.get_class_urls(cazy_home_url, None, 1, null_logger)
-    assert pytest_wrapped_e.type == SystemExit
 
+def test_add_db_log_with_config(db_session):
+    config_dict = {}
+    taxonomy_filters = {
+        "genera": ["Caldivirga", "Cuniculiplasma"],
+        "species": ["Pyrococcus furiosus"],
+        "strains": ["Saccharolobus solfataricus POZ149", "Saccharolobus solfataricus SULB"]
+    }
+    kingdoms = ["Archaea"]
+    args = {
+        "args": Namespace(
+            classes="GH,PL",
+            families="AA1,AA2",
+            genera="Trichoderma",
+            species="Aspergillus Niger",
+            strains="Acidianus ambivalens LEI 10",
+            kingdoms="Archaea,Bacteria"
+        )
+    }
 
-def test_get_class_urls_none_urls(cazy_home_url, null_logger, monkeypatch):
-    """Test get_class_urls() when a None type object is returned."""
+    cazy_webscraper.log_scrape_in_db(
+        "YYYY-MM-DD--HH-MM-SS",
+        config_dict,
+        taxonomy_filters,
+        kingdoms,
+        db_session,
+        args["args"],
+    )
 
-    def mock_class_urls(*args, **kwargs):
-        return
 
-    monkeypatch.setattr(crawler, "get_cazy_class_urls", mock_class_urls)
+# tests for parsing taxonomy filters
 
-    with pytest.raises(SystemExit) as pytest_wrapped_e:
-        cazy_webscraper.get_class_urls(cazy_home_url, None, 1, null_logger)
-    assert pytest_wrapped_e.type == SystemExit
 
+def test_get_filter_set():
+    taxonomy_dict = {"genera": None, "species": ["species1", "species2"]}
 
-def test_get_class_urls_success(cazy_home_url, null_logger, monkeypatch):
-    """Test get_class_urls() when URLs were returned."""
+    assert set(["species1", "species2"]) == cazy_webscraper.get_filter_set(taxonomy_dict)
 
-    def mock_class_urls(*args, **kwargs):
-        return ["url1", "url2", "url3"]
 
-    monkeypatch.setattr(crawler, "get_cazy_class_urls", mock_class_urls)
+def test_get_filter_set_none():
+    taxonomy_dict = {"genera": None, "species": None}
 
-    assert [['url1', 0], ['url2', 0], ['url3', 0]] == cazy_webscraper.get_class_urls(
-        cazy_home_url,
-        None,
-        1,
-        null_logger,
-    )
+    assert None is cazy_webscraper.get_filter_set(taxonomy_dict)