nodejs_chromium 1.1.15 → 1.1.16

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