2

So I copied the steps from this question and converted it to node.js

...
app.use('/', async (request, response) => {
    const fetchedSite = await fetch('https://public.tableau.com/views/COVID-19CasesandDeathsinthePhilippines_15866705872710/Home?%3Aembed=y&%3AshowVizHome=no&%3Adisplay_count=y&%3Adisplay_static_image=y&%3AbootstrapWhenNotified=true&%3Alanguage=en&:embed=y&:showVizHome=n&:apiID=host0#navType=0&navSrc=Parse')
    const siteText = await fetchedSite.text()
    const $ = cheerio.load(siteText)
    const tsConfigJson = JSON.parse($('#tsConfigContainer').text())

    const body = {
        sheet_id: tsConfigJson.sheetId
    }

    const getTableauData = await fetch(`https://public.tableau.com${tsConfigJson.vizql_root}/bootstrapSession/sessions/${tsConfigJson.sessionid}`, {
        method: 'POST',
        body: JSON.stringify(body)
    })

    return response.status(200).send(getTableauData)
...

The only response I get it is this

{"size":0,"timeout":0}

status: 500

statusText: Internal Server Error

Am I missing something here?

frost kazuma
  • 350
  • 1
  • 8
  • 24

1 Answers1

1

The issue was that you've attempted to send json whereas it needs to be form data :

const body = new URLSearchParams();
body.append('sheet_id', tsConfigJson.sheetId);

const tableauData = await fetch(`https://public.tableau.com${tsConfigJson.vizql_root}/bootstrapSession/sessions/${tsConfigJson.sessionid}`, {
    method: 'POST',
    body: body
})

The full code getting the data :

const fetch = require('node-fetch');
const cheerio = require('cheerio');

const url = 'https://public.tableau.com/views/COVID-19CasesandDeathsinthePhilippines_15866705872710/Home?';
const params = new URLSearchParams({ 
    ":embed": "y",
    ":showVizHome": "no",
    ":display_count": "y",
    ":display_static_image": "y",
    ":bootstrapWhenNotified": true,
    ":language": "en",
    ":embed": "y",
    ":showVizHome": "n",
    ":apiID": "host0" 
});

(async () => {
    const site = await fetch(url + params);
    var text = await site.text();
    const $ = cheerio.load(text);
    const tsConfigJson = JSON.parse($('#tsConfigContainer').text());

    const body = new URLSearchParams();
    body.append('sheet_id', tsConfigJson.sheetId);

    const tableauData = await fetch(`https://public.tableau.com${tsConfigJson.vizql_root}/bootstrapSession/sessions/${tsConfigJson.sessionid}`, {
        method: 'POST',
        body: body
    })
    text = await tableauData.text();
    var jsonRegex = /\d+;({.*})\d+;({.*})/g;
    var match = jsonRegex.exec(text);
    const info = JSON.parse(match[1]);
    const data = JSON.parse(match[2]);
    console.log(data.secondaryInfo.presModelMap.dataDictionary.presModelHolder.genDataDictionaryPresModel.dataSegments["0"].dataColumns)
})();

Try this on repl.it

Bertrand Martel
  • 42,756
  • 16
  • 135
  • 159
  • Will try this out, Thanks! – frost kazuma Oct 05 '20 at 08:11
  • @bertrandmartel - trying to do this with regular Tableau server (not Tableau public) using trusted authentication and the call to site.text() does not return content that can be parsed to get the tsConfigContainer and fails when trying to get it. Would you have an example of this that works with regular Tableau server? – vmachan Mar 14 '22 at 03:31