initial commit
This commit is contained in:
commit
fe9d1ee619
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*~
|
||||
.DS_Store
|
||||
*.swp
|
||||
node_modules
|
50
README.md
Normal file
50
README.md
Normal file
@ -0,0 +1,50 @@
|
||||
# NZZ Downloader
|
||||
The [NZZ](https://en.wikipedia.org/wiki/Neue_Z%C3%BCrcher_Zeitung) is the Swiss
|
||||
Swiss newspaper of record. Its first issue was all the way back in 1780. It's
|
||||
even better that you can download every single issue ever released (if
|
||||
you have a subscription of course).
|
||||
|
||||
This little tool helps you with downloading all released issues in a specified
|
||||
time span.
|
||||
|
||||
It was written because the archive website is not very friendly in the author's
|
||||
opinion and of course because it is not possible to download everything in a time
|
||||
span.
|
||||
|
||||
Because the archive website makes heavy use of javascript this is done with
|
||||
[selenium](https://www.selenium.dev/) to remote control a browser (firefox in
|
||||
this case). This is also why it is not all that fast but that is ok.
|
||||
|
||||
Please only use this with your own credentials, the journalists deserve to be
|
||||
paid for their work.
|
||||
|
||||
## Installation
|
||||
You need to be comfortable with the command line to use the nzz downloader and
|
||||
it has only been tested on linux systems though it should work fine on Windows
|
||||
or macOS.
|
||||
|
||||
- [NodeJS](https://nodejs.org/en/download/) (the LTS version is fine)
|
||||
- [Firefox](https://www.mozilla.org/en-US/firefox/download/thanks/)
|
||||
- [geckodriver](https://github.com/mozilla/geckodriver/releases)
|
||||
- [nzz.js]()
|
||||
|
||||
## Usage
|
||||
```
|
||||
Usage: nzz.js -f [date] -t [date] -o [path] -u [usernane] -p [password]
|
||||
|
||||
Options:
|
||||
--version Show version number [boolean]
|
||||
-h, --help Show help [boolean]
|
||||
-f, --from Earliest issue to download. [default: "2020-12-23"]
|
||||
-t, --to Latest issue to download. [default: "2020-12-23"]
|
||||
-o, --out Download directory. [default: "./nzz"]
|
||||
-u, --user Username for the nzz archive. [required]
|
||||
-p, --password Password for the user. [required]
|
||||
```
|
||||
|
||||
### Examples
|
||||
Download all existing issues from 01-01-1780 until 30-02-1780 to the default
|
||||
directory "./nzz"
|
||||
```
|
||||
./nzz.js -u 'myuser@example.com' -p 'mypassword' -f 1780-01-01 -t 1780-02-30
|
||||
```
|
256
nzz.js
Executable file
256
nzz.js
Executable file
@ -0,0 +1,256 @@
|
||||
#!/usr/bin/env node
|
||||
/* Copyright (c) Sebastian Hugentobler <sebastian@vanwa.ch> 2020.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const tmp = require('tmp');
|
||||
var path = require('path');
|
||||
const fs = require('fs');
|
||||
const { Builder, By, Key, until } = require('selenium-webdriver');
|
||||
const fx = require('selenium-webdriver/firefox');
|
||||
const yargs = require('yargs/yargs')
|
||||
const { hideBin } = require('yargs/helpers');
|
||||
|
||||
const URL = 'https://zeitungsarchiv.nzz.ch/';
|
||||
const RETRY_DELAY = 2000;
|
||||
const WAIT_TIMEOUT = 2000;
|
||||
const TIMEOUT_MSG = `Timeout after ${WAIT_TIMEOUT / 1000} seconds.`;
|
||||
const SEARCH_WAIT_TIMEOUT = 5000;
|
||||
const SEARCH_TIMEOUT_MSG = `Timeout after ${SEARCH_WAIT_TIMEOUT / 1000} seconds.`;
|
||||
|
||||
Date.prototype.isoDate = function () {
|
||||
return `${this.getFullYear()}-${String(this.getMonth() + 1).padStart(2, '0')}-${String(this.getDate()).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
Date.prototype.nzzDate = function () {
|
||||
return `${String(this.getDate()).padStart(2, '0')}.${String(this.getMonth() + 1).padStart(2, '0')}.${this.getFullYear()}`;
|
||||
}
|
||||
|
||||
Date.prototype.addDays = function (days) {
|
||||
let date = new Date(this.valueOf());
|
||||
date.setDate(date.getDate() + days);
|
||||
return date;
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for an in progress download to finish and move the file to the correct
|
||||
* destination.
|
||||
*
|
||||
* @param {fs.PathLike} tmpDir Download directory.
|
||||
* @param {fs.PathLike} outDir Final destination directory.
|
||||
* @param {Date} date Date of the issue.
|
||||
*/
|
||||
async function moveDownload(tmpDir, outDir, date) {
|
||||
return new Promise(resolve => {
|
||||
let needsOffset = false;
|
||||
|
||||
// Dates in filenames are off by one before 1894
|
||||
if (date.getFullYear() < 1894) {
|
||||
date = date.addDays(-1);
|
||||
needsOffset = true;
|
||||
}
|
||||
|
||||
let srcFile = path.join(tmpDir, `Gesamtausgabe_NZZ_-_Neue_Zürcher_Zeitung_${date.isoDate()}.pdf`);
|
||||
|
||||
|
||||
fs.watchFile(srcFile, () => {
|
||||
if (fs.existsSync(srcFile)) {
|
||||
fs.unwatchFile(srcFile);
|
||||
if (needsOffset) {
|
||||
date = date.addDays(1);
|
||||
}
|
||||
|
||||
let destFile = path.join(outDir, `${date.isoDate()}.pdf`);
|
||||
fs.copyFileSync(srcFile, destFile);
|
||||
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter the dates of the issue to download.
|
||||
*
|
||||
* @param {WebDriver} driver Selenium driver to use.
|
||||
* @param {Date} date Date of the issue.
|
||||
*/
|
||||
async function enterDate(driver, date) {
|
||||
console.log(driver);
|
||||
let dateString = date.nzzDate();
|
||||
|
||||
let startDate = await driver.wait(until.elementLocated(By.css('.fup-s-date-start')), WAIT_TIMEOUT, TIMEOUT_MSG, RETRY_DELAY);
|
||||
await startDate.clear();
|
||||
await startDate.sendKeys(dateString);
|
||||
|
||||
let endDate = await driver.wait(until.elementLocated(By.css('.fup-s-date-end')), WAIT_TIMEOUT, TIMEOUT_MSG, RETRY_DELAY);
|
||||
await endDate.clear();
|
||||
await endDate.sendKeys(dateString + Key.ENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Login to the NZZ archive.
|
||||
*
|
||||
* @param {WebDriver} driver Selenium driver to use.
|
||||
* @param {String} user Username for the login.
|
||||
* @param {String} password Password for the user.
|
||||
*/
|
||||
async function login(driver, user, password) {
|
||||
console.log('logging in...');
|
||||
|
||||
await driver.get(URL);
|
||||
await sleep(500);
|
||||
|
||||
let loginButton = await driver.findElement(By.css('.fup-menu-login-container'));
|
||||
await driver.wait(until.elementIsVisible(loginButton), WAIT_TIMEOUT);
|
||||
await sleep(1000);
|
||||
await loginButton.click();
|
||||
|
||||
let emailField = await driver.wait(until.elementLocated(By.id('c1-login-field')), WAIT_TIMEOUT, TIMEOUT_MSG, RETRY_DELAY);
|
||||
await emailField.sendKeys(user + Key.ENTER);
|
||||
|
||||
let pwField = await driver.wait(until.elementLocated(By.id('c1-password-field')), WAIT_TIMEOUT, TIMEOUT_MSG, RETRY_DELAY);
|
||||
await pwField.sendKeys(password + Key.ENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the downloa of a full issue.
|
||||
*
|
||||
* @param {WebDriver} driver Selenium driver to use.
|
||||
*/
|
||||
async function download(driver) {
|
||||
let menu = await driver.wait(until.elementLocated(By.css('.fup-menu-item-download')), WAIT_TIMEOUT, TIMEOUT_MSG, RETRY_DELAY);
|
||||
await menu.click();
|
||||
|
||||
let download = await driver.wait(until.elementLocated(By.css('.fup-s-menu-download-edition')), WAIT_TIMEOUT, TIMEOUT_MSG, RETRY_DELAY);
|
||||
await download.click();
|
||||
|
||||
let back = await driver.wait(until.elementLocated(By.css('.fup-s-menu-back')), WAIT_TIMEOUT, TIMEOUT_MSG, RETRY_DELAY);
|
||||
await driver.wait(until.elementIsVisible(back), WAIT_TIMEOUT);
|
||||
await sleep(500)
|
||||
}
|
||||
|
||||
/**
|
||||
* Download all issues in a certain time span.
|
||||
*
|
||||
* @param {WebDriver} driver Selenium driver to use.
|
||||
* @param {Date} from Earliest issue to download.
|
||||
* @param {Date} to Latest issue to download.
|
||||
* @param {fs.PathLike} tmpDir Download directory.
|
||||
* @param {fs.PathLike} outDir Final destination directory.
|
||||
*/
|
||||
async function findIssues(driver, from, to, tmpDir, outDir) {
|
||||
from = from.addDays(-1);
|
||||
|
||||
while (from.toDateString() !== to.toDateString()) {
|
||||
from = from.addDays(1);
|
||||
await enterDate(driver, from);
|
||||
|
||||
try {
|
||||
let articles = await driver.wait(until.elementsLocated(By.css('.fup-archive-result-item-article-title')), SEARCH_WAIT_TIMEOUT, SEARCH_TIMEOUT_MSG, RETRY_DELAY);
|
||||
await articles[0].click();
|
||||
|
||||
await download(driver);
|
||||
console.log(`downloading ${from.isoDate()}...`);
|
||||
|
||||
// do this in the background
|
||||
moveDownload(tmpDir, outDir, from);
|
||||
|
||||
await driver.get(URL);
|
||||
} catch {
|
||||
// this means there is no issue on the searched date
|
||||
// move along with the next date
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the headless browser and download all issues in the specified time span.
|
||||
*
|
||||
* @param {Date} from Earliest issue to download.
|
||||
* @param {Date} to Latest issue to download.
|
||||
* @param {String} user Username for the nzz archive.
|
||||
* @param {String} password Password for the user.
|
||||
* @param {fs.PathLike} outDir Final destination directory.
|
||||
*/
|
||||
async function run(from, to, user, password, outDir) {
|
||||
if (!fs.existsSync(outDir)) {
|
||||
fs.mkdirSync(outDir);
|
||||
}
|
||||
|
||||
let tmpDir = tmp.dirSync();
|
||||
console.log(`downloading to ${outDir} (tmp dir: ${tmpDir.name})...`);
|
||||
|
||||
let fxOptions = new fx.Options()
|
||||
.addArguments('-headless')
|
||||
.setPreference('pdfjs.disabled', true)
|
||||
.setPreference('browser.helperApps.neverAsk.openFile', 'application/pdf')
|
||||
.setPreference('browser.download.folderList', 2)
|
||||
.setPreference('browser.download.manager.showWhenStartingout', false)
|
||||
.setPreference('browser.download.dir', tmpDir.name)
|
||||
.setPreference('browser.helperApps.neverAsk.saveToDisk', 'application/pdf');
|
||||
|
||||
let driver = await new Builder()
|
||||
.forBrowser('firefox')
|
||||
.setFirefoxOptions(fxOptions)
|
||||
.build();
|
||||
|
||||
try {
|
||||
await login(driver, user, password);
|
||||
await findIssues(driver, from, to, tmpDir.name, outDir);
|
||||
await sleep(1000);
|
||||
}
|
||||
finally {
|
||||
driver.quit();
|
||||
fs.rmdirSync(tmpDir.name, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse arguments and start the downloading off the issues.
|
||||
*/
|
||||
(async function init() {
|
||||
let now = new Date();
|
||||
let nowString = now.isoDate();
|
||||
|
||||
const argv = yargs(hideBin(process.argv))
|
||||
.usage('Usage: $0 -f [date] -t [date] -o [path] -u [usernane] -p [password]')
|
||||
.demandOption(['u', 'p'])
|
||||
.help('h')
|
||||
.describe('f', 'Earliest issue to download.')
|
||||
.describe('t', 'Latest issue to download.')
|
||||
.describe('o', 'Download directory.')
|
||||
.describe('u', 'Username for the nzz archive.')
|
||||
.describe('p', 'Password for the user.')
|
||||
.alias('h', 'help')
|
||||
.alias('f', 'from')
|
||||
.alias('t', 'to')
|
||||
.alias('o', 'out')
|
||||
.alias('u', 'user')
|
||||
.alias('p', 'password')
|
||||
.default('f', nowString)
|
||||
.default('t', nowString)
|
||||
.default('o', './nzz')
|
||||
.epilog('Copyright (c) Sebastian Hugentobler <sebastian@vanwa.ch> 2020')
|
||||
.example("$0 -u 'myuser@example.com' -p 'mypassword' -f 1780-01-01 -t 1780-02-30", 'Download all existing issues from 01-01-1780 until 30-02-1780 to the default directory "./nzz"')
|
||||
.argv;
|
||||
|
||||
let from = new Date(argv.from);
|
||||
let to = new Date(argv.to);
|
||||
|
||||
if (from > to) {
|
||||
console.error('"from" date must be before "to" date');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
run(from, to, argv.user, argv.password, argv.out)
|
||||
})();
|
331
package-lock.json
generated
Normal file
331
package-lock.json
generated
Normal file
@ -0,0 +1,331 @@
|
||||
{
|
||||
"name": "nzz-downloader",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"requires": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"immediate": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"jszip": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.5.0.tgz",
|
||||
"integrity": "sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==",
|
||||
"requires": {
|
||||
"lie": "~3.3.0",
|
||||
"pako": "~1.0.2",
|
||||
"readable-stream": "~2.3.6",
|
||||
"set-immediate-shim": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"lie": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||
"requires": {
|
||||
"immediate": "~3.0.5"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"pako": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"selenium-webdriver": {
|
||||
"version": "4.0.0-alpha.8",
|
||||
"resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.8.tgz",
|
||||
"integrity": "sha512-yPSaiWySZTEbxuuWQMDqdXh3H3N4Aiw/bSUjpkKMPWWCysfPqUncrq6FewBqdxWD1wQKzy5yWaQMGsgTY/0rCQ==",
|
||||
"requires": {
|
||||
"jszip": "^3.5.0",
|
||||
"rimraf": "^2.7.1",
|
||||
"tmp": "^0.1.0",
|
||||
"ws": "^7.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"tmp": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.1.0.tgz",
|
||||
"integrity": "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==",
|
||||
"requires": {
|
||||
"rimraf": "^2.6.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"set-immediate-shim": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
|
||||
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"tmp": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
|
||||
"integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
|
||||
"requires": {
|
||||
"rimraf": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"rimraf": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"requires": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.4.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz",
|
||||
"integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ=="
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz",
|
||||
"integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"requires": {
|
||||
"cliui": "^7.0.2",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.0",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^20.2.2"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "20.2.4",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
|
||||
"integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA=="
|
||||
}
|
||||
}
|
||||
}
|
13
package.json
Normal file
13
package.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "nzz-downloader",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"main": "nzz.js",
|
||||
"author": "Sebastian Hugentobler",
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"selenium-webdriver": "^4.0.0-alpha.8",
|
||||
"tmp": "^0.2.1",
|
||||
"yargs": "^16.2.0"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user