Compare commits

..

10 Commits
zhihu ... main

Author SHA1 Message Date
LingandRX
82920dd8fb fix: 修改文件名大小写 2024-12-21 00:01:42 +08:00
82414ef213 fix hlk 2024-12-20 23:25:00 +08:00
LingandRX
b9c7b52a4d fix login data exception 2024-12-19 23:43:54 +08:00
LingandRX
e521f3b028 test 2024-12-19 00:05:29 +08:00
LingandRX
1d4797ece3 feat: 添加 HLK 平台数据拉取脚本
- 新增 HLK 平台登录和数据拉取脚本
- 使用 Puppeteer 实现自动化登录和数据抓取
- 添加打印 IndexedDB 数据的功能
2024-12-18 09:11:31 +08:00
wenpeng
cc1251eda9 add on response 2024-08-07 16:28:49 +08:00
wenpeng
427cc0d929 fix 2024-08-05 18:18:38 +08:00
wenpeng
1f315fe199 fix 2024-08-02 14:31:49 +08:00
wenpeng
b3f96ddddd fix 2024-08-01 17:30:36 +08:00
wenpeng
9a9b4646ca fix 2024-08-01 16:07:17 +08:00
23 changed files with 4449 additions and 263 deletions

3
.gitignore vendored
View File

@ -3,5 +3,4 @@ node_modules/
*.png
businessData.json
data/user.json
data/zhihu.json
data/zhihuData.json
data/technicianReport.json

View File

@ -1,13 +0,0 @@
{
"printWidth": 100,
"tabWidth": 4,
"semi": true,
"singleQuote": false,
"quoteProps": "consistent",
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "avoid",
"proseWrap": "never",
"endOfLine": "lf",
"embeddedLanguageFormatting": "off"
}

View File

@ -0,0 +1,36 @@
import { launch } from 'puppeteer';
import fs from 'fs';
import 'dotenv/config.js'
import { setLocalStorage } from './utils/userUtils.js';
import { getDate } from './utils/businessDataUtil.js';
import { setMonthTime } from './utils/commnUtils.js'
(async () => {
const browser = await launch({ headless: true, args: [`--window-size=1920,1080`], defaultViewport: { width: 1920, height: 1080 } });
const page = await browser.newPage();
page.on('response', async(response) => {
console.log(response.url());
});
setLocalStorage(page, '.\\data\\user.json');
await page.goto('https://dev-dmp.meiguanjia.net/report/businessData');
// await page.goto('https://boss.aizhb.net/report/businessData');
await page.waitForSelector('.menu-list-second');
const childElements = await page.$$('.menu-list-second .menu-list-second-item');
await new Promise(r => setTimeout(r, 1000));
await childElements[1].click();
const str = await page.evaluate(node => node.textContent.trim(), childElements[1]);
console.log(str);
const file = './data/businessData.json';
fs.writeFileSync(file, '', 'utf-8');
await setMonthTime(page, '.arco-picker-start-time', '2024-05');
await getDate(page, fs, file);
console.log('========');
await browser.close();
})();

View File

@ -1,3 +0,0 @@
111
333

View File

@ -0,0 +1,30 @@
import { launch } from 'puppeteer';
import fs from 'fs';
import 'dotenv/config.js'
import { setLocalStorage } from './utils/userUtils.js';
import { setMonthTime, getDate, changeTimeDimension } from './utils/commnUtils.js'
(async () => {
const browser = await launch({ headless: false, args: [`--window-size=1920,1080`], defaultViewport: { width: 1920, height: 1080 } });
const page = await browser.newPage();
setLocalStorage(page, '.\\data\\user.json');
await page.goto('https://dev-dmp.meiguanjia.net/report/technicianReport');
// await page.goto('https://boss.aizhb.net/report/businessData');
await page.waitForSelector('.menu-list-second');
const childElements = await page.$$('.menu-list-second .menu-list-second-item');
await new Promise(r => setTimeout(r, 1000));
await childElements[2].click();
const str = await page.evaluate(node => node.textContent.trim(), childElements[2]);
console.log(str);
const file = './data/technicianReport.json';
fs.writeFileSync(file, '', 'utf-8');
await changeTimeDimension(page, 2);
await setMonthTime(page, '.arco-picker-start-time', '2024-05');
await getDate(page, fs, file);
await browser.close();
})();

3670
allData.json Normal file

File diff suppressed because it is too large Load Diff

1
cookie.json Normal file
View File

@ -0,0 +1 @@
[{"name":"JSESSIONID","value":"9E55F1720F56A71F1C1DDE22ECE125EA","domain":"hlk.meiguanjia.net","path":"/","expires":-1,"size":42,"httpOnly":true,"secure":false,"session":true,"priority":"Medium","sameParty":false,"sourceScheme":"Secure"}]

View File

