In [1]:
#sources:
#creating and deleting paths: https://stackabuse.com/creating-and-deleting-directories-with-python/
#using requests to download data from URLs: https://realpython.com/python-requests/
#using arrays to download a list of URLs: https://likegeeks.com/downloading-files-using-python/
#reading zipped shapefiles: https://medium.com/@loldja/reading-shapefile-zips-from-a-url-in-python-3-93ea8d727856
#listing feature classes: https://pro.arcgis.com/en/pro-app/arcpy/functions/listfeatureclasses.htm

import os #manipulate files and paths
import arcpy #Esri data management
import zipfile #manipulate zipped files
import io #work with input/output
import requests #requests allows you to download large files without consuming a lot of memory
import shutil #shutil supports file copying and removal

#list of tuples of counties and download URLs
urls = [('Benton', 'http://www.mediafire.com/file/gnd4a9yjcya9zsc/Parcel.zip/file'),
        ('Clallam', 'http://www.clallam.net/Maps/parcel.zip'),
        ('Ferry', 'https://www.ferry-county.com/Other_Depts/GIS_Dept_Files/Parcel%20Layer/2020-02%20FC%20PARCEL%20LAYER.zip'),
        ('Franklin', 'http://franklingis.org/Data/Parcels_Web.zip'),
        ('Grant', 'http://www.grantcountywa.gov/GIS/MISC/ZIPDATA/Parcel_boundaries.zip'),
        ('GraysHarbor', 'http://www.co.grays-harbor.wa.us/GIS/Data_Download/Parcel.zip'),
        ('Island', 'https://maps.islandcountywa.gov/WebFiles/DataDownloads/Parcels.zip'),
        ('Jefferson', 'https://opendata.arcgis.com/datasets/c0fa49b507ed4d57b9aa2dbc4314c4f0_4.zip?outSR=%7B%22latestWkid%22%3A3857%2C%22wkid%22%3A102100%7D'),
        ('King', 'https://opendata.arcgis.com/datasets/c7a17b7ad3ec44b7ae64796dca691d72_1722.zip'),
        ('Kittitas', 'https://opendata.arcgis.com/datasets/bda6b56b35cd461b8b600b4f98f564c7_1.zip?outSR=%7B%22latestVcsWkid%22%3A6360%2C%22latestWkid%22%3A2286%2C%22wkid%22%3A102749%2C%22vcsWkid%22%3A105703%7D'),
        ('Lewis', 'https://maps.lewiscountywa.gov/data/parcels_NoOwner.zip'),
        ('Mason', 'http://www.arcgis.com/sharing/rest/content/items/186d264834fd4d1c84eed4b617f4b0ac/data'),
        ('Okanogan', 'http://www.okanogancounty.org/planning/zip/parcels.zip'),
        ('Pacific', 'https://www.co.pacific.wa.us/gis/DesktopGIS/WEB/data_2006/tax_lots.zip'),
        ('Pierce', 'https://opendata.arcgis.com/datasets/0ef33b5e288f49b38b936f6047ba1ace_0.zip?outSR=%7B%22latestWkid%22%3A2927%2C%22wkid%22%3A2927%7D'),
        ('SanJuan', 'https://opendata.arcgis.com/datasets/03e90bc346594df88f9b3edc73eb83dd_1.zip'),
        ('Spokane', 'https://opendata.arcgis.com/datasets/228db1be1d6940a3b5e3f2104e470134_0.zip'),
        ('Thurston', 'https://opendata.arcgis.com/datasets/04030948640b42a992fa2d644898e359_0.zip'),
        ('Yakima', 'https://opendata.arcgis.com/datasets/681e5ccefbb24cb59c0f7969fd8994b4_0.zip')]

#create temp folder for workspace
work_path = r'<PATH>\temp' #this would be changed if you wanted a different location
os.mkdir(work_path)
print('Temp folder created')

#set workspace
arcpy.env.workspace = work_path

#create file GDB
gdb_folder_path = r'<PATH>' #this would be changed if you wanted a different location
gdb_name = 'counties.gdb'
arcpy.CreateFileGDB_management(gdb_folder_path, gdb_name)

print('Geodatabase created')

#define lists to add failed download and extracts to
download_failure = []
extract_failure = []

print('Beginning data download...')

#function for downloading and extracting parcel shapefiles
def county_download(url):
    path, url = url
    response = requests.get(url, stream=True) #'get' the URL. set stream to true to only dowload one file at a time
    
    if response: #if county shapefile download succeeds
        
        try: #try to extract the contents of the zipped folder
            zipshape = zipfile.ZipFile(io.BytesIO(response.content))
            zipshape.extractall(work_path + '\/' + str(path)) #extract to folder with same name as county
        
        except: #if it is a bad zip file, add it to the extract_failure list
            extract_failure.append(x)
                
    else: #if error code is returned/download failed, add it to the download_failure list
        download_failure.append(x)

#run the county_download function for each county's URL in list
for x in urls:
    county_download(x)

#print lists of failed downloads and extracts
print('Failed downloads: ' + str(download_failure))
print('Failed extracts: ' + str(extract_failure))

print('Data download complete!')

print('Exporting to geodatabase...')

#create list of county folders in the temp downloads folder
import os
FileDirectoryPath = work_path
files = []
files = [f for f in sorted(os.listdir(FileDirectoryPath))]
#print(files) #optional to list the county folders in the temp downloads folder

#create list to append failed exports to
export_failure = []

#function for exporting each shapefile to the gdb
def county_export(i):
        arcpy.env.workspace = work_path + '\/' + str(i)
        gdb = r'<PATH>\counties.gdb' #this would be changed if you used a different location to create the gdb
        fc = arcpy.ListFeatureClasses()
        
        for shp in fc:
            inFeatures = shp
            outLocation = gdb
            outFeatureClass = str(i)

            #export shapefiles to gdb
            try:
                arcpy.FeatureClassToFeatureClass_conversion(inFeatures, outLocation, outFeatureClass)
            except:
                export_failure.append(i)

#run county_export function
for i in files:
    county_export(i)

#print list of failed exports
print('Failed exports: ' + str(export_failure))

#delete county folders
shutil.rmtree(FileDirectoryPath)
print('County folders deleted')
print('Script complete!')
Temp folder created
Geodatabase created
Beginning data download...
Failed downloads: [('Ferry', 'https://www.ferry-county.com/Other_Depts/GIS_Dept_Files/Parcel%20Layer/2020-02%20FC%20PARCEL%20LAYER.zip')]
Failed extracts: [('King', 'https://opendata.arcgis.com/datasets/c7a17b7ad3ec44b7ae64796dca691d72_1722.zip')]
Data download complete!
Exporting to geodatabase...
Failed exports: []
County folders deleted
Script complete!
In [ ]: