需求分析
別人分享了很多網盤鏈接,自己每個手動去轉存很浪費時間,而且,這些操作都是重復性勞動,與Pandownload的這個功能類似,不過pandownload由于一些原因無法使用了,所以只能自己實作,
思路
思路其實很簡單,就是完全模擬人為操作,將網盤鏈接存起來,我們可以把網盤鏈接分為兩種,第一種是沒有提取碼的,第二種是有提取碼的,前者比后者少一個提交提取碼的步驟,那么,我們
如何區分,訪問一個網盤鏈接的時候,究竟是哪種呢?
可以通過訪問頁面的title來決定,

這種是無提取碼的,后綴是無限制

這種是需要填寫提取碼的,后綴是請輸入提取碼,寫代碼的時候,截取后三個字兒提取碼即可
填寫Cookie資訊
批量轉存的前提是,我們得登錄,我這里實作的方案是直接從瀏覽器中獲取到cookie資訊,復制到代碼中進行使用,查看網站的cookie資訊可以用插件EditThisCookie

點擊右上角匯出Cookie,cookie就放在粘貼板中了,復制到代碼中,然后使用回圈,將所有cookie利用page.setCookie方法,將cookie放置到當前請求背景關系中
填寫提取碼
等待頁面加載完畢,找到輸入提取碼框的元素,找到其id,然后使用page.$$eval()方法獲取并寫入東西

可以看見,這里的id為accessCode,所以我們只需要寫
await page.$$eval('#accessCode', writeCode, code);
async function writeCode(nodes, code) {
for (let node of nodes) {
node.value = https://www.cnblogs.com/chaojilaji/archive/2020/10/23/code;
}
}
就可以了,我這里是直接改的node.value,你也可以用puppeteer模擬人來填寫,
提取檔案
找到提取檔案按鈕,點擊,然后等待跳轉完畢,

值得注意的是,我們點擊的一定是A標簽,其他標簽需要進行過濾,
await page.$$eval('.g-button-blue-large', click);
await page.waitFor(1000);
async function click(nodes) {
for (let node of nodes) {
if (node.title === '提取檔案') {
await node.click();
}
}
}
然后等待跳轉即可
選擇要保存的檔案
這里簡單實作為,選擇全部檔案,不過值得注意的是,如果是單檔案,是不需要點擊選擇全部檔案的,可以通過判斷元素是否存在判斷是否有復選框,是否需要進行點擊

如圖,不過這里奇怪的是,class的值是一個不可讀的字串,我不確定這個值是不是與用戶有關,所以這里就打碼了,
既然需要做的就是找到這個元素,點擊就行了,那我們照著做就行
await page.$$eval('.zbyDdwb', selectAll);
async function selectAll(nodes) {
for (let node of nodes) {
await node.click();
break;
}
}
點擊保存到網盤
與點擊提取檔案一樣,找到目表按鈕,然后點擊就行,感興趣的朋友,可以自己試試
彈出框選擇保存的檔案路徑
避免麻煩,這里寫得比較簡單,如果有選擇跟上一次樣的框,那么就點擊選擇跟上一次一樣,如果沒有,就直接存盤在根目錄下,(可以根據你想要的需求自己改)
選擇前

選擇后

可以發現,僅僅是改變了Class的值,所以實作的時候,也改變一下值就行
await page.$$eval('.save-path-item', chooseLocation);
async function chooseLocation(nodes) {
for (let node of nodes) {
node.setAttribute('class', 'save-path-item check');
}
}
點擊確定按鈕
與之前幾個按鈕一樣,我們只需要找到確認按鈕,點擊就行了,
await page.$$eval('[title=確定]', confirm)
async function confirm(nodes) {
for (let node of nodes) {
console.log(node.tagName);
if (node.tagName === 'A') {
await node.click();
}
}
}
這樣,整個邏輯就完成了,
完整代碼
為了程式能正常運行,需要加入一些額外的waitFor等待,避免操作太快導致的諸如IP封禁,元素未加載出來等亂七八糟的問題,同時,我這里資料都是從資料庫中出來的,所以里面有與更新資料庫狀態的代碼,
const Pan = require('../model/Pan');
const {Cluster} = require('puppeteer-cluster');
const crawler = require('./crawler');
const cookies = [];
async function selectAll(nodes) {
console.log('selectAll',nodes.length);
for (let node of nodes) {
await node.click();
break;
}
}
async function click(nodes) {
console.log('click',nodes.length);
for (let node of nodes) {
if (node.title === '提取檔案') {
await node.click();
}
}
}
async function writeCode(nodes, code) {
console.log('writeCode',nodes.length);
for (let node of nodes) {
node.value = https://www.cnblogs.com/chaojilaji/archive/2020/10/23/code;
}
}
async function confirm(nodes) {
console.log(nodes.length);
for (let node of nodes) {
console.log(node.tagName);
if (node.tagName ==='A') {
await node.click();
}
}
}
async function clickSave(nodes) {
for (let node of nodes) {
if (node.tagName === 'A') {
await node.click();
break;
}
}
}
async function chooseLocation(nodes) {
for (let node of nodes) {
node.setAttribute('class', 'save-path-item check');
}
}
async function saveBaidu() {
const cluster = await Cluster.launch(crawler.clusterLanuchOptionsPan);
await cluster.task(async ({page, data}) => {
let {id, url, code} = data;
for (let i = 0; i < cookies.length; i++) {
await page.setCookie(cookies[i]);
}
await page.goto(url);
await page.waitForSelector('html');
await page.content();
let title = await page.title();
let codeWrong = false;
let used = true;
let needCodeButNone = false;
if (title.indexOf('提取碼') !== -1) {
// todo 填寫提取碼
if (code === '-' || code === '+') {
needCodeButNone = true;
} else {
await page.$$eval('#accessCode', writeCode, code);
await page.$$eval('.g-button-blue-large', click);
await page.waitFor(1000);
let content = await page.content();
if (content.indexOf('驗證碼錯誤') !== -1) {
used = false;
} else if (content.indexOf('提取碼錯誤') !== -1) {
codeWrong = true;
used = false;
} else {
await page.waitFor(2000);
}
}
}
if (used && !needCodeButNone) {
title = await page.title();
await page.waitFor(1000);
console.log(title);
if (title.indexOf('不存在') !== -1) {
} else {
// todo 找到title=保存到網盤的a標簽并點擊
let x = await page.$$('.zbyDdwb');
console.log(x.length);
if (!(x === null || x===undefined || x.length === 0)){
await page.$$eval('.zbyDdwb', selectAll);
}
await page.$$eval('[title=保存到網盤]', clickSave);
await page.$$eval('.save-path-item', chooseLocation);
await page.waitFor(2000);
await page.$$eval('[title=確定]', confirm);
}
}
await Pan.update({
used: used,
code_wrong: codeWrong,
need_code: needCodeButNone
}, {
where: {
id: id
}
});
await page.waitFor(3000);
});
let pans = await Pan.findAll({
where: {
site_id:12,
reachable: true,
used:false,
code_wrong:false
}
});
console.log(pans.length);
for (let i = 0; i < pans.length; i++) {
if (pans[i].url.startsWith('http://pan.baidu') || pans[i].url.startsWith('https://pan.baidu')) {
await cluster.queue({
id: pans[i].id,
url: pans[i].url,
code: pans[i].code
});
}
}
await cluster.idle();
}
(async () => {
await saveBaidu();
})();
// crawler.clusterLanuchOptionsPan 是啟動配置項,如下
const launchOptions = {
headless: true,
ignoreHTTPSErrors: true, // 忽略證書錯誤
waitUntil: 'networkidle2',
defaultViewport: {
width: 1920,
height: 1080
},
args: [
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-web-security',
'--disable-xss-auditor', // 關閉 XSS Auditor
'--no-zygote',
'--no-sandbox',
'--disable-setuid-sandbox',
'--allow-running-insecure-content', // 允許不安全內容
'--disable-webgl',
'--disable-popup-blocking',
//'--proxy-server=http://127.0.0.1:8080' // 配置代理
],
executablePath: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
};
const clusterLanuchOptionsPan = {
concurrency: Cluster.CONCURRENCY_PAGE, // 單Chrome多tab模式
maxConcurrency: 1, // 并發的workers數
retryLimit: 2, // 重試次數
skipDuplicateUrls: true, // 不爬重復的url
monitor: false, // 顯示性能消耗
puppeteerOptions: launchOptions,
};
本文由博客群發一文多發等運營工具平臺 OpenWrite 發布
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/187385.html
標籤:其他
