Получить - Скачать файл Excel не работает. Размер файла 1 кб - PullRequest
0 голосов
/ 08 апреля 2020

Я пытаюсь скачать файл, он не работает после загрузки. Я получаю файлы, но их размер составляет 1 КБ, что не соответствует их размеру.

Если я использовал fetchResp.text (), я не могу открыть имя файла.

Вот полный код.

Я думаю, что проблема может быть здесь: return await fetchResp.text ();

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

Как обращаться с файлами cookie кукловода и извлекать их?

Что если я добавлю функцию извлечения за пределы page.evaluation. Работает ли {credentials: "include"}?

Заранее благодарим за помощь.

const puppeteer = require("puppeteer");
const cheerio = require("cheerio");
const fs = require("fs");

(async () => {
  const browser = await puppeteer.launch({
    args: ["--no-sandbox"],
    headless: false,
    slowMo: 30,
  });
  const page = await browser.newPage();

  await page.goto(
    "https://file-examples.com/index.php/sample-documents-download/sample-xls-download/"
  );
  const content = await page.content();
  const $ = cheerio.load(content);

  const listings = $("#table-files > tbody > tr:has(a)")
    .map((index, element) => {
      const URL = $(element).find("a").attr("href");

      const Filename = $(element).find("a").attr("href").split("/").pop();
      //.replace(/^.*[\\\/]/g, "");

      const name = $(element)
        .find("td:nth-child(1)")
        .text()
        .trim()
        .replace("\n", "");

      return {
        Filename,
        URL,
      };
    })
    .get();

  for (let val of listings) {
    const downloadUrl = val.URL;
    const Filename = val.Filename;
    console.log(val);

    const downloadedContent = await page.evaluate(async (downloadUrl) => {
      const fetchResp = await fetch(downloadUrl, { credentials: "include" });
      return await fetchResp.text();
    }, downloadUrl);

    fs.writeFile(`./${Filename}`, downloadedContent, () =>
      console.log("Wrote file")
    );
  }

  await page.close();
  await browser.close();
})();

1 Ответ

0 голосов
/ 12 апреля 2020

Основная проблема здесь в том, что вы получаете содержимое файла в виде простого текста, что было бы неплохо, если бы вы хотели простой текстовый файл, но вам нужно написать файл Excel, поэтому вам понадобится blob или arrayBuffer, оба из которых не может быть возвращено методом page.evaluate. См. https://github.com/puppeteer/puppeteer/issues/3722

Таким образом, вам не нужно извлекать файлы Excel с помощью функции page.evaluate от puppeteer, вы можете получить их напрямую с узла с помощью модуля https после получения все ссылки, а затем передавать содержимое в файлы, что проще в этом случае, а также меньше кода. Вам понадобятся эти модификации

Сначала потребуется модуль https

const https = require('https');

Затем закройте кукловода после получения ссылок, поскольку он нам больше не нужен

.get();
await page.close();
await browser.close();

Вызовите функцию здесь, при циклическом пересылке по ссылкам

for (let val of listings) {
 const downloadUrl = val.URL;
 const Filename = val.Filename;
 console.log(val);
 var file = await getFile(downloadUrl, Filename);
}

Наконец, вам нужно создать функцию для чтения / записи файла вне вашего основного блока кода

function getFile(downloadUrl, Filename) {
    var data = '';
    var writeStream = fs.createWriteStream(Filename);
    var req = https.get(downloadUrl, function(res) {
        res.pipe(writeStream);
        res.on('end', () => {
            console.log('No more data in response.');
        });
    });
    req.end();
}

Полный фрагмент

const puppeteer = require('puppeteer');
const cheerio = require("cheerio");
const fs = require("fs");
const https = require('https');

(async () => {
	const browser = await puppeteer.launch({
		args: ["--no-sandbox"],
		headless: false,
		slowMo: 30,
	});
	const page = await browser.newPage();

	await page.goto(
		"https://file-examples.com/index.php/sample-documents-download/sample-xls-download/"
	);
	const content = await page.content();
	const $ = cheerio.load(content);

	const listings = $("#table-files > tbody > tr:has(a)")
		.map((index, element) => {
			const URL = $(element).find("a").attr("href");

			const Filename = $(element).find("a").attr("href").split("/").pop();
			//.replace(/^.*[\\\/]/g, "");

			const name = $(element)
				.find("td:nth-child(1)")
				.text()
				.trim()
				.replace("\n", "");

			return {
				Filename,
				URL,
			};
		})
		.get();
	await page.close();
	await browser.close();

	for (let val of listings) {
		const downloadUrl = val.URL;
		const Filename = val.Filename;
		console.log(val);
    //call the function with each link and filename
		var file = await getFile(downloadUrl, Filename);
	}

})();
//send request and stream the response to a file
function getFile(downloadUrl, Filename) {
	var writeStream = fs.createWriteStream(Filename);
	var req = https.get(downloadUrl, function(res) {
		res.pipe(writeStream);
		res.on('end', () => {
			console.log('No more data in response.');
		});
	});
	req.end();
}

РЕДАКТИРОВАТЬ Увидев свой комментарий, вы можете отправлять куки, изменив запрос на получение, подобный этому, но помните о той же политике домена для куки

function getFile(downloadUrl, Filename) {
 var url = new URL(downloadUrl)
 var options = {
  hostname: url.hostname,
  path: url.pathname,
  method: 'GET',
  headers: {
   'Cookie': 'myCookie=myvalue'
  }
 };
 var writeStream = fs.createWriteStream(Filename);
 var req = https.request(options, function(res) {
  res.pipe(writeStream);
  res.on('end', () => {
   console.log('No more data in response.');
  });
 });
 req.end();
}
...