Скачать файл с помощью Nightmare

Я использую Nightmare для создания автоматического загрузчика сегодняшней газеты. Мне удалось войти и перейти на указанную страницу. Однако я не мог узнать, как скачать файл с Nightmare.

var Nightmare = require('nightmare');
new Nightmare()
  .goto('https://login.nrc.nl/login?service=http://digitaleeditie.nrc.nl/welkom')
    .type('input[name="username"]', 'Username')
    .type('input[name="password"]','Password')
    .click('button[type="submit"]')
    .wait()
    .goto('http://digitaleeditie.nrc.nl/digitaleeditie/NH/2014/10/20141124___/downloads.html')
    .wait()
    .click('a[href="/digitaleeditie/helekrant/epub/nrc_20141124.epub"]')
    .wait()

    .url(function(url) {
        console.log(url)
    })
    .run(function (err, nightmare) {
      if (err) return console.log(err);
      console.log('Done!');
    });

Я попытался загрузить файл, нажав на кнопку загрузки. Однако это, кажется, не работает.


person Fokke Dekker    schedule 24.11.2014    source источник


Ответы (4)


PhantomJS (а также CasperJS и Nightmare) не вызывают загрузку (диалоговое окно), когда вы нажимаете на что-то, что должно быть загружено. Итак, необходимо скачать его самостоятельно. Если вы можете узнать URL-адрес файла, то его можно легко загрузить с помощью XMLHttpRequest из контекста страницы.

Так что вам нужно обменять

.click('a[href="/digitaleeditie/helekrant/epub/nrc_20141124.epub"]')

для

.evaluate(function ev(){
    var el = document.querySelector("[href*='nrc_20141124.epub']");
    var xhr = new XMLHttpRequest();
    xhr.open("GET", el.href, false);
    xhr.overrideMimeType("text/plain; charset=x-user-defined");
    xhr.send();
    return xhr.responseText;
}, function cb(data){
    var fs = require("fs");
    fs.writeFileSync("book.epub", data, "binary");
})

Вы также можете использовать более новый способ запроса двоичных данных.

.evaluate(function ev(){
    var el = document.querySelector("[href*='.pdf']");
    var xhr = new XMLHttpRequest();
    xhr.open("GET", el.href, false);
    xhr.responseType = "arraybuffer";
    xhr.send();

    var bytes = [];
    var array = new Uint8Array(xhr.response);
    for (var i = 0; i < array.length; i++) {
        bytes[i] = array[i];
    }
    return bytes;
}, function cb(data){
    var fs = require("fs");
    fs.writeFileSync("book.epub", new Buffer(data), "binary");
})

Оба способа описаны на MDN. Вот пример скрипта, демонстрирующий концепцию.

person Artjom B.    schedule 24.11.2014
comment
Я пытался реализовать это. Однако это только загрузка файла 4k с тем же именем. Он не загружает весь файл. - person Fokke Dekker; 25.11.2014
comment
4k немного произвольно. Каково содержание? Возможно, это страница с ошибкой. - person Artjom B.; 25.11.2014
comment
Это файл epub размером 4k. Если открыть в текстовом редакторе, он содержит только null. - person Fokke Dekker; 25.11.2014
comment
Вы можете попробовать его единственным другим способом и посмотреть, поддерживает ли его страница. Я обновил свой ответ. - person Artjom B.; 25.11.2014
comment
Второй вариант выдает ошибку: stream.js:94 throw er; // Ошибка необработанного потока в канале. ^ TypeError: Невозможно прочитать свойство 'length' null в новом буфере (buffer.js:184:31) в cb (/home/nrclogin.js:32:35) в завернутом (/home/node_modules/nightmare/lib/actions) .js:324:14) в Proto.apply(/home/node_modules/nightmare/node_modules/phantom/node_modules/dnode/node_modules/dnode-protocol/index.js:123:13) Не совсем уверен, что делать - person Fokke Dekker; 29.11.2014
comment
Я тоже пытаюсь загрузить файл, который не находится по URL-адресу, а запускается через javascript. Как я могу скачать такой файл? - person user1749672; 23.11.2015
comment
@user1749672 user1749672 Полагаю, мой ответ вам не помог. Я не знаю, как еще это может работать, но вы пробовали последнюю версию Nightmare? Он работает с Electron, и я думаю, что есть что-то подобное. - person Artjom B.; 23.11.2015
comment
@ArtjomB. Я наткнулся на этот вопрос, ища то же самое, что и OP, проблема не может быть решена с помощью простого HttpXmlRequest, подобного вашему. Мы можем ясно видеть, что кошмар сначала входит в систему, прежде чем пытаться получить файл. Использование базового (или «обнаженного») запроса GET не сможет получить файл... Я думаю, что нужно взять все файлы cookie из кошмара и использовать их правильно. - person Salketer; 04.06.2016
comment
@Salketer Это может быть правдой, но я не знаю ни одного сайта, где я мог бы правильно проверить это (логин + загрузка). Может быть, я решу создать учетную запись на сайте ОП. Кроме того, вы уверены, что это все еще проблема с Nightmare 2, поскольку теперь он использует Electron. - person Artjom B.; 04.06.2016
comment
@ArtjomB. Я не знаю, но я все еще пытаюсь понять это для себя... Может быть, документы слишком скудны. - person Salketer; 04.06.2016

Существует плагин загрузки Nightmare. Вы можете скачать файл только с этим кодом ниже:

var Nightmare = require('nightmare');
require('nightmare-download-manager')(Nightmare);
var nightmare = Nightmare();
nightmare.on('download', function(state, downloadItem){
  if(state == 'started'){
    nightmare.emit('download', '/some/path/file.zip', downloadItem);
  }
});

nightmare
  .downloadManager()
  .goto('https://github.com/segmentio/nightmare')
  .click('a[href="/segmentio/nightmare/archive/master.zip"]')
  .waitDownloadsComplete()
  .then(() => {
    console.log('done');
  });

person Maksim Groshevoi    schedule 20.12.2016

Я получил свои загрузки очень легко, используя модуль request, как описано здесь.

var Nightmare = require('nightmare');
var fs = require('fs');
var request = require('request');

new Nightmare()
  .goto('https://login.nrc.nl/login?service=http://digitaleeditie.nrc.nl/welkom')
  .insert('input[name="username"]', 'Username')
  .insert('input[name="password"]','Password')
  .click('button[type="submit"]')
  .wait()
  .goto('http://digitaleeditie.nrc.nl/digitaleeditie/NH/2014/10/20141124___/downloads.html')
  .wait()
  .then(function () {
    download('http://digitaleeditie.nrc.nl/digitaleeditie/helekrant/epub/nrc_20141124.epub', 'myBook.epub', function () {
      console.log('done');
    });
  })
  .catch(function (err) {
    console.log(err);
  })

function download(uri, filename, callback) {
  request.head(uri, function () {
    request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
  });
}

Запустите npm i request, чтобы использовать request.

person Nelu    schedule 09.09.2016
comment
ошибка в коде - отсутствует ',' между аргументами при вызове загрузки() - person API_sheriff_orlie; 22.01.2018

Nightmare загрузит его правильно, если вы нажмете на ссылку для скачивания.

const Nightmare         = require('nightmare');
const show              = ( process.argv[2].includes("true") ) ? true : false;
const nightmare         = Nightmare( { show: show } );

nightmare
    .goto("https://github.com/segmentio/nightmare")
    .click('a[href="/segmentio/nightmare/archive/master.zip"]')
    .end(() => "Done!")
    .then((value) => console.log(value));
person Pranay Pant    schedule 19.03.2017