Bookmarklet for Creating a CSV From an HTML Table

We have a wiki at work that we use for documentation called Confluence. It has the ability to export pages to Word or PDF, but a lacking feature is the ability to take a table and export it for Excel. So, I decided to create a bookmarklet that will allow you to select an HTML table on any web page and create a CSV file from that table that can be downloaded to your machine. Below is the bookmarklet. Just drag it to your bookmarks toolbar. Then give it a shot by clicking the bookmarklet and the below example table should get a link right before it that says “Export to CSV”. Click that link and you will be prompted to download the CSV version of that table. Let me know if it is useful for you.

On thing of note, this will not work correctly in Internet Explorer 9 and below as IE will not allow data uri’s for anything other than images.

Bookmarklet:
Export to CSV <- drag this to your bookmarks toolbar

Update:
05/08/2019 – Enhanced to not kill line breaks.
09/16/2016 – Now works with IE 10+.
04/19/2016 – Fixed issue with tables that have header cells not on top.

Example Table:

Heading 1Heading 2Heading 3Heading 4Heading 5Heading 6
Data 1, 1Data 1, 2Data 1, 3Data 1, 4Data 1, 5Data 1, 6
Data 2, 1Data 2, 2Data 2, 3Data 2, 4Data 2, 5Data 2, 6
Data 3, 1Data 3, 2Data 3, 3Data 3, 4Data 3, 5Data 3, 6
Data 4, 1Data 4, 2Data 4, 3Data 4, 4Data 4, 5Data 4, 6
Data 5, 1Data 5, 2Data 5, 3Data 5, 4Data 5, 5Data 5, 6
Data 6, 1Data 6, 2Data 6, 3Data 6, 4Data 6, 5Data 6, 6

Bookmarklet Source: 

javascript:(function(){
    function getJavaScript(url, success) {
        var script = document.createElement('script');
            script.src = url;
        var head = document.getElementsByTagName('head')[0],
            done = false;
        script.onload = script.onreadystatechange = function(){
            if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
                done = true;
                success();
                script.onload = script.onreadystatechange = null;
                head.removeChild(script);
            }
        };
        head.appendChild(script);
    }
    function addCSVLinks() {
        jQuery('.csvLink').remove();
        
        jQuery('table').each(function(index){
            jQuery(this).attr('data-csvtable', index).before('<a href="#" class="csvLink" data-forcsvtable="' + index + '">Export to CSV</a>');
        });
        
        jQuery('.csvLink').click(function(){
            var text = '';
            var csvTableIndex = jQuery(this).attr('data-forcsvtable');
            jQuery('table[data-csvtable="' + csvTableIndex + '"] tr').each(function(){
                jQuery('td, th', this).each(function(index){
                    if(index != 0) {
                        text += ',';
                    }
                    text += '"' + formatedText(jQuery(this).html()) + '"';
                });
                text += '\r\n';
            });
            jQuery('.csvLink').remove();
            downloadCSVFile('TableExport.csv', 'text/csv', text);
        });
    }
	function formatedText(html) {
		var ret = html;
		
		//replace line breaks
		ret = ret.replace(/\n/g, ' ');
		
		//replace tabs
		ret = ret.replace(/\t/g, ' ');
		
		//replace multiple spaces
		ret = ret.replace(/\s+/g, ' ');
		
		//Fix html encoded characters
		ret = decodeHtml(ret);
		
		//Deal with lines breaks and paragraphs
		ret = ret.replace(/<br>/ig, '\n<br>');
		ret = ret.replace(/<br/ig, '\n<br ');
		ret = ret.replace(/<p/ig, '\n<p ');
		
		//Deal with quotes
		ret = ret.replace(/"/ig, '""');
		
		//Deal first character being line break
		ret = ret.replace(/^\n/, '');
		
		//Remove HTML tags
		ret = ret.replace(/(<([^>]+)>)/ig,"");

		return ret;
	}
	function decodeHtml(html) {
		var txt = document.createElement('textarea');
		txt.innerHTML = html;
		return txt.value;
	}
    function downloadCSVFile(filename, mime, text) {
        if (window.navigator.msSaveOrOpenBlob){
            // IE 10+
            var blob = new Blob([decodeURIComponent(encodeURI(text))], {
                type: 'text/csv;charset=utf-8'
            });
            window.navigator.msSaveBlob(blob, filename);
        } else {
            var pom = document.createElement('a');
            pom.setAttribute('href', 'data:' + mime + ';charset=utf-8,' + encodeURIComponent(text));
            pom.setAttribute('download', filename);
            document.body.appendChild(pom);
            pom.click();
            document.body.removeChild(pom);
        }
    }
    if(typeof jQuery == 'undefined') {
        getJavaScript(
            '//code.jquery.com/jquery-latest.min.js',
            function(){
                addCSVLinks();
            }
        )
    } else {
        addCSVLinks();
    }
})();