@ -1,152 +0,0 @@
[
{
"title": "2024 巴黎奥运会女乒单打决赛,陈梦 4-2 击败孙颖莎成功卫冕奥运冠军,如何评价这场比赛?",
"excerpt": "",
"createTime": 1722700586230
},
{
"title": "哈里斯已获足够票数,锁定民主党总统候选人提名 ,目前美国大选形势如何?哈里斯将如何展开其竞选活动?",
"excerpt": "美国民主党全国委员会 2 日宣布,美国副总统哈里斯已获得足够锁定民主党总统候选人提名的党代表票。 约 4700 名民主党代表参与的线上投票于 1 日上午开始。经过约一天半的投票后,民主党全国委员会主席贾梅·哈里森宣布,哈里斯已获得足够锁定提名的党代表票。委员会预计将在 5 日结束此次线上投票,并正式宣布结果。哈里斯竞选团队说,哈里斯已获得超过 2350 票,达到锁定提名门槛。 7 月 21 日,美国总统、民主党人拜登在政治和舆论压力下宣布放弃竞选连任,并「背书」哈里斯成为民主党总统候选人。民主党全国代表大会定于 8 月 19 日至 22 日在芝加哥举行,民主党计划在大会上正式提名该党总统候选人。民主党希望提前进行线上投票,以尽早确定党内总统候选人。 据美国媒体报道,哈里斯预计最迟将于 5 日公布她的竞选搭档,二人将于 6 日在费城举行首次联合竞选集会。哈里斯竞选搭档的热门人选包括宾夕法尼亚州州长夏皮罗、亚利桑那州参议员凯利和肯塔基州州长贝希尔。 最新民调数据显示,哈里斯和共和党总统候选人、前总统特朗普的民调接近,目前选情胶着。据美国选举信息网站「真正透明政治」汇总的民调数据,截至 7 月 31 日,特朗普在全国民调中平均领先哈里斯 1.2 个百分点,而拜登退选之前,特朗普对哈里斯的优势为 1.7 个百分点。 来源:新华社哈里斯已获足够锁定民主党总统候选人提名的党代表票 _ 竞选 _ 美国 _ 特朗普",
"createTime": 1722700586235
},
{
"title": "陈梦战胜孙颖莎夺巴黎奥运女单金牌,现场粉丝的行为会不会对参赛者产生影响?球迷应该以什么态度观看比赛?",
"excerpt": "第 14 金 奥运乒乓女单巅峰对决!陈梦成功卫冕 孙颖莎收获银牌",
"createTime": 1722700586240
},
{
"title": "7 月日本东京都 123 人疑似中暑死亡,其中 121 人死在室内,东京到底有多热?为多在室内中暑?",
"excerpt": "当地时间 8 月 3 日获悉据日本东京都监察医务院初步统计7 月东京都 23 区可能因中暑死亡的人数为 123 人,较去年同期增加 28 人。死者大多数为老年人。另外123 名死者中,有 121 人死亡地点为室内。7 月日本东京都 123 人疑似中暑死亡 | 每经网",
"createTime": 1722700586245
},
{
"title": "如何评价绝区零 1.1 版本前瞻直播?",
"excerpt": "这也太短了?",
"createTime": 1722700586250
},
{
"title": "《甄嬛传》中皇上为什么不提防宁嫔?",
"excerpt": "",
"createTime": 1722700586253
},
{
"title": "2024 巴黎奥运会网球女子单打金牌赛中国 VS 克罗地亚,如何评价这场比赛?",
"excerpt": "",
"createTime": 1722700586256
},
{
"title": "1500 到 2000 的手机有什么高性价比的推荐的吗?",
"excerpt": "",
"createTime": 1722700586259
},
{
"title": "北航新生想问问怎么安排大一?",
"excerpt": "北航信息类工科试验班新生,想问问各位大一时怎么安排,以及这个大类之后该选什么专业",
"createTime": 1722700586264
},
{
"title": "郑钦文战胜头号种子斯瓦泰克,成首位闯入网球赛事单打决赛的中国球员,你看好她的夺冠前景吗?",
"excerpt": "",
"createTime": 1722700586267
},
{
"title": "你悟出或听到哪些扎心又真实的道理?",
"excerpt": "",
"createTime": 1722700586271
},
{
"title": "在现代社会,女性在追求个人发展和婚姻之间如何找到平衡?",
"excerpt": "",
"createTime": 1722700586274
},
{
"title": "文笔挑战:「如果遗憾有声音,…」后面怎样接?",
"excerpt": "",
"createTime": 1722700586277
},
{
"title": "有哪些适合深夜解馋的宵夜值得推荐?",
"excerpt": "",
"createTime": 1722700586281
},
{
"title": "王楚钦在看台哭红眼睛,肖战指导暖心安慰,下一届奥运会,「大头」还有机会进男单决赛吗?",
"excerpt": "在樊振东半决赛比赛现场,肖指导看台安慰王楚钦,王楚钦看起来哭了,都红了眼睛。 不少网友为王楚钦可惜,认为如果不是那盘的爆冷,他如今应该也还在比赛,不至于坐在观赛区。",
"createTime": 1722700586285
},
{
"title": "41.9℃ 杭州打破当地历史最高气温纪录,为什么杭州 2024 年这么热?",
"excerpt": "潮新闻记者从杭州市气象台确认8 月 3 日 14 点 33 分,杭州站最高气温达到 41.9 ℃,一举打破历史最高气温纪录 41.8 ℃,创下新高。 「目前气温还在波动之中,今天的最高气温还没有定格。」杭州市气象台的工作人员说。 西湖边。里尔 / 摄 今天的起步气温就非常高调,上午 9 点多,体感温度就破了 40℃。 今天早晨,杭州站最低气温就有 31.0℃, 是 1951 年有连续气象观测纪录以来 8 月上旬乃至 8 月上半月里日最低气温的最高值。 烈日持续烘烤下,最终破了历史最高气温记录。可谓是「杀」疯了。 由于高温强劲,大气中不稳定能量增加,午后热对流正在蠢蠢欲动,今天浙东和浙南地区午后局部有阵雨或雷雨,有雷雨地区局地可伴有短时强降水和 8-10 级雷雨大风,在山里或海边避暑的朋友,一定要加强防范! 未来七天,高温依旧「全勤」。杭州、绍兴、衢州等地或将连遭 40℃暴击 比如杭州9 日前或将持续突破 4 字大关,可能追平观测史最长连续 40℃以上日数并打破观测史最高气温纪录。 杭州 2013 年 8 月 5 日—12 日连续 8 天 40℃以上历史极值为 2022 年 8 月 14 日,高达 41.8℃。 总之8 月上旬浙江省依旧被副高牢牢掌控,高温热浪不停歇! 小插曲是8 月 7 日后期起副高略有南退,午后对流有所加强。 11—12 日高空槽东移影响浙江省或将有一次系统性的降水过程届时高温强度略有减弱。41.9℃!杭州打破当地历史最高气温纪录 39.40 度的加起来几十天了,记得以前没上过 40 啊。",
"createTime": 1722700586290
},
{
"title": "开车真的方便吗?",
"excerpt": "",
"createTime": 1722700586294
},
{
"title": "济南姑娘崔宸曦创中国队奥运会滑板最好成绩,从教育角度分析,父母如何因材施教,孩子才能更好的实现自己?",
"excerpt": "第 414 岁崔宸曦创下中国滑板奥运最好成绩,日本选手包揽金银牌",
"createTime": 1722700586298
},
{
"title": "潘展乐破纪录,澳洲教练恼羞成怒「人类在这个项目上做不到」,潘展乐破纪录夺冠对世界自由泳意味着什么?",
"excerpt": "北京时间 8 月 2 日搜狐体育消息,在昨日的男子 100 米自由泳决赛上,中国小将潘展乐打破世界纪录,以绝对的优势取得冠军,查尔莫斯获得银牌。 潘展乐曾在采访中透露澳大利亚选手查尔莫斯,在奥运第一天曾经不理自己。 但值得一提的是,查尔莫斯赛后在社媒上发表了自己的感想时,加了两张与潘展乐握手的配图。也表示相信潘展乐是清白的,他有夺得金牌的实力。 搜狐体育原创UiiJK实力赢得尊重查尔莫斯赛后晒与潘展乐握手合照 _ 体育 _ 消息 _ 金牌潘展乐夺金,澳游泳名将查尔莫斯的教练破大防:声称「人类在这个项目上做不到!」,被网友回怼",
"createTime": 1722700586303
},
{
"title": "2024 巴黎奥运会篮球女子小组赛中国 80:58 波多黎各,如何评价这场比赛?",
"excerpt": "",
"createTime": 1722700586308
},
{
"title": "工作之后真的能把以前花过的钱赚回来吗?",
"excerpt": "学生时代总是会花钱买这买那,不说兴趣爱好和马斯洛理论的底层需求,光是学习读书就有一大堆教辅和补习班老师还有各种课,现在根本不敢想自己到底花了多少钱。小时候就老听大人和各种长辈说读书是硬道理,以后工作能把这些钱赚回来,我想知道各位工作的社畜知友,不管是什么年龄段,这句话的真实性有多少?",
"createTime": 1722700586336
},
{
"title": "女单决赛中陈梦对决孙颖莎,陈梦夺冠,你有什么看法?",
"excerpt": "",
"createTime": 1722700586342
},
{
"title": "李清照与岳飞同时代,为何她一字不提岳飞?",
"excerpt": "把秦桧是李的表妹夫这个可能性搁置,还有别的原因吗?",
"createTime": 1722700586350
},
{
"title": "为什么文字工作者大多数是熬夜大神?",
"excerpt": "如果深夜的你刷到了这个问题,请写出你想表达的文字吧",
"createTime": 1722700586358
},
{
"title": "西方在殖民全球的过程中,遇到过拥有火器等装备的原住民吗?",
"excerpt": "中国,日本等拥有高度文明的民族除外",
"createTime": 1722700586365
},
{
"title": "江苏等地已叫停房贷返点,此前有银行商贷返点折现 5 克金条,银行为何要花钱拉业务?背后有哪些原因?",
"excerpt": "部分区域房贷返点潜规则已被叫停。 据第一财经 8 月 2 日报道,日前,有消息称,江苏银行业协会发布《关于禁止个人住房按揭贷款返佣共同维护银行业公平竞争秩序的倡议》(以下简称《倡议》),请各银行金融机构在 2024 年 7 月底前规范与中介机构的合作协议。江苏一家银行网点的负责人表示,目前已经接到该文件。 这是今年以来首个规范房贷返点问题的文件。 近段时间,据多家媒体报道,此前被全面叫停的房贷返点现象有所抬头。 据《每日经济新闻》此前报道,上海购房者陈青(化名)表示,她于今年 6 月办了二手房按揭业务,商贷返点折现了 5 克金条。 花钱买贷款?江苏等地已叫停房贷「返点」,破除行业潜规则!专家表示「不要恶意竞争」 | 每经网银行房贷返点抢客再现,办 100 多万元贷款送 5 克金条,业内认为不利于银行长期运营,如何看待此事?",
"createTime": 1722700586371
},
{
"title": "巴黎奥运会 100 米女子蝶泳冠军脸色引争议,红得很不自然,被质疑需要药检,如何看待此事?",
"excerpt": "在刚刚结束的巴黎奥运会女子 100 米蝶泳决赛中,中国运动员张雨霏以 56 秒 21 获得铜牌,美国选手胡斯克获金牌,沃尔什获得银牌,不过在抵达终点之后,冠军胡斯克的脸红得很不正常,这也引发了不少网友的猜疑,呼吁赶紧让她做药检。 争议!美国冠军脸色不正常,网友呼吁赶紧药检,张雨霏偷偷抹泪",
"createTime": 1722700586375
},
{
"title": "夺得混双铜牌后林钟勋欣喜若狂,网友调侃「不用服兵役了」,韩国兵役制度是怎样的?为啥韩国人这么怕服兵役?",
"excerpt": "北京时间 7 月 30 日晚2024 巴黎奥运会乒乓球项目结束混双铜牌战。韩国组合林钟勋 / 申裕斌在第四局挽救 3 个局点,直落四局,以 4-011-5/11-7/11-7/14-12战胜中国香港组合黄镇廷 / 杜凯琹,获得铜牌。 7 月 30 日,林钟勋 / 申裕斌(右)庆祝胜利。 图 / 新华社 韩国媒体称,林钟勋原定于 8 月 19 日入伍到韩军体育部队,本来只剩下 20 天就要入伍。然而,由于这次获得铜牌,他获得免除兵役的待遇,不需要再入伍到军队服务。 赢得比赛后,林钟勋的喜悦溢于言表,他甚至当场举手敬礼,宣告免服兵役。颁奖结束后,林钟勋举起手机和其余获奖选手合影,有网友开玩笑表示这是在为免兵役「存档留证」。 林钟勋当场敬礼 图 / 视频截图 林钟勋表示:「从混合双打比赛开始时就已经意识到了(免兵役)。如果说没想过这件事,那就是撒谎。」 韩国《兵役法》规定,在相关国际艺术、体育赛事上取得优异成绩的艺术、体育特长人员可以享受「兵役优惠」,以艺术、体育要员身份的服务替代兵役。其中,「在艺术、体育领域具备特长的人」包括,在国际艺术大赛中的竞争单元获得前两名者、国内艺术大赛(限于韩国国乐等没有国际赛事的项目)中的第一名、具有 5 年以上国家非物质文化遗产传授教育人员,以及奥运会中获得前三名、亚运会中获得第一名的运动员。 自从在 2012 伦敦奥运会上夺得乒乓球男团赛银牌后,韩国队在奥运会乒乓球项目上再无奖牌入账,此次是韩国队时隔 12 年在奥运舞台摘得乒乓球项目奖牌。这也是林钟勋和申裕斌个人职业生涯中的首枚奥运奖牌,两人搭档仅 2 年便拿下了奥运会奖牌。 九派新闻记者 闫华阳 韩国乒乓球混双组合拿下奥运季军,林钟勋当场敬礼宣告免服兵役 _ 腾讯新闻 不用服兵役了!韩国乒乓球混双夺得铜牌,林钟勋欣喜若狂 - 观察者网",
"createTime": 1722700586380
},
{
"title": "聊聊武侠美学,你喜爱的武侠作品、人物与道具有哪些?",
"excerpt": "武侠之美,是一种融合了历史、文化、哲学与艺术的独特美学体验。它不仅仅体现在刀光剑影、飞檐走壁的激烈场面,更在于其中蕴含的深厚内涵和人文精神。 首先,武侠之美在于其独特的文化韵味。武侠作品往往以中国古代历史为背景,通过丰富的想象力和细腻的描绘,展现了一个充满传奇色彩的江湖世界。这个世界中既有英雄豪杰的豪情壮志,也有小人物的悲欢离合,充满了浓厚的人文气息。 其次,武侠之美在于其深刻的哲学思考。武侠作品往往探讨人性、道义、忠诚、爱情等永恒的主题,通过武侠人物的言行举止,传达出对人生、社会、世界的深刻洞见。这些哲学思考不仅丰富了武侠作品的内涵,也使其具有了超越时空的普世价值。 再者,武侠之美在于其精湛的艺术表现。无论是小说中的文字描绘,还是影视作品中的画面呈现,武侠作品都展现出了极高的艺术水准。精彩的打斗场面、唯美的风景描绘、动人的音乐配乐,都让人仿佛置身于一个梦幻般的武侠世界。 最后,武侠之美在于其传递的正义精神。武侠人物往往以行侠仗义为己任,他们不畏强权、不惧恶势力,用自己的勇气和智慧维护社会的公平和正义。这种正义精神不仅让人敬佩,也激励着人们在现实生活中坚守道义、追求真理。 武侠之美是一种多元而深刻的美学体验。它融合了历史、文化、哲学与艺术等多个方面,展现了一个充满传奇色彩和人文精神的江湖世界。在这个世界中,我们可以感受到人性的光辉、道义的力量以及艺术的魅力。 聊聊你喜爱的武侠作品、人物与道具,如: 武侠作品《笑傲江湖》:金庸先生的这部作品以其深邃的哲学思考和丰富的人物形象深受我喜爱。它讲述了令狐冲在江湖中的种种经历,展现了人性的复杂与美好。《神雕侠侣》:同样出自金庸之手,这部作品讲述了杨过与小龙女之间的爱情故事,以及他们在江湖中的冒险。其情节跌宕起伏,人物形象鲜明,让人难以忘怀。 武侠人物令狐冲:他性格豁达,不拘小节,剑法高超。他在江湖中的种种行为都展现了他的正义感和侠义精神。杨过:他是一个命运多舛但性格坚韧的人物。他的一生充满了磨难,但他始终坚守自己的道义,最终成为了江湖中的一代大侠。",
"createTime": 1722700586385
},
{
"title": "康定泥石流造成一村庄 2 人遇难 12 人失联,雅康高速公路隧间桥垮塌,掉坠 3 辆车,当地情况如何?",
"excerpt": "最新进展 截至 3 日早上 11 时,已核查出雅康高速公路康定往雅安方向掉坠 3 辆车共 6 人,其中 1 人获救、 5 人失联。雅康高速公路隧间桥垮塌 已核查出掉坠 3 辆车共 6 人 2024 年 8 月 3 日 3 时 30 分左右,雅康高速公路康定至泸定段日地 1 号隧道至 2 号隧道处,因突遇山洪泥石流隧间桥垮塌,有车辆掉坠。 目前,抢救出 2 人送医,有关灾情正在进一步核实中。甘孜州已启动 3 级应急响应,救援工作正全面推进。雅康高速公路突遇泥石流有隧间桥垮塌 救援工作正在进行 8 月 3 日夜间,局地发生的山洪泥石流造成四川省康定市姑咱镇日地村部分房屋被冲毁,其中 2 人遇难12 人失联。目前有关灾情正在进一步核实中。更多资讯请下载央视新闻客户端",
"createTime": 1722700586389
}
]

