ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: wodewan

[原创] JSA爬虫新玩法-更少的代码,更快的速度,更便捷的选择

[复制链接]

TA的精华主题

TA的得分主题

发表于 2024-7-8 15:42 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
一江春水1688 发表于 2024-7-8 12:53
补充说一下:
您的异步函数查询数据的2个函数,直接在循环中使用async/await,效率比较低。
循环调用了 ...

请教一下,Promise.all怎么用?

TA的精华主题

TA的得分主题

发表于 2024-7-8 21:53 | 显示全部楼层
sunya_0529 发表于 2024-7-8 15:42
请教一下,Promise.all怎么用?

参考如下:

  1. async function 获取中考成绩1(){
  2.     let tb1 = ThisWorkbook.Sheets(1).Cells(1).CurrentRegion.Columns(1).Cells
  3.     tb1 = tb1.Offset(1, 0).Resize(tb1.Rows.Count - 1, tb1.Columns.Count);
  4.     let arr = await Promise.all([...tb1].map((_, i) => {
  5.         let rng = tb1.Cells(i + 1).Resize(1, 3);
  6.         const url="http://cx.jzsjyksy.com/queryPost";
  7.         const data=`id=24&code=${rng.Value2.flat().join('|')}`;
  8.         const options={
  9.             method: "POST",
  10.             headers: {
  11.                 "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"            
  12.             },
  13.             body: data
  14.         }
  15.         return fetch(url,options)
  16.     }));
  17.     let htmltext_arr = await Promise.all(arr.map(r => r.text()));
  18.     let res = [];
  19.     for (let htmltext of htmltext_arr) {
  20.         res.push(htmltext.match(/(?<=var data = ")(.+)(?=";)/)[0].split(',').slice(3));
  21.     }
  22.     tb1.Offset(0, 3).Resize(res.length, res[0].length).Value2 = res;
  23. }
复制代码


TA的精华主题

TA的得分主题

发表于 2024-7-9 09:21 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2024-7-9 23:03 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2024-7-10 11:15 | 显示全部楼层
sunya_0529 发表于 2024-7-9 23:03
对比测试了一下——

0.006秒,不是真实的耗时。没等网络请求返回数据,就已经先执行了耗时计算及显示。
另外,重新审视了您的代码,发现我的理解有误,您的代码,也类似于并发执行(跟Promise.all处理的时间相当),即没等待返回结果,就循环到下一次调用,不过,最终返回结果的时序很有趣,有可能后面的数据先返回
下面的代码可以证实:
  1. async function GetHTMLAsync(rng, t1){
  2.         const url = "http://cx.jzsjyksy.com/queryPost";
  3.         const data = `id=24&code=${rng.Value2.flat().join('|')}`;
  4.         const options = {
  5.                 method: "POST",
  6.                 headers: {
  7.                         "Content-Type": "application/x-www-form-urlencoded"                        
  8.                 },
  9.                 body: data
  10.         }
  11.         let response = await fetch(url,options);
  12.         let htmltext = await response.text();
  13.         let res = htmltext.match(/(?<=var data = ")(.+)(?=";)/)[0].split(',').slice(3);
  14. //        rng.Offset(0, 3).Resize(1,res.length).Value2 = res;
  15.         rng.Offset(0, 3).Resize(1, 1).Value2 = (new Date() - t1); //耗时写入单元格,单位毫秒数

  16. async function 获取中考成绩(){
  17.         console.clear();
  18.         let t1 = new Date();
  19.         for(let rng of ThisWorkbook.Sheets(1).Cells(1).CurrentRegion.Columns(1).Cells){
  20.                 if(rng.Row>1) GetHTMLAsync(rng.Resize(1,3), t1);
  21.         }
  22.         console.log(`耗时:${new Date() - t1} 毫秒`)
  23. }
复制代码


【 function 获取中考成绩() 】函数改写如下,即为串行执行了,不改变返回结果的时序,但运行时间慢于并行(并发)执行的时间:
  1. async function 获取中考成绩(){
  2.         console.clear();
  3.         let t1 = new Date();
  4.         for(let rng of ThisWorkbook.Sheets(1).Cells(1).CurrentRegion.Columns(1).Cells){
  5.                 if(rng.Row>1) await GetHTMLAsync(rng.Resize(1,3), t1);
  6.         }
  7.         console.log(`耗时:${new Date() - t1} 毫秒`)
  8. }
复制代码

其实用网络请求并返回数据来检验,并不准确,更准确的办法,应使用 [color=var(--code-token-attribute-name)]setTimeout 来模拟。另外,并发执行可以显著提高效率,但效率也没有我之前说的那么夸张,跟运行环境和应用场景有关。

参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function#%E7%A4%BA%E4%BE%8B

点评

受教了,栓Q~  发表于 2024-7-10 13:14

TA的精华主题

TA的得分主题

发表于 2024-9-16 15:34 | 显示全部楼层
请教下
有如下代码
async function fetchData() {&#160; &#160;
         let response = await fetch('http://127.0.0.1:5000/');&#160; &#160;
         let data = await response.text();&#160; &#160;
         console.log(data);
         return data;
}

然后在单元格a1写公式=fetchData(),返回值是[object Promise],是啥原因呢

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-9-16 19:22 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
konka-- 发表于 2024-9-16 15:34
请教下
有如下代码
async function fetchData() {&#160; &#160;

你是对的,只要是async修饰的函数,无论你的返回值是什么都会包装成一个Promise。
所以,对于UDF函数来说,使用fetch直接返回结果到单元格貌似不行,只能在函数内部处理获取的数据,比如你写的console或alert等。
这种需求貌似目前只能改用同步的XMLHttpRequest来实现。




您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-15 07:14 , Processed in 0.035400 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表