IT関連雑記帳

IT関連の話をつらつらと

(Puppeteer)内部ビューアで表示されるファイルをダウンロードする方法

サイトからファイルをダウンロードしたかったのですが、リンクをクリックすると内部ビューアでファイルが表示されてしまうんですよね。PDFとか。

Puppeteerには「右クリック ⇒ 名前を付けて保存」みたいな機能はないので、どうしたものかとGoogle先生に聞きまくったら、以下のサイトを教えてくれました。

officeforest.org

やりたいことそのままだったので、本当に助かりました。ありがとうございます。

仕組みなどは上記のサイトに詳しく書いてあるので、そちらをご参照願います。

万が一ですが、参照先のサイトが無くなってしまうような事があると困るので、例によって私のコードも自分メモとして貼っておきます。コードをほぼ完全にコピーしているのはご容赦ください。

変更したのはファイル名をURLから抜き出し、decodeURI()をしているぐらいですかね。

const fs = require('fs');
const requestP = require('request-promise');

(省略)
const targetFile = await (await (await Page_new.$('a[href$=".pdf"]')).getProperty('href')).jsonValue();
await Page_new.click('a[href$=".pdf"]');

await Page_new.setRequestInterception(true);
Page_new.on('request', async (request) => {
	if (request.url().startsWith(targetFile)){

		options = {
			method: request._method,
			uri: request._url,
			body: request._postData,
			headers: request._headers,
			encoding: "binary"
		}

		let cookies = await Page_main[0].cookies();
		options.headers.Cookie = cookies.map(ck => ck.name + '=' + ck.value).join(';');

		requestP(options).then(function (body){
			let targetFilenameIdx = targetFile.lastIndexOf('/');
			let targetFilename = decodeURI(targetFile.substr(targetFilenameIdx + 1));

			fs.writeFileSync(targetFilename, body, "binary", (err) => {console.log(err)})
		}).catch(err => {
			console.log(err);
		})

		request.abort();

	} else {

		request.continue()

	}
});

await Page_new.reload();

ページをリロードした後にファイルが保存されますが、ブラウザでは以下のように「このサイトにアクセスできません」というメッセージが表示されました。最初、プログラムがちゃんと動いていないのではないかと焦ったのですが、本来ブラウザが受け取るべきデータを横取りしているのでこうなるのは仕方が無いのですよね。

f:id:ta9mi3:20210202000024p:plain