38
example.js Normal file
View File

@ -0,0 +1,38 @@
import { launch } from 'puppeteer';
import 'dotenv/config.js'
(async () => {
const browser = await launch({ headless: true, args: [`--window-size=1920,1080`], defaultViewport: { width: 1920, height: 1080 } });
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080 });
const dev = 'https://dev-dmp.meiguanjia.net/login';
const stging = 'https://boss.aizhb.net/login';
let current = '';
if (process.env.PROFILE === 'dev') {
current = dev;
} else if (process.env.PROFILE === 'stging') {
current = stging;
}
console.log(current);
console.log(process.env.ACCOUNT);
await page.goto(current);
await page.locator('#userName input').fill(process.env.ACCOUNT);
await page.locator('.forgot_box').click();
await page.waitForSelector('.modify_main');
await page.locator('#digitalCode input').fill('1');
await page.locator('#smsCode input').fill(process.env.SMS);
await page.locator('#newPassWord input').fill(process.env.PASSWORD);
await page.locator('#confirmPassWord input').fill(process.env.PASSWORD);
await page.locator('[type="submit"]').click();
await page.waitForSelector('.arco-message .arco-message-content', { visible: true });
const arcoMessage = await page.$eval('.arco-message .arco-message-content', node => node.innerHTML);
await page.screenshot({ path: 'resetPassword.png' });
console.log(arcoMessage);
page.on('console', msg => {
console.log('PAGE:', msg.text())
})
await browser.close();
})();

