最近看到知乎上一话题:微信公众号文章里的视频怎么下载?。看还是有很多人推荐啥工具啊,很是捉急,当然本次的主题也是通过程序来获取内容,但是目前来说仅仅是娱乐吧。
其实,如果只是针对一个文章的话是很简单的,直接通过复制文章地址
,在谷歌浏览器
打开后,然后在视频右下角
点击全屏,点击右下角的点点点,点击下载即可。
当然也可以通过F12
来查看video
标签或查看network
数据请求。
这些都是一些基本的操作了,这里不细说了,下边主要是通过puppeteer
来获取视频并下载。
之前通过puppeteer其实已经做过很多事情了,登录啊 签到啊 等等,我也不知道我为啥会继续做,因为总体来说没有什么技术含量的,目前主要是做个铺垫,后续研究下如何抓取所有公众号的所有文章。
/**
* 小爬虫。
* 目标:
* 将微信公众号的视频下载下来,将文章保存PDF。
*
* 问题:如果等待资源文件全部加载完毕后,才打印PDF。
*
* 后续计划:
* 获取某公众号内所有的文章地址,并进行轮询获取所有视频/文章PDF。
* --微信。
*/
const puppeteer = require('puppeteer');
const path = require('path');
const fs = require('fs');
const helper = require('think-helper');//创建目录api
const axios = require('axios');
const folder = __dirname;
let url = `https://mp.weixin.qq.com/s/fwY6FPFCfgdJNTd22qqjKg`;
// let url = `https://mp.weixin.qq.com/s?__biz=MjM5MDAwNTk0MA==&mid=2653094471&idx=1&sn=8f430a2f1764714815ee9f523091b88b`;
function wsf(rs,ws){
return new Promise((r,j)=>{
rs.pipe(ws);
ws.on('close',e=>{
r();
})
});
}
(async function(){
let browser = await puppeteer.launch({
headless : true,
executablePath : 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
});
console.log(`开启新页面:[${url}]`);
const page = await browser.newPage();
let asyncArr = [];
page.on('response',async (res)=>{
try{
let json = await res.json();//
if(json && json.url_info){
console.log(`获取到异步视频数据.`);
asyncArr = asyncArr.concat(json.url_info);
}
}catch(e){}
})
console.log(`等待页面数据请求加载完成。`)
await page.goto(url,{
waitUntil : 'networkidle2'//请求结束
});
//url
let videoArr = await page.evaluate(()=>{
return $('video').get().map(t=>{
return $(t).attr('src');
})
});
//获取公众号信息
let name = await page.evaluate(()=>{
return $('.account_nickname_inner').length > 0 ? $('.account_nickname_inner').text() : $('.rich_media_meta_nickname #js_name').text();
});
let title = await page.evaluate(()=>{
return $('.common_share_title').length > 0 ? $('.common_share_title').text() : $('.rich_media_title').text();
});
name = name.trim();
title = title.trim();
console.log(`获取到公众号信息:[${name}-${title}]`)
//创建目录
let folderPath = path.join(folder,name,title);
helper.mkdir(folderPath);//创建目录
//对视频做处理。
let vr = [];
vr =vr.concat(videoArr.map(t=>{
let u = new URL(t);
let fileName = title+path.extname(u.pathname);
let filePath = path.join(folderPath,fileName);
return {
title : fileName,
filePath : filePath,
url : t
}
}));
vr = vr.concat(asyncArr.map(t=>{
let u = new URL(t.url);
let fileName = t.video_quality_wording +'-'+ title+path.extname(u.pathname);
let filePath = path.join(folderPath,fileName);
return {
title : fileName,
filePath : filePath,
url : t.url
}
}));
console.log(`开始准备下载视频文件`);
for(let video of vr){
console.log(`开始下载视频:[${video.title}]`)
await axios.get(video.url,{
responseType : 'stream'
}).then(async rs=>{
await wsf(rs.data,fs.createWriteStream(video.filePath));
})
}
//将页面滚动到最底部
await page.evaluate(()=>{
$('html').get(0).scrollTop = $('html').get(0).scrollHeight
});
console.log('等待资源加载.....')
// await page.evaluate(function(){
// let timeLimit = 60 * 1000;
// return new Promise((r,j)=>{
// let isLoaded = true;
// let start = +new Date();
// let t = setInterval(function(){
// $('img').get().forEach(t=>{
// var img = $(t).attr('src');
// var pimg = $(t).data('src');
// if(img.indexOf(pimg) > -1){
// isLoaded = isLoaded && true;
// }else{
// isLoaded = isLoaded && false;
// }
// })
// if(isLoaded || (+new Date()) - start > timeLimit){
// clearInterval(t);
// r();
// }
// },500);
// })
// });
//pdf
console.log(`保存文章到PDF`)
await page.pdf({
path : path.join(folder,name,title,title+'.pdf'),
format : 'A4',
printBackground : true
});
console.log(`关闭浏览器`);
await browser.close();
process.exit(0);
})();
总体来说大约用了不到一个小时,包括实现啊调试啊,相对来说没有什么难度。不过也碰到了一个问题,资源懒加载的问题。
目前还没有啥比较好的思路来去确定资源加载完毕的回调,暂时搁置。
准备抽时间把这个小东西做成服务,扔在博客的工具里面,到时候看看情况。
转载请注明出处: https://chrunlee.cn/article/weixin-video-fetch.html