Когда речь заходит о парсинге всех интересующих страниц сайта, я прибегаю к помощи своего скрипта. На мой взгляд, это наиболее быстрый и простой способ. Учитывая размеры скрипта, можно не бояться его потярять и в последствии восстановить по памяти (уже несколько раз писал).
Логика скрипта будет проста как туфелька:
- Поднять http-сервер
- На входящий запрос
- проверить, есть ли сохраненные данные по данному URL
- если есть, то отдать их в браузер
- если нет, то сделать запрос на целевой ресурс, заменить все упоминания целевого ресурса, сохранить данные в файл и отдать данные в браузер
Таким образом, мы можем авторизовываться на сайте, ходить по сайту, по разным страницам, и вся статика будет сохраняться.
Требования:
- Nodejs (теоретически, любой версии, используется core функционал)
- свободное дисковое пространство (для сохранения всех медиа файлов)
Пишем скрипт:
Данный скрипт был создан для решения моей цели - быстро скачать всю статику. Другие решения, которые встречались, имели ряд проблем, которые меня не устраивали.
Данный скрипт может содержать разные неточности и не во всех случаях будет отрабатывать корректно (в частности, из-за заголовков)
Логика скрипта будет проста как туфелька:
- Поднять http-сервер
- На входящий запрос
- проверить, есть ли сохраненные данные по данному URL
- если есть, то отдать их в браузер
- если нет, то сделать запрос на целевой ресурс, заменить все упоминания целевого ресурса, сохранить данные в файл и отдать данные в браузер
Таким образом, мы можем авторизовываться на сайте, ходить по сайту, по разным страницам, и вся статика будет сохраняться.
Требования:
- Nodejs (теоретически, любой версии, используется core функционал)
- свободное дисковое пространство (для сохранения всех медиа файлов)
Пишем скрипт:
JavaScript:
const { request: request1 } = require('https');
const { request: request2, createServer } = require('http');
const { normalize } = require('path');
const { writeFile, readFile, existsSync, mkdir } = require('fs');
const targetHost = 'https://a.b'; // целевой ресурс
const saveDir = '/tmp/files'; // путь к директории, куда сохранять файлы
const port = 3000; // порт сервера, на котором поднимаем парсер
const ownHost = ''; // в большинстве случаев оставляем пустым
const always = false; // save existing files on every request
// маппинг расширений файлов и заголовков. Решает проблему браузера, когда "получил javascript , а тип контента text/html"
const ext2type = {
'html': 'text/html',
'css': 'text/css',
};
// игнорирование некорректных ssl сертификатов
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
////////////////////////////////////////////////////////////////////////////////
const request = targetHost[4] === 's' ? request1 : request2;
const server = createServer((req, res) => {
const path = req.url.split('?')[0];
const pathSegments = path.split('/');
let file = path;
let fpath = path;
const pathSegmentsLast = pathSegments[pathSegments.length - 1];
if (pathSegmentsLast.length === 0) {
file += 'index.html';
} else {
const lfext = pathSegmentsLast.split('.');
if (lfext.length === 1) {
file += '.html';
}
fpath = [...pathSegments];
fpath.pop();
fpath = fpath.join('/');
}
if (!always && existsSync(saveDir + file)) {
let ext = file.split('.');
ext = ext[ext.length-1];
if (ext2type.hasOwnProperty(ext)) {
res.setHeader('content-type', ext2type[ext]);
}
return readFile(saveDir + file, (err, data) => {
if (err) {
console.log('error readFile `%s`: ', file, err);
res.end();
return;
}
res.end(data);
});
}
req.headers.host = targetHost.replace(/^https?:\/\//, ownHost);
delete req.headers['accept-encoding'];
console.log(' => ', req.method, targetHost + req.url);
console.log(' => ', req.headers);
//console.log(' => ', path, fpath, file);
const r = request(targetHost + req.url, {
method: req.method,
headers: req.headers
}, (resp) => {
console.log(' <= ', resp.statusCode, resp.headers);
Object.keys(resp.headers).forEach((header) => res.setHeader(header, resp.headers[header]));
let data = Buffer.alloc(0);
resp.on('data', (dat) => {
data = Buffer.concat([data, dat], data.length + dat.length);
res.write(dat);
});
resp.on('end', () => {
res.end();
console.log(' <= END event ');
mkdir(saveDir + fpath, { recursive: true }, (err) => {
if (err) {
console.log('err creating dirs %s:', fpath, err);
res.end(data);
} else {
writeFile(saveDir + file, data, (err) => {
if (err) {
console.log('err with file %s:', req.url, err);
}
});
}
});
});
});
req.on('data', (data) => r.write(data));
req.on('end', () => r.end());
});
server.listen(port);
Данный скрипт был создан для решения моей цели - быстро скачать всю статику. Другие решения, которые встречались, имели ряд проблем, которые меня не устраивали.
Данный скрипт может содержать разные неточности и не во всех случаях будет отрабатывать корректно (в частности, из-за заголовков)
Последнее редактирование модератором: