0

I am writing a scraper in nodejs with Axios which is intended to access a list of urls and then save it to file with fs. However fs writes [object Promise] to the file instead of the intended html response. Here is the code:


var urls = [url1, url2, url3]
var responses = [];
var completed_requests = 0;
for (i in urls) {

    responses.push(axios.get(urls[i]))
    completed_requests ++

    if(completed_requests == urls.length){

    Promise.all(responses).then((e)=>{
        for (i in e) {
            console.log(responses[i]) //this returns the http correctly
            return fs.writeFile('/answer/'+ i +'.txt', responses[i], function(err) {
                if(err) {
                    return console.log(err);
                }})
        }

    }
    )}
}
ChrisY
  • 3
  • 3
  • 1
    Use `e[i]` instead of `responses[i]`. you might also want to remove the if statement (and the completed_requests variable) and just move your Promise.all call to be after the outer loop. – Paul Aug 27 '19 at 04:53
  • `responses[i]` will be the Promises, and you will see the resolved value when logging to console, so while it may look correct, as above `e[i]` is the value you want to write – Jaromanda X Aug 27 '19 at 05:04
  • by the way, the code as written would only write one file, since you have a `return` in your for loop – Jaromanda X Aug 27 '19 at 05:07
  • and ... your whole code is better written `var urls = [url1, url2, url3] Promise.all(urls.map(url => axios.get(url))).then(e => e.forEach(response => fs.writeFile('/answer/'+ i +'.txt', response, err => { if (err) { console.log(err); } })));` – Jaromanda X Aug 27 '19 at 05:09
  • Btw, [don't use `for…in` enumerations on arrays](https://stackoverflow.com/q/500504/1048572), and don't forget to declare your iteration variable (with `var`) – Bergi Aug 27 '19 at 07:56
  • Thank you all - the code works fine now and it was the issue of e[i] and responses[i]. – ChrisY Aug 27 '19 at 09:07

2 Answers2

1

It is writing '[object promise]' because you are writing promise object to the file and also don't return value from for loop if you do so it will run only once . If you want write only html then following code will work.

var urls = [url1,url2,url3]
var responses = [];
var completed_requests = 0;
for (i in urls) {
    responses.push(axios.get(urls[i]))
    completed_requests ++

    if(completed_requests == urls.length){
        console.log('here');

    Promise.all(responses).then((e)=>{

        for (i in e) {
             fs.writeFile( i +'.txt',  e[i].data, function(err) {
                if(err) {

                     console.log(err);
                }})
        }

    }
    )}
}

If you want to write whole object use JSON.stringify(e[i]) .

Aviso
  • 695
  • 4
  • 12
  • There's no point to `Promise.all()` in this. Don't know why it's part of your solution as it does nothing useful the way you're using it. Also, there's no error handling here. The caller has no way of getting an error back. And `for (i in e)` is no way to iterate an array. – jfriend00 Aug 28 '19 at 00:08
0

I think you have first to fill the array so you code is working unexpected just because of a curly brace and because your are saving the Promise object instead the response payload. Please note the comments:

var urls = [url1, url2, url3]
var responses = [];
//var completed requests not needed as a flag here
for (i in urls) {
    responses.push(axios.get(urls[i]))

}

//then after having an array of Promises you should then wait for them
//also you should be saving the `e` variable instead of the responses (array) that is a promise.

Promise.all(responses).then((e)=>{
    for (i in e) {
        console.log(responses[i]) //this returns the http correctly
        return fs.writeFile('/answer/'+ i +'.txt', e, function(err) {
            if(err) {
                return console.log(err);
            }})
    }

}
)}
iwaduarte
  • 1,600
  • 17
  • 23