nodejs_chromium 1.1.15 → 1.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,10 +1,18 @@
1
- require('nodejs_patch');
2
- const puppeteer = require("puppeteer");
3
- const chrome = require("./src/chrome.js");
4
- const { exec } = require("child_process");
1
+ import 'nodejs_patch';
2
+ import puppeteer from "puppeteer";
3
+ import {KnownDevices} from "puppeteer";
4
+ import {exec} from "child_process";
5
+ import fs from "fs";
6
+ import chrome from "./src/chrome.js";
7
+
8
+ // const puppeteer = require("puppeteer");
9
+ // const { KnownDevices } = require("puppeteer");
10
+ // const chrome = require("./src/chrome.js");
11
+ // const { exec } = require("child_process");
12
+
5
13
  global.__UA__ = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36';
6
14
  const mob_ua = 'Mozilla/5.0 (Linux; Android 13;Build/TKQ1.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36';
7
- const fs = require("fs");
15
+ // const fs = require("fs");
8
16
 
9
17
 
10
18
  async function NormalClose(path) {
@@ -16,13 +24,17 @@ async function NormalClose(path) {
16
24
  */
17
25
  let file = `${path}/Default/Preferences`;
18
26
  // console.log({file});
19
- if (!fs.existsSync(file)) return;
27
+ if (!fs.existsSync(file)) {
28
+ console.log(file, 'NotExists')
29
+ return;
30
+ }
20
31
  let text = fs.readFileSync(file);
21
32
  let json = JSON.parse(text);
22
33
  json.credentials_enable_service = false; //新增项,禁止保存密码
23
34
  json.profile.exit_type = 'Normal'; //原值可能为:Crashed
24
35
  // console.log('json.profile.exit_type', json.profile.exit_type);
25
36
  fs.writeFileSync(file, JSON.stringify(json));
37
+ console.log(file, json.profile.exit_type)
26
38
  }
27
39
 
28
40
 
@@ -99,7 +111,7 @@ async function newBrowser(params) {
99
111
 
100
112
  const browser = await puppeteer.launch(option);
101
113
 
102
- await NormalClose(option.userDataDir); //禁止显示【要恢复页面吗?chromium 未正确关闭。】
114
+ // await NormalClose(option.userDataDir); //禁止显示【要恢复页面吗?chromium 未正确关闭。】
103
115
 
104
116
  return browser;
105
117
  }
@@ -126,6 +138,7 @@ async function newChrome(params) {
126
138
  cookies = null, //若cookies=false,则不处理cookies,不指定则由chrome处理,若=文件路径
127
139
  abort = [], //要禁止的类型,常见["font","image","ping","stylesheet","document","fetch","script","xhr"]
128
140
  headers = {},
141
+ device = null
129
142
  } = params;
130
143
 
131
144
  const browser = await newBrowser(params);
@@ -136,11 +149,14 @@ async function newChrome(params) {
136
149
  // const version = await browser.version();
137
150
  const page = (await browser.pages())[0];
138
151
  // const page = await browser.newPage();
139
- await page.setRequestInterception(true); //允许拦截
152
+ // await page.setRequestInterception(true); //允许拦截
140
153
 
141
154
  if (ua) await page.setUserAgent(ua);
142
- else if (mobile) await page.setUserAgent(mob_ua);
155
+ else if (mobile) {
156
+ await page.emulate(device || KnownDevices['iPhone 15 Pro']);
157
+ }
143
158
  else await page.setUserAgent(__UA__);
159
+ if (device) await page.emulate(device); //必须要放在setUserAgent后面
144
160
 
145
161
  await page.evaluateOnNewDocument(() => {
146
162
  const newProto = navigator.__proto__;
@@ -149,7 +165,7 @@ async function newChrome(params) {
149
165
  });
150
166
 
151
167
  if (cookies !== false) cookies = `runtime/.cache/${id}/cookies.json`;
152
- const pageOption = { cookies, visible, abort, headers };
168
+ const pageOption = { cookies, visible, abort, headers, device };
153
169
  return new chrome(browser, page, pageOption);
154
170
  }
155
171
  catch (err) {
@@ -192,4 +208,4 @@ async function checkInstall(install = false) {
192
208
  }
193
209
 
194
210
 
195
- module.exports = { newChrome, checkInstall }
211
+ export default { newChrome, checkInstall }
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "nodejs_chromium",
3
- "version": "1.1.15",
3
+ "version": "1.1.18",
4
+ "type": "module",
4
5
  "description": "for pupeteer chromium",
5
6
  "main": "index.js",
6
7
  "scripts": {
7
8
  "test": "echo \"Error: no test specified\" && exit 1"
8
9
  },
9
10
  "dependencies": {
10
- "nodejs_patch": ">1.0.5",
11
+ "nodejs_patch": ">1.0.20",
11
12
  "puppeteer": ">22.6.0"
12
13
  },
13
14
  "author": "laoCC",
package/src/chrome.js CHANGED
@@ -1,7 +1,8 @@
1
- const fs = require("fs");
2
- const Cookies = require("./cookies");
3
- const { URL } = require('url');
4
-
1
+ import fs from "fs";
2
+ import { URL } from "url";
3
+ import Cookies from "./cookies.js";
4
+ // const Cookies = require("./cookies");
5
+ // const { URL } = require('url');
5
6
 
6
7
  /**
7
8
  *
@@ -12,15 +13,17 @@ const { URL } = require('url');
12
13
  *
13
14
  * @type {exports}
14
15
  */
15
- module.exports = class {
16
+ export default class {
16
17
  browser = void 0;
17
18
  page = void 0;
18
19
  responseCall = void 0;
19
20
  requestCall = void 0;
20
21
  cookies = void 0;
21
22
  options = void 0;
23
+ device = void 0;
22
24
  isFrame = false; //是不是在iFrame中
23
25
  visible = false; //是否可见,也就是有没有启动窗口
26
+ resIndex = 0; //当前窗口经过response的序号
24
27
 
25
28
  constructor(browser, page, options, isFrame = false) {
26
29
  this.browser = browser;
@@ -28,28 +31,78 @@ module.exports = class {
28
31
  this.options = options;
29
32
  this.cookies = new Cookies(page, options.cookies);
30
33
  this.visible = !!options.visible;
34
+ this.device = options.device;
31
35
  this.isFrame = !!isFrame;
32
36
  this.doListening(options);
33
37
  }
34
38
 
35
- request(call) {
39
+ /**
40
+ * 设置拦截
41
+ * 如果只是要读取cookies这些信息而不拦截处理,只需调用interception
42
+ *
43
+ * @param call
44
+ * @returns {Promise<exports>}
45
+ */
46
+ async request(call) {
47
+
48
+ if (call === true) {
49
+ //等同于this.interception(true)
50
+ await this.page.setRequestInterception(true); //允许拦截
51
+ this.page.interception = true;
52
+ this.requestCall = null;
53
+ return this;
54
+
55
+ }
56
+ else if (call === false) {
57
+ //等同于this.interception(false)
58
+ await this.page.setRequestInterception(false); //关闭允许拦截
59
+ this.page.interception = false;
60
+ this.requestCall = null;
61
+ return this;
62
+
63
+ }
64
+
65
+ await this.page.setRequestInterception(true); //允许拦截
66
+ this.page.interception = true;
36
67
  this.requestCall = call;
37
68
  return this;
38
69
  }
39
70
 
71
+
72
+ /**
73
+ * 设置是否允许拦截
74
+ *
75
+ * @param val
76
+ * @returns {Promise<exports>}
77
+ */
78
+ async interception(val = true) {
79
+ await this.page.setRequestInterception(val);
80
+ this.page.interception = val;
81
+ return this;
82
+ }
83
+
84
+
40
85
  response(call) {
41
86
  this.responseCall = call;
42
87
  return this;
43
88
  }
44
89
 
90
+ newPage(device = null) {
91
+ return this.clone(device);
92
+ }
93
+
45
94
  /**
46
95
  * 重新在当前浏览器创建新窗口
47
96
  */
48
- async clone() {
97
+ async clone(device = null) {
49
98
  try {
50
99
  const page = await this.browser.newPage();
51
100
  await page.setBypassCSP(true); //绕过页面的内容安全策略
52
- await page.setRequestInterception(true); //允许拦截
101
+ // await page.setRequestInterception(true); //允许拦截
102
+
103
+ if (device) await page.emulate(device);
104
+ else if (this.options.device) await page.emulate(this.options.device);
105
+
53
106
  await page.evaluateOnNewDocument(() => {
54
107
  const newProto = navigator.__proto__;
55
108
  delete newProto.webdriver; //删除 navigator.webdriver字段
@@ -108,10 +161,10 @@ module.exports = class {
108
161
  /**
109
162
  * 这必须放在已经打开过这个URL之后
110
163
  */
111
- waitForFrame() {
164
+ waitForFrame(name = 'Test') {
112
165
  try {
113
166
  this.page.waitForFrame(async frame => {
114
- return frame.name() === 'Test';
167
+ return await frame.name() === name;
115
168
  });
116
169
  return this;
117
170
  }
@@ -127,7 +180,7 @@ module.exports = class {
127
180
  async waitFrame(urlKey, timeout = 5000) {
128
181
  try {
129
182
  return await this.page.waitForFrame(async frame => {
130
- return frame.url().indexOf(urlKey) > 0;
183
+ return frame.url().includes(urlKey);
131
184
  }, { timeout });
132
185
  }
133
186
  catch (e) {
@@ -137,6 +190,7 @@ module.exports = class {
137
190
 
138
191
  /**
139
192
  * 按tag创建当前窗口中的某个iFrame
193
+ *
140
194
  * @param {Object} tag
141
195
  */
142
196
  async iframe(tag) {
@@ -245,6 +299,21 @@ module.exports = class {
245
299
  }
246
300
  }
247
301
 
302
+
303
+ /**
304
+ * 获取部分或全部HTML
305
+ * @param {Object} obj
306
+ */
307
+ async evaluate(obj, callback) {
308
+ try {
309
+ return await this.page.evaluate(callback, obj);
310
+ }
311
+ catch (e) {
312
+ console.log('[chrome.evaluate.Error]', e.message);
313
+ }
314
+ }
315
+
316
+
248
317
  /**
249
318
  * 获取部分或全部HTML
250
319
  * @param {Object} obj
@@ -291,7 +360,7 @@ module.exports = class {
291
360
  return this;
292
361
  }
293
362
  catch (e) {
294
- console.log('[chrome.text.Error]', e.message);
363
+ console.log('[chrome.display.Error]', [tag, e.message]);
295
364
  }
296
365
  }
297
366
 
@@ -305,21 +374,19 @@ module.exports = class {
305
374
  */
306
375
  async elements(tag1, tag2, call) {
307
376
  try {
377
+ let has = await this.wait(tag, 2, 2);
378
+ if (!has) return null;
308
379
 
309
- const div = await this.page.$(tag1);
310
- if (!div) {
311
- throw new Error(`${tag1} not exists`);
312
- }
313
380
  let index = 0;
314
- for (const elm of (await div.$$(tag2))) {
315
- const html = await elm.evaluate(node => node.outerHTML);
316
- const text = await elm.evaluate(node => node.innerHTML);
317
- call(elm, { html, text, index: index++ });
381
+ for (const ele of (await div.$$(tag2))) {
382
+ const html = await ele.evaluate(node => node.innerHTML);
383
+ const text = await ele.evaluate(node => node.innerText);
384
+ await call(ele, { html, text, index: index++ });
318
385
  }
319
386
 
320
387
  }
321
388
  catch (e) {
322
- console.log('[chrome.elements.Error]', e.message)
389
+ console.log('[chrome.elements.Error]', [tag1, tag2, e.message])
323
390
  }
324
391
  }
325
392
 
@@ -334,24 +401,23 @@ module.exports = class {
334
401
  async search(tag1, tag2, call) {
335
402
  return await new Promise(async (resolve) => {
336
403
  try {
404
+ let has = await this.wait(tag, 2, 2);
405
+ if (!has) return {};
337
406
 
338
- const div = await this.page.$(tag1);
339
- if (!div) {
340
- throw new Error(`${tag1} not exists`);
341
- }
342
407
  let index = 0;
343
408
  for (const ele of (await div.$$(tag2))) {
344
409
  index++;
345
- const html = await ele.evaluate(node => node.outerHTML);
346
- const text = await ele.evaluate(node => node.innerHTML);
347
- let val = call(ele, { html, text, index });
410
+ const html = await ele.evaluate(node => node.innerHTML);
411
+ const text = await ele.evaluate(node => node.innerText);
412
+ let val = await call(ele, { html, text, index });
348
413
  if (val === true) return resolve({ success: true, ele, html, text, index });
349
414
  }
350
- resolve({ success: false });
415
+ resolve({ success: false, index });
351
416
 
352
417
  }
353
418
  catch (e) {
354
- console.log('[chrome.elements.Error]', e.message)
419
+ console.log('[chrome.search.Error]', [tag1, tag2, e.message])
420
+ return {};
355
421
  }
356
422
  });
357
423
 
@@ -373,11 +439,14 @@ module.exports = class {
373
439
  */
374
440
  async element(tag, selector = false) {
375
441
  try {
442
+ let has = await this.wait(tag, 2, 2);
443
+ if (!has) return null;
444
+
376
445
  if (selector) return await this.page.querySelector(tag);
377
446
  return await this.page.$(tag);
378
447
  }
379
448
  catch (e) {
380
- console.log('[chrome.element.Error]', e.message);
449
+ console.log('[chrome.element.Error]', [tag, e.message]);
381
450
  return null;
382
451
  }
383
452
  }
@@ -437,9 +506,6 @@ module.exports = class {
437
506
  }
438
507
  }
439
508
 
440
- /**
441
- * delay=每键入一个字符延迟毫秒
442
- */
443
509
  async clear(el) {
444
510
  try {
445
511
  await this.page.$eval(el, ele => ele.value = '');
@@ -480,12 +546,12 @@ module.exports = class {
480
546
  */
481
547
  async click(el, option = {}) {
482
548
  try {
549
+
483
550
  let { delay = 100, count = 1, x = 6, y = 3 } = option;
484
551
  return await this.page.click(el, { delay, count, offset: { x, y } });
485
- // return this;
486
552
  }
487
553
  catch (e) {
488
- console.log('[chrome.click.Error]', e.message);
554
+ console.log('[chrome.click.Error]', el, e.message);
489
555
  }
490
556
  }
491
557
 
@@ -640,59 +706,84 @@ module.exports = class {
640
706
  return this;
641
707
  }
642
708
 
643
- delSkipType(...item) {
709
+ delSkipType(item) {
644
710
  this.skipTypes = this.skipTypes.del(...item);
645
711
  return this;
646
712
  }
647
713
 
714
+
648
715
  async parseResponse(response) {
649
716
  // const response = await this.page.waitForResponse(res => res);
650
-
651
717
  const value = {};
652
- const request = await response.request();
653
- const headers = await response.headers();
654
- value.method = await request.method();
655
- if (value.method === 'OPTIONS') return;
656
-
657
- value.type = await request.resourceType();
658
- // value.redirect = await response.redirectURL();
659
- if (value.type === 'fetch') value.type = 'xhr';
660
- if (value.type === 'xhr') value.type = 'AJAX';
661
- value.url = await response.url();
662
- value.headers = { request: request.headers(), response: headers };
663
- value.domain = (new URL(value.url))['host'];
664
- value.content = headers['content-type'];
665
- value.length = headers['content-length'];
666
- value.status = await response.status();
667
- value.ok = await response.ok();
668
- value.datetime = (new Date(headers['date'])).date('yyyy-mm-dd hh:ii:ss');
669
- // value.headers = headers;
670
- if (headers['server']) value.server = headers['server'];
671
- if (headers['set-cookie']) value.cookies = await this.cookies.parse(headers['set-cookie']);
672
- value.remote = await response.remoteAddress(); //目标服务器
673
- if (value.status === 301 || value.status === 302) return value;
674
-
675
- // if (['image', 'font', 'other', 'script', 'stylesheet', 'document', 'ping'].has(value.type)) return value;
676
- // if (['image', 'font', 'other', 'script', 'stylesheet', 'ping'].includes(value.type)) return value;
677
- if (this.skipTypes.includes(value.type)) return value;
678
-
679
- if (value.content) {
680
- if (value.content.startsWith('application/vnd')) return value;
681
- if (value.content.startsWith('application/xml')) return value;
682
- if (value.content.startsWith('text/css')) return value;
683
- }
684
-
685
- value.post = await request.postData();
686
- if (value.post) value.post = value.post.toString();
718
+
719
+ try {
720
+
721
+ const request = await response.request();
722
+ const headers = await response.headers();
723
+
724
+ value.method = await request.method();
725
+ if (value.method === 'OPTIONS') return;
726
+ // if (value.method === 'DELETE') return;
727
+ value.index = this.resIndex++
728
+
729
+ value.type = await request.resourceType();
730
+ // value.redirect = await response.redirectURL();
731
+ if (value.type === 'fetch') value.type = 'xhr';
732
+ if (value.type === 'xhr') value.type = 'AJAX';
733
+ value.url = await response.url();
734
+ value.headers = { request: request.headers(), response: headers };
735
+ value.domain = (new URL(value.url))['host'];
736
+ value.content = headers['content-type'];
737
+ value.length = headers['content-length'];
738
+ value.status = await response.status();
739
+ value.ok = await response.ok();
740
+ value.datetime = (new Date(headers['date'])).date('yyyy-mm-dd hh:ii:ss');
741
+ if (headers['server']) value.server = headers['server'];
742
+ if (headers['set-cookie']) value.cookies = await this.cookies.parse(headers['set-cookie']);
743
+ value.remote = await response.remoteAddress(); //目标服务器
744
+ if (value.status === 301 || value.status === 302) return value;
745
+ if (this.skipTypes.includes(value.type)) return value;
746
+
747
+ value.post = await request.postData();
748
+ if (value.post) value.post = value.post.toString();
749
+
750
+ }
751
+ catch (e) {
752
+ const err = e.parse();
753
+ value.error = err.message;
754
+ }
755
+
756
+ try {
757
+
758
+ if (value.content.includes('text/html')) {
759
+ const buffer = await response.buffer();
760
+ value.html = buffer.toString();
761
+ return value;
762
+ }
763
+
764
+ if (value.content) {
765
+ if (value.content.includes('application/vnd')) return value;
766
+ if (value.content.includes('application/xml')) return value;
767
+ if (value.content.includes('application/javascript')) return value;
768
+ if (value.content.includes('text/css')) return value;
769
+ if (value.content.includes('text/plain')) return value;
770
+ }
771
+
772
+ }
773
+ catch (e) {
774
+ const err = e.parse();
775
+ value.error = err.message;
776
+ }
687
777
 
688
778
  try {
689
779
  const buffer = await response.buffer();
690
780
  value.response = buffer.toString();
781
+ if (!/^[\[\{].+[\]\}]$/.test(value.response)) return value;
691
782
  value.json = JSON.parse(value.response);
692
783
  }
693
784
  catch (e) {
694
785
  const err = e.parse();
695
- value.json = err.message;
786
+ value.error = err.message;
696
787
  }
697
788
 
698
789
  return value;
@@ -707,6 +798,8 @@ module.exports = class {
707
798
  async doListening(options) {
708
799
 
709
800
  this.page.on('request', async (request) => {
801
+ if (!this.page.interception) return;
802
+
710
803
  const host = this.host(request.url());
711
804
  const headers = request.headers();
712
805
  if (headers.cookie) this.cookies.request(headers.cookie, host);
@@ -714,6 +807,7 @@ module.exports = class {
714
807
  if (this.requestCall) {
715
808
  const run = await this.requestCall(request);
716
809
  if (run === false) return request.abort();
810
+ if (run === true) return;
717
811
  }
718
812
 
719
813
  const rType = request.resourceType();
package/src/cookies.js CHANGED
@@ -1,6 +1,6 @@
1
- const fs = require("fs");
1
+ import fs from "fs";
2
2
 
3
- module.exports = class {
3
+ export default class {
4
4
  page = void 0;
5
5
  file = void 0;
6
6
  cookies = [];