3

I'm converting an array to a csv so that I can import items rapidly to Shopify. According to Shopify, you must do the following to add multiple images when importing:

  1. Insert new rows (one per picture).
  2. Copy + paste the "handle".
  3. Copy + paste the image URLs.

Thus, the first image goes in the first row, and all subsequent images go in rows below. The example CSV is located here: https://help.shopify.com/csv/product_template.csv

Thus, I would like to program something that will loop through an array, which looks like the following (except significantly longer), and converts it to a CSV, putting all the photos except the first into a new row.

var array = [
  {
    "brief": "Brief 1",
    "description": "Description 1",
    "photos": [
      "https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example.jpg?0101010101010",
      "https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example2.jpg?0101010101010",
      "https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example3.jpg?0101010101010"
    ],
    "price": "145",
    "tags": [
      "tag1",
      "tag2",
      "tag3"
    ],
    "title": "Title 1"
  },
  {
    "brief": "Brief 2",
    "description": "Description 2",
    "photos": [
      "https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example4.jpg?0101010101010",
      "https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example5.jpg?0101010101010"
    ],
    "price": "150",
    "tags": [
      "tag4",
      "tag5",
      "tag6",
      "tag7",
      "tag8",
    ],
    "title": "Title 2"
  }
]

I typically do this sort of thing with json2csv, which would look something like the following, only I'm not sure how to handle the multi-line aspect.

json2csv -i data_in.json -f title,description,price,etc -o data_out.csv

Python might also be a good option, as following this post, but again the multi-line aspect is confusing:

import csv
import json

x = """[
  {
    "brief": "Brief 1",
    "description": "Description 1",
    "photos": [
      "https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example.jpg?0101010101010",
      "https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example2.jpg?0101010101010",
      "https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example3.jpg?0101010101010"
    ],
    "price": "145",
    "tags": [
      "tag1",
      "tag2",
      "tag3"
    ],
    "title": "Title 1"
  },
  {
    "brief": "Brief 2",
    "description": "Description 2",
    "photos": [
      "https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example4.jpg?0101010101010",
      "https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example5.jpg?0101010101010"
    ],
    "price": "150",
    "tags": [
      "tag4",
      "tag5",
      "tag6",
      "tag7",
      "tag8",
    ],
    "title": "Title 2"
  }
]"""

x = json.loads(x)

f = csv.writer(open("example.csv", "wb+"))

# Write CSV Header, If you dont need that, remove this line
f.writerow(["title", "description", "price"])

