Как загрузить файл с кукловодом с помощью безголового: true?
У меня был следующий код для загрузки файла csv
с веб-сайта http://niftyindices.com/resources/holiday-calendar
:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
await page.goto('http://niftyindices.com/resources/holiday-calendar');
await page._client.send('Page.setDownloadBehavior', {behavior: 'allow',
downloadPath: '/tmp'})
await page.click('#exportholidaycalender');
await page.waitFor(5000);
await browser.close();
})();
с headless: false
он работает, он загружает файл в /Users/user/Downloads
. с headless: true
он НЕ работает.
Я запускаю это на macOS Sierra (MacBook Pro), используя версию кукольника 1.1.1
, которая вытаскивает версию Chromium 66.0.3347.0
в каталог .local-chromium/
и использует npm init
и npm i --save puppeteer
для ее настройки.
Любая идея, что не так?
Заранее благодарим за ваше время и помощь,
Ответы
Ответ 1
Эта страница загружает csv, создавая строку с разделителями-запятыми и заставляя браузер загружать ее, задав таким образом тип данных
let uri = "data:text/csv;charset=utf-8," + encodeURIComponent(content);
window.open(uri, "Some CSV");
Это на chrome открывает новую вкладку.
Вы можете использовать это событие и физически загружать содержимое в файл. Не уверен, что это лучший способ, но хорошо работает.
const browser = await puppeteer.launch({
headless: true
});
browser.on('targetcreated', async (target) => {
let s = target.url();
//the test opens an about:blank to start - ignore this
if (s == 'about:blank') {
return;
}
//unencode the characters after removing the content type
s = s.replace("data:text/csv;charset=utf-8,", "");
//clean up string by unencoding the %xx
...
fs.writeFile("/tmp/download.csv", s, function(err) {
if(err) {
console.log(err);
return;
}
console.log("The file was saved!");
});
});
const page = await browser.newPage();
.. open link ...
.. click on download link ..
Ответ 2
Проблема в том, что браузер закрывается до окончания загрузки.
Вы можете получить размер файла и имя файла из ответа, а затем использовать сценарий наблюдения, чтобы проверить размер файла из загруженного файла, чтобы закрыть браузер.
Это пример:
const filename = <set this with some regex in response>;
const dir = <watch folder or file>;
// Download and wait for download
await Promise.all([
page.click('#DownloadFile'),
// Event on all responses
page.on('response', response => {
// If response has a file on it
if (response._headers['content-disposition'] === 'attachment;filename=${filename}') {
// Get the size
console.log('Size del header: ', response._headers['content-length']);
// Watch event on download folder or file
fs.watchFile(dir, function (curr, prev) {
// If current size eq to size from response then close
if (parseInt(curr.size) === parseInt(response._headers['content-length'])) {
browser.close();
this.close();
}
});
}
})
]);
Даже то, что способ поиска в ответ может быть улучшен, хотя я надеюсь, что вы найдете это полезным.
Ответ 3
Вчера я потратил часы на просмотр этой темы и, пытаясь выяснить, как заставить Puppeteer загрузить CSV файл, щелкнув ссылку для загрузки в режиме без заголовка во время аутентифицированного сеанса. Принятый ответ здесь не сработал в моем случае, потому что загрузка не инициировала targetcreated
, а следующий ответ по какой-либо причине не сохранил аутентифицированный сеанс. Эта статья спасла день. Короче, fetch
. Надеюсь, это поможет кому-то еще.
const res = await this.page.evaluate(() =>
{
return fetch('https://example.com/path/to/file.csv', {
method: 'GET',
credentials: 'include'
}).then(r => r.text());
});
Ответ 4
Мне нужно было скачать файл из-за входа, который обрабатывал Puppeteer. targetcreated
не запускается. В конце я загрузил с помощью request
, после копирования файлов cookie из экземпляра Puppeteer.
В этом случае я передаю файл, но вы можете просто сохранить его.
res.writeHead(200, {
"Content-Type": 'application/octet-stream',
"Content-Disposition": `attachment; filename=secretfile.jpg`
});
let cookies = await page.cookies();
let jar = request.jar();
for (let cookie of cookies) {
jar.setCookie(`${cookie.name}=${cookie.value}`, "http://secretsite.com");
}
try {
var response = await request({ url: "http://secretsite.com/secretfile.jpg", jar }).pipe(res);
} catch(err) {
console.trace(err);
return res.send({ status: "error", message: err });
}
Ответ 5
У меня есть другое решение этой проблемы, так как ни один из ответов здесь не работал для меня.
Мне нужно было зайти на сайт и загрузить некоторые отчеты .csv. С головой было хорошо, без головы не получалось, что бы я ни пытался. Глядя на сетевые ошибки, загрузка прерывается, но я не могу (быстро) определить причину.
Итак, я перехватил запросы и использовал node-fetch, чтобы сделать запрос за пределами кукловода. Это потребовало копирования параметров выборки, тела, заголовков и добавления в файл cookie доступа.
Удачи.