31
example2.js Normal file
View File

@ -0,0 +1,31 @@
import { launch } from 'puppeteer';
import fs from 'fs';
import 'dotenv/config.js'
import { setLocalStorage } from './utils/userUtils.js';
import { getDate } from './utils/businessDataUtil.js';
import { setMonthTime } from './utils/commnUtils.js'
(async () => {
const browser = await launch({ headless: true, args: [`--window-size=1920,1080`], defaultViewport: { width: 1920, height: 1080 } });
const page = await browser.newPage();
setLocalStorage(page, '.\\data\\user.json');
await page.goto('https://dev-dmp.meiguanjia.net/report/businessData');
// await page.goto('https://boss.aizhb.net/report/businessData');
await page.waitForSelector('.menu-list-second');
const childElements = await page.$$('.menu-list-second .menu-list-second-item');
await new Promise(r => setTimeout(r, 1000));
await childElements[1].click();
const str = await page.evaluate(node => node.textContent.trim(), childElements[1]);
console.log(str);
const file = './data/businessData.json';
fs.writeFileSync(file, '', 'utf-8');
await setMonthTime(page, '.arco-picker-start-time', '2024-05');
await getDate(page, fs, file);
console.log('========');
await browser.close();
})();

View File

@ -1,66 +0,0 @@
import { launch } from "puppeteer";
import "dotenv/config.js";
import { injectionCookie } from "../utils/userUtils.js";
import fs from "fs";
import dotenv from "dotenv";
dotenv.config();
(async () => {
const browser = await launch({
headless: false,
args: [`--window-size=1920,1080`],
defaultViewport: { width: 1920, height: 1080 },
});
const page = await browser.newPage();
page.on("console", msg => console.log("PAGE LOG", msg.text()));
page.on("error", error => console.error("PAGE error", error));
// 注入cookie
const webUrl = "https://www.zhihu.com/hot";
const cookieFileUrl = "./data/zhihu.json";
await injectionCookie(page, webUrl, cookieFileUrl);
const hotItems = await page.$$(".HotList-list .HotItem");
const hotText = new Array();
for (const hot in hotItems) {
if (Object.hasOwnProperty.call(hotItems, hot)) {
const element = hotItems[hot];
const h2Element = await element.$("h2");
const pElement = await element.$("p");
const title = h2Element != null ? await h2Element.evaluate(e => e.textContent) : "";
const excerpt = pElement != null ? await pElement.evaluate(e => e.textContent) : "";
const createTime = Date.now();
hotText.push({ title, excerpt, createTime });
}
}
fs.writeFileSync("./data/zhihuData.json", JSON.stringify(hotText, null, 2));
const url = process.env.URL;
console.log(process.env.URL);
try {
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(hotText, null, 2),
});
if (!response.ok) {
throw new Error(`Http error! status : ${response.status}`);
}
const responseData = await response.json();
console.log("Repsonse data", responseData);
} catch (error) {
console.error(error);
}
await browser.close();
})();

