Skip to content

Instantly share code, notes, and snippets.

@answerquest
Created April 30, 2018 10:40
Show Gist options
  • Select an option

  • Save answerquest/9f575120e7cae5e3601d77ff33519fe5 to your computer and use it in GitHub Desktop.

Select an option

Save answerquest/9f575120e7cae5e3601d77ff33519fe5 to your computer and use it in GitHub Desktop.
Shopify 2 WooCommerce import CSV
# Usage: python3 shopify2woocommerce.py https://ABC.myshopify.com
# or for interactive mode, just: python3 shopify2woocommerce.py
import json
import os.path
import requests
from collections import OrderedDict
import pandas as pd
from sys import argv, exit
# Flags, accumulators
interactiveMode = False
collector = []
# create folders if they don't exist
if not os.path.exists('jsons'):
os.makedirs('jsons')
##############################
# Functions:
def downloadFile(x,y):
if os.path.exists(y) :
# print('skipping '+ y + ' as its already been downloaded.')
return
print('\nDownloading '+x)
try:
r = requests.get(x, allow_redirects=True)
except requests.exceptions.RequestException as e: # from https://stackoverflow.com/a/16511493/4355695
print('\nInvalid URL.')
if interactiveMode: interactiveExit()
else: exit()
with open(y, 'wb') as f:
f.write(r.content)
print( 'Saved as '+ y )
def interactiveExit():
print('\n\nPress any key to exit.\n')
a = input()
exit()
#############################
# Main Program Start:
# taking first argument as URL, or asking user to provide URL
if len(argv) > 1 :
shopifyURL = argv[1]
else:
print('\n\nEnter a shopify URL, like https://abc.myshopify.com:')
shopifyURL = input()
interactiveMode = True
downloadFile( shopifyURL + '/collections.json', 'jsons/collections.json' )
collections = json.load(open('jsons/collections.json')).get('collections',[]);
#########################################
# Looping through each collection
print('\n\nShopify API to WooCommerce-import-CSV converter.\n\nStarting to loop through collections')
for collection in collections:
handle = collection.get('handle')
category = collection.get('title')
countCheck = collection.get('products_count')
# https://ecoexist-enterprises.myshopify.com/collections/cloth-bags-15-x-17/products.json
productJsonURL = 'https://ecoexist-enterprises.myshopify.com/collections/' + handle + '/products.json'
productJson = 'jsons/' + handle + '.json'
if countCheck: downloadFile( productJsonURL, productJson )
else: continue
products = json.load(open(productJson)).get('products',[])
print( '\nCATEGORY: ' + category + ' has ' + str(len(products)) + ' products.')
#########################################
# Looping through each product entry in the collection
for product in products:
common = OrderedDict()
numVariants = len( product.get('variants',[]))
common['SKU'] = product.get('handle')
#########################################
# duplicates check, and if so, then just add the collection to categories and skip to next loop.
repeatingSKU = False
for x in collector:
if x['SKU'] == common['SKU']:
x['Categories'] += ', ' + category
categorycount = len( x['Categories'].split(', ') )
print( 'handle=' + x['SKU'] + ' encountered again, it now has ' + str(categorycount) + ' Categories.')
repeatingSKU = True
break
if repeatingSKU:
continue
common['Name'] = product.get('title')
common['Description'] = product.get('body_html').replace('\n','')
common['Categories'] = category
common['Tags'] = ', '.join( product.get('tags') )
# Images:
imageURLs = [ x.get('src') for x in product.get('images',[]) ]
common['Images'] = ', '.join(imageURLs)
numOptions = len( product.get('options',[])[0].get('values'))
if numOptions > 1: print('OPTIONS for product ' + common['SKU'] +' : ' + str(numOptions))
#########################################
# assumptions
common['Is featured?'] = 0
common['Stock'] = ''
common['Backorders allowed?'] = 0
common['Sold individually?'] = 0
common['Length (in)'] = ''
common['Width (in)'] = ''
common['Height (in)'] = ''
common['Allow customer reviews?'] = 0
common['Stock'] = ''
# defaults
common['Published'] = 1
common['Visibility in catalog'] = 'visible'
row = OrderedDict(common) # making a copy.. see if this works
#########################################
# now, here we check for variants
# firstly, if it's a simple product with no variants, it'll have ONE variant in shopify.
if (numVariants < 2):
row['Type'] = 'simple'
# print( product.get('variants')[0].get('taxable') )
taxStatus = product.get('variants')[0].get('taxable')
# row['Tax status'] = ('taxable' if taxStatus else 'not taxable')
# skipping tax status.. woocommerce didn't accept "not taxable"
row['In stock?'] = 1 if product.get('variants')[0].get('available') else 0
grams = product.get('variants')[0].get('grams') if ( row['Type'] == 'simple' ) else 0
#row['Weight (lbs)'] = 0.00220462 * grams if ( grams > 0 ) else ''
# not doing weight, importer isn't taking it.
row['Regular price'] = product.get('variants')[0].get('price') if (numVariants == 1) else ''
collector.append(row)
#########################################
# next, if there's variants then processing each variant and adding as a new entry to the table
else:
print( 'VARIATIONS for product ' + row['SKU'] + ' : ' + str(numVariants) )
# first, let's complete the parent row. Most fields will be left blank here as their variants step in.
row['Type'] = 'variable'
row['Attribute 1 name'] = product.get('options',[])[0].get('name')
row['Attribute 1 value(s)'] = ', '.join( product.get('options',[])[0].get('values') )
collector.append(row)
# next, make a new row for each variation
for variant in product.get('variants',[]):
row2 = OrderedDict(common)
row2['Type'] = 'variation'
row2['SKU'] = common['SKU'] + '-' + variant.get('title').lower()
# have to over-write the parent's SKU with a new one. This was what was causing a duplicating issue for all variants. Shopify didn't give
row2['Name'] = common['Name'] + ' - ' + variant.get('title')
# have to pre-pend the parent's title to variant's title to get full title.
row2['In stock?'] = 1 if variant.get('available') else 0
grams = variant.get('grams')
#row2['Weight (lbs)'] = 0.00220462 * grams if ( grams > 0 ) else ''
# not doing weight, importer isn't taking it.
row2['Regular price'] = variant.get('price') if (numVariants == 1) else ''
# if there's a featured image, add at beginning of images list
if variant.get('featured_image'):
featured = variant.get('featured_image').get('src')
if featured in imageURLs:
# if the featured image is there in the list, remove it so it can be inserted at beginning without repeating.
imageURLs.remove(featured)
imageURLs.insert(0,featured)
common['Images'] = ', '.join(imageURLs)
collector.append(row2)
df = pd.DataFrame(collector)
df.to_csv('woocommerce-import.csv', index=False)
print('\n\nProcessed ' + shopifyURL + '. Total ' + str(len(df)) + ' products found.')
print('Created woocommerce-import.csv in the same folder where you ran this script.')
if interactiveMode:
interactiveExit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment