需求:在A电脑内用node和superagent爬取头像和证件号,将头像nase64编码后和身份证一起保存在excel。后在B电脑内用node访问接口,参数是excel内的头像和证件号。数据可能几百上千条,所以批量访问的时候需要设置同步异步的问题,且B电脑的访问链接由于参数是图片base64,返回结果可能不是很快,希望能得到完整代码和最优解。能有多线程什么最好。
“Devil组”引证GPT后的撰写:
在A电脑内使用以下代码来爬取并保存图片和证件号:
const superagent = require('superagent');
const cheerio = require('cheerio');
const xlsx = require('xlsx');
const async = require('async');
const fs = require('fs');
const filename = 'data.xlsx';
const getImagesAndIds = (callback) => {
const images = [];
const ids = [];
const urls = [
'http://example.com/user1',
'http://example.com/user2',
// add more urls as needed
];
async.eachSeries(urls, (url, next) => {
superagent.get(url).end((err, res) => {
if (err) return next(err);
const $ = cheerio.load(res.text);
const image = $('img.avatar').attr('src');
const id = $('#id').text();
images.push(image);
ids.push(id);
next();
});
}, (err) => {
if (err) return callback(err);
const workbook = xlsx.utils.book_new();
const worksheet = xlsx.utils.json_to_sheet(ids.map((id, i) => ({id, image: images[i]})));
xlsx.utils.book_append_sheet(workbook, worksheet, 'data');
xlsx.writeFile(workbook, filename);
callback(null);
});
};
getImagesAndIds((err) => {
if (err) console.error(err);
console.log('Done');
});
在B电脑内使用以下代码来读取Excel文件,并将图片和证件号码上传到远程API:
const superagent = require('superagent');
const xlsx = require('xlsx');
const async = require('async');
const apiUrl = 'http://example.com/api';
const processData = (data, callback) => {
async.eachLimit(data, 5, (row, next) => {
const { id, image } = row;
superagent.post(apiUrl)
.send({ id, image })
.end((err, res) => {
if (err) console.error(err);
next();
});
}, (err) => {
if (err) return callback(err);
callback(null);
});
};
const workbook = xlsx.readFile('data.xlsx');
const worksheet = workbook.Sheets['data'];
const data = xlsx.utils.sheet_to_json(worksheet);
processData(data, (err) => {
if (err) console.error(err);
console.log('Done');
});
用了async模块来处理异步操作。在A电脑中,用了async.eachSeries来依次爬取每个URL,并在完成后保存数据到Excel文件中。在B电脑中,用了async.eachLimit来限制并发数,并依次处理Excel文件中的每一行数据,并将数据上传到远程API。
这个代码还使用了superagent模块来进行HTTP请求,并使用了cheerio模块来解析HTML。用了xlsx模块来处理Excel文件。
该回答引用ChatGPT
以下是您所需的 Node.js 代码,它可以在 A 电脑上使用 Node 和 superagent 模块来爬取头像和证件号,并将它们保存在 Excel 文件中。然后在 B 电脑上使用 Node 来读取 Excel 文件,并通过 HTTP POST 请求将图片和证件号上传到接口。这个程序使用了异步方式来处理大量数据,使用了多线程池以提高性能。
在 A 电脑上的代码(爬取头像和证件号):
const fs = require('fs');
const xlsx = require('xlsx');
const superagent = require('superagent');
const { promisify } = require('util');
const { parse } = require('node-html-parser');
const { Worker, isMainThread, workerData } = require('worker_threads');
const writeFile = promisify(fs.writeFile);
const readFile = promisify(fs.readFile);
const parseHtml = html => parse(html);
const URL = 'http://www.example.com/userinfo?id=';
const workerScript = `
const { parentPort, workerData } = require('worker_threads');
const superagent = require('superagent');
const { parseHtml } = require('./utils');
const URL = 'http://www.example.com/userinfo?id=';
(async () => {
try {
const { id } = workerData;
const { body } = await superagent.get(URL + id);
const root = parseHtml(body);
const avatarUrl = root.querySelector('#avatar').getAttribute('src');
const avatarRes = await superagent.get(avatarUrl).buffer(true);
const avatarBase64 = avatarRes.toString('base64');
parentPort.postMessage({ id, avatarBase64, idNo: root.querySelector('#idNo').innerText });
} catch (error) {
parentPort.postMessage({ error: error.message });
}
})();
`;
async function main() {
const workbook = xlsx.readFile('data.xlsx');
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
const rows = xlsx.utils.sheet_to_json(worksheet);
const workerPool = new Set();
for (const row of rows) {
const id = row['ID'];
const worker = new Worker(workerScript, { workerData: { id } });
worker.on('message', ({ id, avatarBase64, idNo, error }) => {
if (error) {
console.error(`Failed to process row ${id}: ${error}`);
return;
}
worksheet[`B${id + 1}`] = { t: 's', v: idNo };
worksheet[`C${id + 1}`] = { t: 's', v: avatarBase64 };
console.log(`Processed row ${id}`);
});
worker.on('error', error => {
console.error(`Worker for row ${id} failed with error: ${error}`);
});
worker.on('exit', () => {
workerPool.delete(worker);
});
workerPool.add(worker);
if (workerPool.size >= 10) {
await Promise.all([...workerPool].map(worker => new Promise(resolve => worker.once('exit', resolve))));
}
}
await Promise.all([...workerPool].map(worker => new Promise(resolve => worker.once('exit', resolve))));
xlsx.writeFile(workbook, 'data.xlsx');
}
main().catch(error => console.error(error));
以下是在 B 电脑上的代码,它会从 Excel 文件中读取头像和证件号,并通过 HTTP POST 请求将它们上传到接口。该程序会异步地处理大量数据,使用了多线程池以提高性能。
const fs = require('fs');
const xlsx = require('xlsx');
const { promisify } = require('util');
const { Worker, isMainThread, workerData } = require('worker_threads');
const request = require('request-promise-native');
const readFile = promisify(fs.readFile);
const workerScript = `
const { parentPort, workerData } = require('worker_threads');
const request = require('request-promise-native');
(async () => {
try {
const { idNo, avatarBase64 } = workerData;
const response = await request({
method: 'POST',
uri: 'http://www.example.com/api',
body: { idNo, avatarBase64 },
json: true,
});
parentPort.postMessage({ idNo, avatarBase64, response });
} catch (error) {
parentPort.postMessage({ error: error.message });
}
})();
`;
async function main() {
const workbook = xlsx.readFile('data.xlsx');
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
const rows = xlsx.utils.sheet_to_json(worksheet);
const workerPool = new Set();
for (const row of rows) {
const id = row['ID'];
const idNo = row['证件号'];
const avatarBase64 = row['头像'];
const worker = new Worker(workerScript, { workerData: { idNo, avatarBase64 } });
worker.on('message', ({ idNo, avatarBase64, response, error }) => {
if (error) {
console.error(`Failed to process row ${id}: ${error}`);
return;
}
console.log(`Processed row ${id}: ${JSON.stringify(response)}`);
});
worker.on('error', error => {
console.error(`Worker for row ${id} failed with error: ${error}`);
});
worker.on('exit', () => {
workerPool.delete(worker);
});
workerPool.add(worker);
if (workerPool.size >= 10) {
await Promise.all([...workerPool].map(worker => new Promise(resolve => worker.once('exit', resolve))));
}
}
await Promise.all([...workerPool].map(worker => new Promise(resolve => worker.once('exit', resolve))));
}
main().catch(error => console.error(error));
上述代码的执行流程如下:
1、在 A 电脑上,首先使用 xlsx 模块读取 Excel 文件,并使用 superagent 模块爬取头像和证件号。然后将这些数据保存到 Excel 文件中。这个过程使用了多线程池,以提高性能。
2、在 B 电脑上,程序从 Excel 文件中读取头像和证件号,并使用 request-promise-native 模块将它们上传到接口。这个过程也使用了多线程池,以提高性能。
请注意,在使用本代码时,您需要将以下代码行替换为实际的接口 URL:
const URL = 'http://www.example.com/userinfo?id=';
javascript
Copy code
uri: 'http://www.example.com/api',
参考GPT和自己的思路:以下是一个基本的示例代码,用于在A电脑内使用Node.js和Superagent爬取头像和证件号,将头像Base64编码后和身份证一起保存在Excel中。
const fs = require('fs');
const xlsx = require('xlsx');
const superagent = require('superagent');
// 获取头像并保存为base64编码格式
async function getAvatarBase64(url) {
const response = await superagent.get(url).buffer(true);
const base64 = Buffer.from(response.body, 'binary').toString('base64');
return base64;
}
// 爬取数据并保存到Excel
async function crawlData() {
const workbook = xlsx.readFile('data.xlsx');
const worksheet = workbook.Sheets['Sheet1'];
const rows = xlsx.utils.sheet_to_json(worksheet);
for (let row of rows) {
const avatarBase64 = await getAvatarBase64(row.avatarUrl);
row.avatarBase64 = avatarBase64;
}
const newWorksheet = xlsx.utils.json_to_sheet(rows);
xlsx.utils.book_append_sheet(workbook, newWorksheet, 'Sheet2');
xlsx.writeFile(workbook, 'data-with-base64.xlsx');
}
crawlData();
这段代码使用Superagent库发出HTTP GET请求来获取头像,并使用Buffer对象将其转换为Base64编码。然后,使用XLSX库读取Excel文件并将头像的Base64编码添加到Excel的新列中,最后将新工作表写回到Excel文件中。
对于在B电脑中访问接口的问题,您需要创建一个服务器端应用程序,它可以接收Excel文件中的头像和证件号,并将头像和证件号作为参数发送到相应的API。以下是一个基本的示例代码:
const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const xlsx = require('xlsx');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// 批量访问API
async function batchAccessAPI(data) {
const promises = data.map(async row => {
const response = await axios.post('https://example.com/api', {
avatarBase64: row.avatarBase64,
idNumber: row.idNumber
});
return response.data;
});
return Promise.all(promises);
}
// 处理Excel文件并批量访问API
app.post('/process', (req, res) => {
const workbook = xlsx.read(req.body.file, { type: 'buffer' });
const worksheet = workbook.Sheets['Sheet1'];
const rows = xlsx.utils.sheet_to_json(worksheet);
batchAccessAPI(rows)
.then(results => {
res.send(results);
})
.catch(error => {
console.error(error);
res.status(500).send(error.message);
});
});
// 启动服务器
app.listen(3000, () => {
console.log('Server started on port 3000');
});
这段代码使用Express框架创建一个HTTP服务器,并使用Axios库发出HTTP POST请求来访问API。它还使用XLSX库读取POST请求中的Excel文件,并使用批处理方式访问API。您可以使用curl或Postman等工具向此服务器端点发送POST请求。
具体的实现方式可以分为以下几个步骤:1. 在A电脑上,通过node和superagent爬取头像和证件号,将头像nase64编码后和身份证一起保存在excel。node爬虫的实现可以使用request或者superagent等第三方库,目标网站是否进行了图片防盗链等操作,可以根据具体情况选择适合的方式。图片的base64编码可以使用buffer和fs模块进行处理,具体代码如下:javascriptconst buffer = require('buffer');const fs = require('fs');let base64Img = buffer.Buffer.from(fs.readFileSync(filePath)).toString('base64');
保存数据到excel表格中可以使用exceljs模块,具体代码如下:javascriptconst Excel = require('exceljs');let workbook = new Excel.Workbook();let worksheet = workbook.addWorksheet('Sheet1');worksheet.columns = [ { header: 'name', key: 'name' }, { header: 'ID', key: 'id' }, { header: 'avatar', key: 'avatar' }];worksheet.addRow({ name: '张三', id: '110101199001010001',avatar: 'data:image/png;base64,' + base64Img});worksheet.addRow({ name: '李四', id: '110101199001010002',avatar: 'data:image/png;base64,' + base64Img});workbook.xlsx.writeFile('data.xlsx').then(function () { console.log("saved");});
2. 在B电脑上,使用node访问接口,参数是excel内的头像和证件号。在B电脑上,通过读取excel表格中的数据,获取头像和证件号等信息,并将请求参数通过http请求方式发送给服务端。代码如下:javascriptconst request = require('request');const Excel = require('exceljs');let workbook = new Excel.Workbook();workbook.xlsx.readFile('data.xlsx') .then(function () { let worksheet = workbook.getWorksheet(1); worksheet.eachRow({ includeEmpty: false }, function (row, rowNumber) { let id = row.getCell('id').value; let avatar = row.getCell('avatar').value; request.post('http://xxx.com/api/user',{form:{id:id,avatar:avatar}}).on('response',function(response){ console.log(response.statusCode); }); }); });
3. 设置同步异步的方式,优化并发请求在批量访问的时候,可能存在并发请求过多导致服务端崩溃或者不能正常响应的情况。可以设置同步和异步的方式,通过限制并发请求数量来避免过多的请求。具体代码如下:javascriptconst request = require('request');const async = require('async');const Excel = require('exceljs');let workbook = new Excel.Workbook();workbook.xlsx.readFile('data.xlsx') .then(function () { let worksheet = workbook.getWorksheet(1); let queue = async.queue(function (task,callback) { let id = task.id; let avatar = task.avatar; request.post('http://xxx.com/api/user',{form:{id:id,avatar:avatar}},function(error,response,body){ console.log(response.statusCode); callback(); }); },5);//设置并发请求数量 worksheet.eachRow({ includeEmpty: false }, function (row, rowNumber) { let id = row.getCell('id').value; let avatar = row.getCell('avatar').value; queue.push({id:id,avatar:avatar}); }); });
4. 实现多线程Node.js中,每个进程只能按照单线程处理。但是可以通过子进程模块和cluster模块实现多进程的方式来实现多线程。cluster模块可以基于多核CPU提高进程的工作效率,通过fork方法来创建子进程来实现多进程间的通信。基于项目复杂度和开发维护成本的考虑,在本项目可不需要使用多线程的方式来优化性能。总结:通过使用node和superagent爬取头像和证件号,并且将头像nase64编码后和身份证一起保存在excel表格中,同时在B电脑上使用node访问接口,并通过设置同步异步的方式,限制并发请求的数量来优化性能。本方案可以满足需求,同时对于实现多线程可以在具体应用场景中进行考虑。
为啥要用excel呢?是不是可以单个资源上锁?
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
针对您的需求,我可以提供以下解决方案:
```javascript
const superagent = require('superagent');
const xlsx = require('xlsx');
const fs = require('fs');
const data = []; // 用于存放数据的数组
// 设置请求头,防止被封禁
const headers = {
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36',
};
// 请求头像和身份证
async function getData() {
for(let i=0; i<100; i++) { // 可以设置for循环批量请求
const response = await superagent // 发起请求
.get(`https://x/
可否用Python实现?