135
hlk.spec.js Normal file
View File

@ -0,0 +1,135 @@
import { launch, Locator } from 'puppeteer'; // v23.0.0 or later
import fs from 'fs';
(async () => {
const browser = await launch({
headless: false,
});
const page = await browser.newPage();
const timeout = 5000;
page.setDefaultTimeout(timeout);
{
const targetPage = page;
await targetPage.goto('https://hlk.meiguanjia.net/#/login');
}
{
const targetPage = page;
await Locator.race([targetPage.locator('input[placeholder="请输入您的手机号码')])
.setTimeout(timeout)
.click();
}
{
const targetPage = page;
await Locator.race([targetPage.locator('input[placeholder="请输入您的手机号码')])
.setTimeout(timeout)
.fill('17770720274');
}
{
const targetPage = page;
await Locator.race([targetPage.locator('input[placeholder="请输入登录密码')])
.setTimeout(timeout)
.click();
}
{
const targetPage = page;
await Locator.race([targetPage.locator('input[placeholder="请输入登录密码')])
.setTimeout(timeout)
.fill('a123456');
}
{
const targetPage = page;
await Locator.race([targetPage.locator('#agreement')])
.setTimeout(timeout)
.click();
}
{
const targetPage = page;
await Locator.race([targetPage.locator('.login-form-button')])
.setTimeout(timeout)
.click();
await new Promise((resolve) => setTimeout(resolve, 3000));
}
{
const targetPage = page;
targetPage.on('console', (msg) => {
for (let i = 0; i < msg.args().length; ++i) {
console.log(`${i}: ${msg.args()[i]}`);
}
});
const allData = await targetPage.evaluate(() => {
return new Promise((resolve, reject) => {
// 获取所有数据库列表
indexedDB
.databases()
.then((databases) => {
const allDatabasesData = [];
// 遍历所有数据库
const dbPromises = databases.map((db) => {
return new Promise((dbResolve, dbReject) => {
const request = indexedDB.open(db.name);
request.onsuccess = () => {
const database = request.result;
const transaction = database.transaction(database.objectStoreNames, 'readonly');
const dbData = { name: db.name, stores: {} };
// 遍历数据库中的每个对象存储
for (let storeName of database.objectStoreNames) {
const storeData = [];
const store = transaction.objectStore(storeName);
const cursorRequest = store.openCursor();
cursorRequest.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
storeData.push(cursor.value);
cursor.continue();
} else {
// 当遍历完所有数据时,将数据保存到 dbData 中
dbData.stores[storeName] = storeData;
if (
Object.keys(dbData.stores).length === database.objectStoreNames.length
) {
// 完成一个数据库的所有对象存储数据
dbResolve(dbData);
}
}
};
cursorRequest.onerror = (error) => {
dbReject(error);
};
}
};
request.onerror = (error) => {
dbReject(error);
};
});
});
// 等待所有数据库的数据获取完成
Promise.all(dbPromises)
.then((results) => {
resolve(results);
})
.catch(reject);
})
.catch(reject);
});
});
fs.writeFileSync('allData.json', JSON.stringify(allData, null, 2));
// console.log(allData[0].stores.keyvaluepairs); // 打印所有数据库的数据
}
// await browser.close();
})().catch((err) => {
console.error(err);
process.exit(1);
});

