写于 2019-12-18 ,不保证后续可用性。
brew install ffmpeg
npm install fs-extra puppeteer uuid
node ./download-iqiyi-videos.js "http://www.iqiyi.com/v_19rrrwga5s.html" "http://www.iqiyi.com/v_19rso4ypgs.html" ...| const fse = require('fs-extra'); | |
| const uuid = require('uuid/v4'); | |
| const {spawnSync} = require('child_process'); | |
| const puppeteer = require('puppeteer'); | |
| // 从视频列表页读取视频URL(在 console 中执行) | |
| function getLinks() { | |
| let links = document.querySelectorAll('.qy-mod-link-wrap > a'); | |
| return Array.from(links).map(link => link.href); | |
| } | |
| copy(getLinks().join('\n')); | |
| async function main(browser) { | |
| let failedURLs = []; | |
| let videoURLs = process.argv.slice(2); | |
| for (let i = 0; i < videoURLs.length; i++) { | |
| try { | |
| let [m3u8, video] = await getVideoURL(videoURLs[i]); | |
| console.log(videoURLs[i], m3u8, video); | |
| let {stdout, stderr} = spawnSync('ffmpeg', [ | |
| '-y', | |
| '-protocol_whitelist', 'file,http,https,tcp,tls', | |
| '-i', `tmp/${m3u8}`, | |
| '-c:v', 'libx264', '-pix_fmt', 'yuv420p', | |
| '-c:a', 'aac', '-ac', '2', '-b:a', '128k', | |
| `tmp/${video}` | |
| ]); | |
| console.log('stdout', stdout.toString('utf8')); | |
| console.log('stderr', stderr.toString('utf8')); | |
| } | |
| catch (err) { | |
| failedURLs.push(videoURLs[i]); | |
| console.log(err); | |
| } | |
| } | |
| console.log(`finish with ${failedURLs.length} error(s).`); | |
| console.log('Failed URLs:'); | |
| console.log(failedURLs.join('\n')); | |
| async function getVideoURL(pageURL) { | |
| const page = await browser.newPage(); | |
| page.setViewport({ | |
| width: 1280, | |
| height: 800 | |
| }); | |
| let promise = new Promise(function (resolve, reject) { | |
| page.on('response', async function (res) { | |
| if (!res.ok()) { | |
| return; | |
| } | |
| let resURL = res.url(); | |
| if (resURL.startsWith('https://cache.video.iqiyi.com/') && resURL.includes('/dash')) { | |
| let data = await res.text(); | |
| // response is JSONP | |
| let i = data.indexOf('({') + 1; | |
| let j = data.lastIndexOf(');'); | |
| content = data.substring(i, j); | |
| try { | |
| data = JSON.parse(content); | |
| data = data.data; | |
| } | |
| catch (err) { | |
| return | |
| } | |
| if (!data || !data.program || !data.program.video) return; | |
| // TODO: find the video with the highest quality | |
| let item = data.program.video.find(item => item.m3u8); | |
| if (!item) { | |
| reject(new Error('No m3u8 found')); | |
| } | |
| resolve(item.m3u8); | |
| } | |
| }); | |
| }); | |
| await page.goto(pageURL); | |
| let title = await page.evaluate(function () { | |
| return document.title; | |
| }); | |
| // TODO: timeout | |
| let m3u8 = await promise; | |
| let m3u8Filename = `${uuid()}.m3u8`; | |
| await fse.writeFile('tmp/' + m3u8Filename, m3u8); | |
| await page.close(); | |
| return [m3u8Filename, `${title}.mp4`]; | |
| } | |
| } | |
| puppeteer.launch({ | |
| headless: false, | |
| slowMo: 100, | |
| userDataDir: './chrome-user-data' | |
| }).then(async browser => { | |
| await main(browser); | |
| await browser.close(); | |
| }).catch(function (err) { | |
| console.log(err); | |
| process.exit(1); | |
| }); |
ดาวโหลดยังไงครับ งงมาก