58 thoughts on “Bookmarklet for Creating a CSV From an HTML Table”

  1. Hello, when I click on the Export to CSV link (after clicking the bookmarklet), the resulting csv file only contains the first column.

    All of my tables have only two columns with the left column acting as a “header” and right column containing data/values.

    I am using Chrome (on Windows), with Confluence 5.8.8.

    Any help would be appreciated. Cheers!

  2. There seems to be a problem with exporting tables that contain merged cells.

    I have a LOT of merged cells in the table I want to export, since it would be very confusing to look at otherwise. But the bookmarklet doesn’t seem to be very friendly with merged cells. I doubt that can be fixed, can it?

    Works just fine for “normal” tables though, so thanks anyways

    1. Hmm … not sure how the best way would be to handle tables with merged cells as those would not translate nicely to csv. I’ll think on it.

  3. Thank you very much. You saved my bacon. I am a non-technical PM and was gnashing my teeth trying to sum up our progress for management until I found your utility.

  4. Hey there,

    great job! Just one thing: could you publish a version with “;” as separator instead of “,”? I found the part in the code but can’t figure out how to change it in the boomarklet 🙁

    Best Regards
    Dmitry

  5. I thrashed for a bit trying to find a solution until I found your bookmarklet. Worked great with Chrome Version 53.0.2785.143 (64-bit) — thank you!

  6. I seem to have encoding issues. My confluence is set to UTF-8 in general settings, and if I understand it correctly, your script is supposed to export UTF-8, but the export clearly has some artifacts, and it does not match what I see on the screen in confluence. Even  s are replaced with  . Is there a way you could help me troubleshoot this?

      1. Similar here; superscripts and math symbols are garbled; still saves a tonne of work but it would be great if there was a function that could be easily enhanced with known search/replace requirements post-export.

        1. The BOM modification referenced further down this comment block fixes the garbled math symbols. Makes no difference for the super/subscript issues; they come through as regular letters on the same baseline as the rest of the content.

  7. Hi. This has been very useful, but for some reason I now cannot “drag and drop” the export to cvs bookmarklet to my favorite bar. I am using IE, but in other browsers I was unable also. This was not a problem previously. Do you have any suggestions for help or where I can find something similar.

  8. This is a great tool, thank you!

    Is there a way for this bookmarklet to include the links that might exist in the tables as well?

  9. Does the input data stay local to the browser ? I’d like to use this, but the data I work with is confidential and cannot be transmitted outside of the corporate network and approved partners. I noticed this hostname in the script, which is why I asked – code.jquery.com

    1. Yes, it stays local. That is simply injecting jQuery into the page to make it easier to work with if jQuery is not already in the page. Nothing is transmitted anywhere.

  10. Thank you so much, very helpful.

    I have many tables on one page, any way to click once and get all tables in different excel worksheets in same excel workbook.

Leave a Reply

Your email address will not be published. Required fields are marked *