1
indexedDB.json Normal file

File diff suppressed because one or more lines are too long

1
localStorage.json Normal file

File diff suppressed because one or more lines are too long

25
login.js Normal file
View File

@ -0,0 +1,25 @@
import { launch } from 'puppeteer';
import fs from 'fs';
import 'dotenv/config.js';
(async () => {
const browser = await launch({ headless: true, args: [`--window-size=1920,1080`], defaultViewport: { width: 1920, height: 1080 } });
const page = await browser.newPage();
await page.goto('https://dev-dmp.meiguanjia.net/login');
// await page.goto('https://boss.aizhb.net/login');
await page.locator('#userName input').fill(process.env.ACCOUNT);
await page.locator('#passWord input').fill(process.env.PASSWORD);
await page.locator('[type="submit"]').click();
await page.waitForSelector('.arco-message .arco-message-content', { visible: true });
const arcoMessage = await page.$eval('.arco-message .arco-message-content', node => node.innerHTML);
console.log(arcoMessage);
await new Promise(r => setTimeout(r, 1000));
const localStorage = await page.evaluate(() => Object.assign({}, window.localStorage));
const importStorage = JSON.stringify(localStorage);
const file = './data/user.json';
fs.writeFileSync(file, importStorage, 'utf-8');
await browser.close();
})();

110
sethlk.spec.js Normal file
View File

@ -0,0 +1,110 @@
import puppeteer from 'puppeteer';
import { readFileSync } from 'fs';
(async () => {
// 读取 JSON 文件
const jsonData = JSON.parse(readFileSync('indexedDB.json', 'utf8'));
const browser = await puppeteer.launch({ headless: false });
// 获取当前的页面,通常是浏览器启动后的默认页面
const [page] = await browser.pages();
// 打开目标网页
await page.goto('https://hlk.meiguanjia.net'); // 替换为你的目标 URL
const localStorageData = JSON.parse(readFileSync('localStorage.json', 'utf8'));
await page.evaluate((data) => {
for (const key in data) {
localStorage.setItem(key, data[key]);
}
}, localStorageData);
console.log('set localStorage success');
await page.evaluate((jsonData) => {
return new Promise((resolve, reject) => {
// 使用 async 函数来处理异步操作
const processDatabase = async (database) => {
try {
// 打开 IndexedDB 数据库
const openRequest = indexedDB.open(database.databaseName, 2);
// 处理数据库版本升级
openRequest.onupgradeneeded = (event) => {
const db = event.target.result;
// 创建对象存储,如果不存在的话
if (!db.objectStoreNames.contains('keyvaluepairs')) {
db.createObjectStore('keyvaluepairs');
}
if (!db.objectStoreNames.contains('local-forage-detect-blob-support')) {
db.createObjectStore('local-forage-detect-blob-support');
}
};
// 处理数据库打开成功
openRequest.onsuccess = async (event) => {
const db = event.target.result;
const table = database.data;
const transaction = db.transaction(['keyvaluepairs'], 'readwrite');
const objectStore = transaction.objectStore('keyvaluepairs'); // 使用硬编码的存储名
console.log(table.value);
let completedOperations = 0;
const totalOperations = table.length;
// 使用 Promise.all 来确保所有的写入操作完成
const writeOperations = table.map((item, index) => {
return new Promise((innerResolve, innerReject) => {
const addObject = objectStore.put(item.value, item.key);
addObject.onsuccess = () => {
console.log('数据添加成功', item.key);
completedOperations++;
// 如果所有操作完成,调用 resolve
if (completedOperations === totalOperations) {
innerResolve('数据写入成功');
}
};
addObject.onerror = (event) => {
console.error('数据添加失败:', event.target.error);
innerReject('数据添加失败');
};
});
});
// 等待所有写入操作完成
try {
await Promise.all(writeOperations);
console.log('所有数据写入完成');
resolve('所有数据写入完成');
} catch (error) {
reject('数据写入失败');
}
};
// 错误处理
openRequest.onerror = (event) => {
console.error('数据库打开失败:', event.target.error);
reject('数据库打开失败');
};
} catch (error) {
reject('数据库操作失败: ' + error);
}
};
// 遍历所有数据库
Promise.all(jsonData.map((database) => processDatabase(database)))
.then(() => resolve('所有数据库操作完成'))
.catch((error) => reject('操作失败: ' + error));
});
}, jsonData); // 将 jsonData 传递到浏览器上下文中
console.log('end');
await new Promise((resolve) => setTimeout(resolve, 2000));
await page.goto('https://hlk.meiguanjia.net');
// await
// await browser.close();
})();

85
testhlk.spec.js Normal file
View File

