rosshinkley / nightmare-inline-download

36 stars 8 forks source link

Error: ENOENT: no such file or directory on fs.renameSync #18

Open sautin1 opened 5 years ago

sautin1 commented 5 years ago

I am using nightmare-inline-download in my crawler to download a set of images. In my crawler I am doing repeatedly the following actions:

The script fails from time to time (it's always a different image it fails on) with the following error:

Error: ENOENT: no such file or directory, rename '/home/sautin1/Downloads/img.png' -> '/home/sautin1/Documents/crawler/images/image0006.png'
    at Object.fs.renameSync (fs.js:772:18)
    at DownloadItem.eval (eval at <anonymous> (/home/sautin1/Documents/crawler/node_modules/nightmare/lib/runner.js:614:14), <anonymous>:43:22)
    at emitTwo (events.js:125:13)
    at DownloadItem.emit (events.js:213:7)

Both directories /home/sautin1/Documents/crawler/images/ and /home/sautin1/Downloads/ definitely exist. It seems like the download does not finish by the moment fs.renameSync is called, thus /home/sautin1/Downloads/img.png does not exist yet.

TheTechChild commented 5 years ago

@sautin1 I am having that problem as well. In my application I am downloading many csv files from a button, and I am capturing it with the .download() method. But I did find a work around that solved the problem for me, and could help you while a solution is coded in nightmare-inline-download

If you have fs-extra installed (which I suggest you do). It provides a function called ensureDir([filepath]). If you call that function on the filePath that you are trying to download to, then it will resolve this problem, because in essence nightmare is not allowing fs to finish creating the directory before trying to save the downloaded file.

So this is what I did:

//Require in fs-extra
let fs = require('fs-extra');
let path = require('path');
let Nightmare = require('nightmare');
require('nightmare-inline-download')(Nightmare);

//Build the filepath
let filePath = path.join('your', 'chosen', 'filePath', 'file.csv');

//ensure that your filePath exists
await fs.ensureDir(filePath)

//download the file
await nightmare.click('downloadBtn')
.download(filePath)
.catch(err => handleError(err));

That worked for me. But I think that @rosshinkley should also patch this soon.

sautin1 commented 5 years ago

@IAmIndra, thank you for the help! ;)

I followed your advice and it might have worked, since the script hasn't failed with the same error in a few launches after the fix. Unfortunately, I cannot say if the fix is actually a solution to the problem, because originally the script failed at a random point of time. Thus, I cannot reproduce the same situation that caused the error earlier. I'll leave another comment here if the problem occurs one more time.

To be honest, I don't really understand how fs.ensureDir can solve the problem, since I am downloading all the images to the same directory, which definitely exists and does not disappear while the script is working. Could you help me to understand the idea of the fix you proposed, please? :)

One more thing: I suppose you meant await fs.ensureDir(path.dirname(filePath)) instead of await fs.ensureDir(filePath), right? The latter option in your example would create a directory with the name ending with .csv and cause an error during the download.