for x in x:
    f.writerow([x["title"],
                x["description"],
                x["price"])

The output row tops of the CSV would be as follows (must "Run Snippet" to see as table) - please note I'm not trying to create an HTML table:

<style type="text/css">
.tg  {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-yw4l{vertical-align:top}
</style>
<table class="tg">
  <tr>
    <th class="tg-yw4l">Handle</th>
    <th class="tg-yw4l">Title</th>
    <th class="tg-yw4l">Body (HTML)</th>
    <th class="tg-yw4l">Vendor</th>
    <th class="tg-yw4l">Type</th>
    <th class="tg-yw4l">Tags</th>
    <th class="tg-yw4l">Published</th>
    <th class="tg-yw4l">Option1 Name</th>
    <th class="tg-yw4l">Option1 Value</th>
    <th class="tg-yw4l">Option2 Name</th>
    <th class="tg-yw4l">Option2 Value</th>
    <th class="tg-yw4l">Option3 Name</th>
    <th class="tg-yw4l">Option3 Value</th>
    <th class="tg-yw4l">Variant SKU</th>
    <th class="tg-yw4l">Variant Grams</th>
    <th class="tg-yw4l">Variant Inventory Tracker</th>
    <th class="tg-yw4l">Variant Inventory Qty</th>
    <th class="tg-yw4l">Variant Inventory Policy</th>
    <th class="tg-yw4l">Variant Fulfillment Service</th>
    <th class="tg-yw4l">Variant Price</th>
    <th class="tg-yw4l">Variant Compare At Price</th>
    <th class="tg-yw4l">Variant Requires Shipping</th>
    <th class="tg-yw4l">Variant Taxable</th>
    <th class="tg-yw4l">Variant Barcode</th>
    <th class="tg-yw4l">Image Src</th>
    <th class="tg-yw4l">Image Alt Text</th>
    <th class="tg-yw4l">Gift Card</th>
    <th class="tg-yw4l">Google Shopping / MPN</th>
    <th class="tg-yw4l">Google Shopping / Age Group</th>
    <th class="tg-yw4l">Google Shopping / Gender</th>
    <th class="tg-yw4l">Google Shopping / Google Product Category</th>
    <th class="tg-yw4l">SEO Title</th>
    <th class="tg-yw4l">SEO Description</th>
    <th class="tg-yw4l">Google Shopping / AdWords Grouping</th>
    <th class="tg-yw4l">Google Shopping / AdWords Labels</th>
    <th class="tg-yw4l">Google Shopping / Condition</th>
    <th class="tg-yw4l">Google Shopping / Custom Product</th>
    <th class="tg-yw4l">Google Shopping / Custom Label 0</th>
    <th class="tg-yw4l">Google Shopping / Custom Label 1</th>
    <th class="tg-yw4l">Google Shopping / Custom Label 2</th>
    <th class="tg-yw4l">Google Shopping / Custom Label 3</th>
    <th class="tg-yw4l">Google Shopping / Custom Label 4</th>
    <th class="tg-yw4l">Variant Image</th>
    <th class="tg-yw4l">Variant Weight Unit</th>
    <th class="tg-yw4l"></th>
    <th class="tg-yw4l"></th>
  </tr>
  <tr>
    <td class="tg-yw4l">Title 1</td>
    <td class="tg-yw4l">Title 1</td>
    <td class="tg-yw4l">Description 1</td>
    <td class="tg-yw4l">Vendor Name</td>
    <td class="tg-yw4l">Product Type</td>
    <td class="tg-yw4l">"tag1,tag2,tag3"</td>
    <td class="tg-yw4l">TRUE</td>
    <td class="tg-yw4l">Title 1</td>
    <td class="tg-yw4l">Default Title</td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l">1</td>
    <td class="tg-yw4l">deny</td>
    <td class="tg-yw4l">manual</td>
    <td class="tg-yw4l">145</td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l">TRUE</td>
    <td class="tg-yw4l">TRUE</td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l">https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example.jpg?0101010101010</td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
  </tr>
  <tr>
    <td class="tg-yw4l">Title 1</td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l">https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example2.jpg?0101010101010</td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
  </tr>
  <tr>
    <td class="tg-yw4l">Title 1</td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l">https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example3.jpg?0101010101010</td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
    <td class="tg-yw4l"></td>
  </tr>
</table>
maudulus
  • 10,627
  • 10
  • 78
  • 117

1 Answers1

1

It's not particularly hard. Your code is nearly right (assuming the columns are laid out how you want them, and assuming you pass valid JSON in, because yours has an extra comma), you just need to add a little:

for x in x:
    images = x["photos"]
    f.writerow([x["title"],
                x["description"],
                x["price"],
                images.pop(0) if images else None])
    while images:
        f.writerow([None, None, None, images.pop(0)])

What this does in short is loop over all of the images in order and print them in new, otherwise-empty rows. Running it on your original code, example.csv ends up looking like this:

title,description,price
Title 1,Description 1,145,https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example.jpg?0101010101010
,,,https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example2.jpg?0101010101010
,,,https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example3.jpg?0101010101010
Title 2,Description 2,150,https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example4.jpg?0101010101010
,,,https://cdn.shopify.com/s/files/1/01/01/01/files/imgs-example5.jpg?0101010101010

It should be pretty obvious how to get the things into different columns -- the Nones are just so csv.writer leaves the cell empty, so use them as placeholders for all the other columns.

If this needed to be easy to modify, I'd recommend a different approach. This looks like a one-off conversion script, though, so a quick, easy hack will work just fine.

A few notes:

  • a if b else c, if b evaluates to True, means a; if it evaluates to False, it means c.
  • ary.pop(n) pops (removes and returns) the object at index n from ary.
  • An empty array evaluates to False (hence why I test just images, not len(images) == 0)
  • You'll probably also want to update the headers. I just them as-is so my only changes were to the last while; you'll probably want to fix them to accurately label the columns.
Nic
  • 6,211
  • 10
  • 46
  • 69