@ -0,0 +1,85 @@
import puppeteer, { launch, Locator } from 'puppeteer'; // v23.0.0 or later
import fs from 'fs';
import { resolve } from 'path';
import { writeIndexedDB, readIndexedDB } from './utils.js';
(async () => {
const browser = await launch({
headless: false,
});
const page = await browser.newPage();
const timeout = 5000;
page.setDefaultTimeout(timeout);
{
const targetPage = page;
await targetPage.goto('https://hlk.meiguanjia.net/#/login');
}
{
const targetPage = page;
await Locator.race([targetPage.locator('input[placeholder="请输入您的手机号码')])
.setTimeout(timeout)
.click();
}
{
const targetPage = page;
await Locator.race([targetPage.locator('input[placeholder="请输入您的手机号码')])
.setTimeout(timeout)
.fill('17770720274');
}
{
const targetPage = page;
await Locator.race([targetPage.locator('input[placeholder="请输入登录密码')])
.setTimeout(timeout)
.click();
}
{
const targetPage = page;
await Locator.race([targetPage.locator('input[placeholder="请输入登录密码')])
.setTimeout(timeout)
.fill('a123456');
}
{
const targetPage = page;
await Locator.race([targetPage.locator('#agreement')])
.setTimeout(timeout)
.click();
}
{
const targetPage = page;
await Locator.race([targetPage.locator('.login-form-button')])
.setTimeout(timeout)
.click();
await new Promise((resolve) => setTimeout(resolve, 3000));
}
{
const targetPage = page;
targetPage.on('console', (msg) => {
for (let i = 0; i < msg.args().length; ++i) {
console.log(`${msg.args()[i]}`);
}
});
// 获取浏览器中的 IndexedDB 数据
const result = await page.evaluate(async (readIndexedDBFnString) => {
// 使用 eval() 执行传入的函数代码
eval(readIndexedDBFnString);
return await readIndexedDB();
// const readIndexedDBFn = new Function('return ' + readIndexedDBFnString)();
// return await readIndexedDBFn();
// 调用传入的函数并等待其返回结果
}, readIndexedDB.toString());
const localStorageData = await page.evaluate(() => {
return JSON.stringify(localStorage); // 将 localStorage 转换为对象
});
fs.writeFileSync('./indexedDB.json', JSON.stringify(result));
fs.writeFileSync('./localStorage.json', localStorageData);
}
await browser.close();
})().catch((err) => {
console.error(err);
process.exit(1);
});

17
uselogin.js Normal file
View File

@ -0,0 +1,17 @@
import { launch } from 'puppeteer';
import fs from 'fs';
import 'dotenv/config.js';
import { setLocalStorage } from './utils/userUtils.js';
(async () => {
const browser = await launch({ headless: false, devtools: true, args: [`--window-size=1920,1080`], defaultViewport: { width: 1920, height: 1080 } });
const page = await browser.newPage();
await page.goto('https://dev-dmp.meiguanjia.net/login');
await setLocalStorage(page, 'user.json');
await page.goto('https://dev-dmp.meiguanjia.net/report/businessData');
await browser.close();
})();

125
utils.js Normal file
View File

@ -0,0 +1,125 @@
export async function readIndexedDB() {
const databases = await indexedDB.databases();
const allData = [];
for (const db of databases) {
const databaseName = db.name;
// 打开数据库
const request = indexedDB.open(databaseName);
const databaseData = await new Promise((resolve, reject) => {
request.onsuccess = (event) => {
const db = event.target.result;
const transaction = db.transaction(db.objectStoreNames, 'readonly');
const objectStore = transaction.objectStore(db.objectStoreNames[0]);
const cursorRequest = objectStore.openCursor();
const storeData = [];
cursorRequest.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
storeData.push({ key: cursor.key, value: cursor.value });
cursor.continue();
} else {
resolve(storeData); // 执行 resolve返回数据
}
};
cursorRequest.onerror = (event) => {
reject(event.target.error); // 发生错误时 reject
};
};
request.onerror = (event) => {
reject(event.target.error); // 发生错误时 reject
};
});
// 将数据库数据存入 allData
allData.push({
databaseName,
data: databaseData,
});
}
return allData;
}
export async function writeIndexedDB(jsonData) {
return new Promise((resolve, reject) => {
// 使用 async 函数来处理异步操作
const processDatabase = async (database) => {
try {
// 打开 IndexedDB 数据库
const openRequest = indexedDB.open(database.databaseName, 2);
// 处理数据库版本升级
openRequest.onupgradeneeded = (event) => {
const db = event.target.result;
// 创建对象存储,如果不存在的话
if (!db.objectStoreNames.contains('keyvaluepairs')) {
db.createObjectStore('keyvaluepairs');
}
if (!db.objectStoreNames.contains('local-forage-detect-blob-support')) {
db.createObjectStore('local-forage-detect-blob-support');
}
};
// 处理数据库打开成功
openRequest.onsuccess = async (event) => {
const db = event.target.result;
const table = database.data;
const transaction = db.transaction(['keyvaluepairs'], 'readwrite');
const objectStore = transaction.objectStore('keyvaluepairs'); // 使用硬编码的存储名
console.log(table.value);
let completedOperations = 0;
const totalOperations = table.length;
// 使用 Promise.all 来确保所有的写入操作完成
const writeOperations = table.map((item, index) => {
return new Promise((innerResolve, innerReject) => {
const addObject = objectStore.put(item.value, item.key);
addObject.onsuccess = () => {
console.log('数据添加成功', item.key);
completedOperations++;
// 如果所有操作完成,调用 resolve
if (completedOperations === totalOperations) {
innerResolve('数据写入成功');
}
};
addObject.onerror = (event) => {
console.error('数据添加失败:', event.target.error);
innerReject('数据添加失败');
};
});
});
// 等待所有写入操作完成
try {
await Promise.all(writeOperations);
console.log('所有数据写入完成');
resolve('所有数据写入完成');
} catch (error) {
reject('数据写入失败');
}
};
// 错误处理
openRequest.onerror = (event) => {
console.error('数据库打开失败:', event.target.error);
reject('数据库打开失败');
};
} catch (error) {
reject('数据库操作失败: ' + error);
}
};
// 遍历所有数据库
Promise.all(jsonData.map((database) => processDatabase(database)))
.then(() => resolve('所有数据库操作完成'))
.catch((error) => reject('操作失败: ' + error));
});
}

54
utils/businessDataUtil.js Normal file
View File

@ -0,0 +1,54 @@
/**
*
* @param {Page} page
* @param {fs} fs
* @param {String} file 存储文件位置
*/
export async function getDate(page, fs, file) {
const its = new Map();
await new Promise(r => setTimeout(r, 2000));
await page.waitForSelector('.ai_custome');
const aiCustome = await page.$$('.ai_custome .ai_custome_item');
if (aiCustome.length > 0) {
for (const iterator of aiCustome) {
const key = await iterator.$('span');
const value = await iterator.$('div');
const keyStr = await page.evaluate(element => element.textContent.trim(), key);
const valueStr = await page.evaluate(element => element.textContent.trim(), value);
its.set(keyStr, valueStr);
}
} else {
console.log('.ai_custome_item not found');
}
const elementHandle = await page.waitForSelector('.bi_warp iframe');
const frame = await elementHandle.contentFrame();
await frame.waitForSelector('#label-content');
const items = await frame.$$('#label-content');
if (items.length > 0) {
for (const e of items) {
const key = await e.$('span p');
const value = await e.$('span span');
const keyStr = await frame.evaluate(element => element.textContent.trim(), key);
const valueStr = await frame.evaluate(element => element.textContent.trim(), value);
its.set(keyStr, valueStr);
}
} else {
console.log('#label-content not found in the iframe');
}
const convert = {};
for (const [key, value] of its) {
convert[key] = value;
}
console.log(convert);
const importStorage = JSON.stringify(convert, null, 2);
fs.appendFileSync(file, importStorage, 'utf-8');
}

80
utils/commnUtils.js Normal file
View File

@ -0,0 +1,80 @@
/**
* 设置月报时间
* @param {Page} page
* @param {String} element
* @param {String} timeContent
*/
export async function setMonthTime(page, element, timeContent) {
await new Promise(r => setTimeout(r, 2000));
const time = await page.$(element);
await time.click({ clickCount: 3 });
await time.type(timeContent, { delay: 100 });
}
/**
*
* @param {Page} page
* @param {Number} dismensionNumber
*/
export async function changeTimeDimension(page, dismensionNumber) {
const timeDimension = [
'日报',
'周报',
'月报',
'自定义'
];
let rb = await page.$('.arco-space-item .arco-select-view-value');
let s = await page.evaluate(node => node.textContent.trim(), rb);
await rb.click();
const timeMap = new Map();
rb = await page.$$('.arco-select-dropdown-list .arco-select-option');
for (const iterator of rb) {
s = await page.evaluate(node => node.textContent.trim(), iterator)
timeMap.set(s, iterator);
}
console.log(timeDimension[dismensionNumber]);
await timeMap.get(timeDimension[dismensionNumber]).click();
}
/**
*
* @param {Page} page
* @param {fs} fs
* @param {String} file 存储文件位置
*/
export async function getDate(page, fs, file) {
const its = new Map();
await new Promise(r => setTimeout(r, 2000));
const elementHandle = await page.waitForSelector('.bi_warp iframe');
const frame = await elementHandle.contentFrame();
await frame.waitForSelector('#label-content');
const items = await frame.$$('#label-content');
if (items.length > 0) {
for (const e of items) {
const key = await e.$('span p');
const value = await e.$('span span');
const keyStr = await frame.evaluate(element => element.textContent.trim(), key);
const valueStr = await frame.evaluate(element => element.textContent.trim(), value);
its.set(keyStr, valueStr);
}
} else {
console.log('#label-content not found in the iframe');
}
const convert = {};
for (const [key, value] of its) {
convert[key] = value;
}
console.log(convert);
const importStorage = JSON.stringify(convert, null, 2);
fs.appendFileSync(file, importStorage, 'utf-8');
}

View File

@ -1,38 +1,20 @@
import fs from "fs";
import fs from 'fs';
/**
* 设置页面的LocalStorage
* @param {import('puppeteer').Page} page
* @param {*} page
* @param {String} file 用户信息
*/
export async function setLocalStorage(page, file) {
const outputLocalStorge = fs.readFileSync(file, "utf-8");
const outputLocalStorge = fs.readFileSync(file, 'utf-8');
let localStorageTest = JSON.parse(outputLocalStorge);
// 设置页面的localStorage
await page.evaluateOnNewDocument(localStorageTest => {
localStorage.clear();
localStorage.setItem("merchant_access_token", localStorageTest.merchant_access_token);
localStorage.setItem("merchant_refresh_token", localStorageTest.merchant_refresh_token);
localStorage.setItem("merchant_login_data", localStorageTest.merchant_login_data);
localStorage.setItem("merchant_metadata_data", localStorageTest.merchant_metadata_data);
localStorage.setItem('merchant_access_token', localStorageTest.merchant_access_token);
localStorage.setItem('merchant_refresh_token', localStorageTest.merchant_refresh_token);
localStorage.setItem('merchant_login_data', localStorageTest.merchant_login_data);
localStorage.setItem('merchant_metadata_data', localStorageTest.merchant_metadata_data);
}, localStorageTest);
console.log("set success");
}
/**
* @param {Page} page
* @param {String} webUrl 网站
* @param {String} cookieFile cookie地址Url
*/
export async function injectionCookie(page, webUrl, cookieFile) {
try {
await page.goto(webUrl);
const cookies = JSON.parse(fs.readFileSync(cookieFile, "utf-8"));
await page.setCookie(...cookies);
await page.goto(webUrl);
} catch (error) {
console.error(error);
}
}