@jackwener/opencli 1.7.5 → 1.7.7
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/README.md +22 -10
- package/README.zh-CN.md +18 -9
- package/cli-manifest.json +401 -11
- package/clis/51job/company.js +125 -0
- package/clis/51job/detail.js +108 -0
- package/clis/51job/hot.js +55 -0
- package/clis/51job/search.js +79 -0
- package/clis/51job/utils.js +302 -0
- package/clis/51job/utils.test.js +69 -0
- package/clis/bilibili/video.js +68 -0
- package/clis/bilibili/video.test.js +132 -0
- package/clis/chatgpt/image.js +1 -1
- package/clis/deepseek/ask.js +37 -11
- package/clis/deepseek/ask.test.js +165 -0
- package/clis/deepseek/utils.js +192 -24
- package/clis/deepseek/utils.test.js +145 -0
- package/clis/gemini/image.js +1 -1
- package/clis/instagram/download.js +1 -1
- package/clis/jianyu/search.js +139 -3
- package/clis/jianyu/search.test.js +25 -0
- package/clis/jianyu/shared/procurement-detail.js +15 -0
- package/clis/jianyu/shared/procurement-detail.test.js +12 -0
- package/clis/twitter/likes.js +3 -2
- package/clis/twitter/search.js +4 -2
- package/clis/twitter/search.test.js +4 -0
- package/clis/twitter/shared.js +35 -2
- package/clis/twitter/shared.test.js +96 -0
- package/clis/twitter/thread.js +3 -1
- package/clis/twitter/timeline.js +3 -2
- package/clis/twitter/tweets.js +219 -0
- package/clis/twitter/tweets.test.js +125 -0
- package/clis/web/read.js +25 -5
- package/clis/web/read.test.js +76 -0
- package/clis/weread/ai-outline.js +170 -0
- package/clis/weread/ai-outline.test.js +83 -0
- package/clis/weread/book.js +57 -44
- package/clis/weread/commands.test.js +24 -0
- package/clis/xiaoyuzhou/podcast-episodes.js +2 -2
- package/clis/xiaoyuzhou/podcast-episodes.test.js +78 -0
- package/clis/youtube/channel.js +35 -0
- package/dist/src/browser/analyze.d.ts +103 -0
- package/dist/src/browser/analyze.js +230 -0
- package/dist/src/browser/analyze.test.d.ts +1 -0
- package/dist/src/browser/analyze.test.js +164 -0
- package/dist/src/browser/article-extract.d.ts +57 -0
- package/dist/src/browser/article-extract.e2e.test.d.ts +1 -0
- package/dist/src/browser/article-extract.e2e.test.js +105 -0
- package/dist/src/browser/article-extract.js +169 -0
- package/dist/src/browser/article-extract.test.d.ts +1 -0
- package/dist/src/browser/article-extract.test.js +94 -0
- package/dist/src/browser/base-page.d.ts +13 -3
- package/dist/src/browser/base-page.js +35 -25
- package/dist/src/browser/cdp.d.ts +1 -0
- package/dist/src/browser/cdp.js +23 -5
- package/dist/src/browser/compound.d.ts +59 -0
- package/dist/src/browser/compound.js +112 -0
- package/dist/src/browser/compound.test.d.ts +1 -0
- package/dist/src/browser/compound.test.js +175 -0
- package/dist/src/browser/dom-snapshot.d.ts +7 -0
- package/dist/src/browser/dom-snapshot.js +76 -3
- package/dist/src/browser/dom-snapshot.test.js +65 -0
- package/dist/src/browser/extract.d.ts +69 -0
- package/dist/src/browser/extract.js +132 -0
- package/dist/src/browser/extract.test.d.ts +1 -0
- package/dist/src/browser/extract.test.js +129 -0
- package/dist/src/browser/find.d.ts +76 -0
- package/dist/src/browser/find.js +179 -0
- package/dist/src/browser/find.test.d.ts +1 -0
- package/dist/src/browser/find.test.js +120 -0
- package/dist/src/browser/html-tree.d.ts +75 -0
- package/dist/src/browser/html-tree.js +112 -0
- package/dist/src/browser/html-tree.test.d.ts +1 -0
- package/dist/src/browser/html-tree.test.js +181 -0
- package/dist/src/browser/network-cache.d.ts +48 -0
- package/dist/src/browser/network-cache.js +66 -0
- package/dist/src/browser/network-cache.test.d.ts +1 -0
- package/dist/src/browser/network-cache.test.js +58 -0
- package/dist/src/browser/network-key.d.ts +22 -0
- package/dist/src/browser/network-key.js +66 -0
- package/dist/src/browser/network-key.test.d.ts +1 -0
- package/dist/src/browser/network-key.test.js +49 -0
- package/dist/src/browser/shape-filter.d.ts +52 -0
- package/dist/src/browser/shape-filter.js +101 -0
- package/dist/src/browser/shape-filter.test.d.ts +1 -0
- package/dist/src/browser/shape-filter.test.js +101 -0
- package/dist/src/browser/shape.d.ts +23 -0
- package/dist/src/browser/shape.js +95 -0
- package/dist/src/browser/shape.test.d.ts +1 -0
- package/dist/src/browser/shape.test.js +82 -0
- package/dist/src/browser/target-errors.d.ts +14 -1
- package/dist/src/browser/target-errors.js +13 -0
- package/dist/src/browser/target-errors.test.js +39 -6
- package/dist/src/browser/target-resolver.d.ts +57 -10
- package/dist/src/browser/target-resolver.js +195 -75
- package/dist/src/browser/target-resolver.test.js +80 -5
- package/dist/src/browser/verify-fixture.d.ts +59 -0
- package/dist/src/browser/verify-fixture.js +213 -0
- package/dist/src/browser/verify-fixture.test.d.ts +1 -0
- package/dist/src/browser/verify-fixture.test.js +161 -0
- package/dist/src/cli.d.ts +32 -0
- package/dist/src/cli.js +936 -141
- package/dist/src/cli.test.js +1051 -1
- package/dist/src/daemon.d.ts +3 -2
- package/dist/src/daemon.js +16 -4
- package/dist/src/daemon.test.d.ts +1 -0
- package/dist/src/daemon.test.js +19 -0
- package/dist/src/download/article-download.d.ts +12 -0
- package/dist/src/download/article-download.js +141 -17
- package/dist/src/download/article-download.test.js +196 -0
- package/dist/src/download/index.js +73 -86
- package/dist/src/errors.js +4 -2
- package/dist/src/errors.test.js +13 -0
- package/dist/src/execution.js +7 -2
- package/dist/src/execution.test.js +54 -0
- package/dist/src/launcher.d.ts +1 -1
- package/dist/src/launcher.js +3 -3
- package/dist/src/main.js +16 -0
- package/dist/src/output.js +1 -1
- package/dist/src/output.test.js +6 -0
- package/dist/src/types.d.ts +18 -3
- package/package.json +5 -1
package/cli-manifest.json
CHANGED
|
@@ -271,6 +271,264 @@
|
|
|
271
271
|
"modulePath": "36kr/search.js",
|
|
272
272
|
"sourceFile": "36kr/search.js"
|
|
273
273
|
},
|
|
274
|
+
{
|
|
275
|
+
"site": "51job",
|
|
276
|
+
"name": "company",
|
|
277
|
+
"description": "51job 公司简介 + 在招职位(按 encCoId)",
|
|
278
|
+
"domain": "jobs.51job.com",
|
|
279
|
+
"strategy": "cookie",
|
|
280
|
+
"browser": true,
|
|
281
|
+
"args": [
|
|
282
|
+
{
|
|
283
|
+
"name": "encCoId",
|
|
284
|
+
"type": "string",
|
|
285
|
+
"required": true,
|
|
286
|
+
"positional": true,
|
|
287
|
+
"help": "加密公司 ID(search 返回的 encCoId)"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"name": "limit",
|
|
291
|
+
"type": "int",
|
|
292
|
+
"default": 20,
|
|
293
|
+
"required": false,
|
|
294
|
+
"help": "返回职位数(1-50)"
|
|
295
|
+
}
|
|
296
|
+
],
|
|
297
|
+
"columns": [
|
|
298
|
+
"rank",
|
|
299
|
+
"jobId",
|
|
300
|
+
"title",
|
|
301
|
+
"salary",
|
|
302
|
+
"city",
|
|
303
|
+
"workYear",
|
|
304
|
+
"degree",
|
|
305
|
+
"funcType",
|
|
306
|
+
"issueDate",
|
|
307
|
+
"url",
|
|
308
|
+
"companyName",
|
|
309
|
+
"companyType",
|
|
310
|
+
"companySize",
|
|
311
|
+
"companyIndustry",
|
|
312
|
+
"companyIntro",
|
|
313
|
+
"companyUrl"
|
|
314
|
+
],
|
|
315
|
+
"type": "js",
|
|
316
|
+
"modulePath": "51job/company.js",
|
|
317
|
+
"sourceFile": "51job/company.js",
|
|
318
|
+
"navigateBefore": false
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
"site": "51job",
|
|
322
|
+
"name": "detail",
|
|
323
|
+
"description": "51job 职位详情(按 jobId)",
|
|
324
|
+
"domain": "jobs.51job.com",
|
|
325
|
+
"strategy": "cookie",
|
|
326
|
+
"browser": true,
|
|
327
|
+
"args": [
|
|
328
|
+
{
|
|
329
|
+
"name": "jobId",
|
|
330
|
+
"type": "string",
|
|
331
|
+
"required": true,
|
|
332
|
+
"positional": true,
|
|
333
|
+
"help": "职位 ID(search 返回的 jobId)"
|
|
334
|
+
}
|
|
335
|
+
],
|
|
336
|
+
"columns": [
|
|
337
|
+
"jobId",
|
|
338
|
+
"title",
|
|
339
|
+
"salary",
|
|
340
|
+
"location",
|
|
341
|
+
"workYear",
|
|
342
|
+
"degree",
|
|
343
|
+
"category",
|
|
344
|
+
"address",
|
|
345
|
+
"ageRequirement",
|
|
346
|
+
"description",
|
|
347
|
+
"welfare",
|
|
348
|
+
"company",
|
|
349
|
+
"companyType",
|
|
350
|
+
"companySize",
|
|
351
|
+
"companyIndustry",
|
|
352
|
+
"companyUrl",
|
|
353
|
+
"url"
|
|
354
|
+
],
|
|
355
|
+
"type": "js",
|
|
356
|
+
"modulePath": "51job/detail.js",
|
|
357
|
+
"sourceFile": "51job/detail.js",
|
|
358
|
+
"navigateBefore": false
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"site": "51job",
|
|
362
|
+
"name": "hot",
|
|
363
|
+
"description": "51job 推荐职位(按城市/行业/排序浏览)",
|
|
364
|
+
"domain": "we.51job.com",
|
|
365
|
+
"strategy": "cookie",
|
|
366
|
+
"browser": true,
|
|
367
|
+
"args": [
|
|
368
|
+
{
|
|
369
|
+
"name": "area",
|
|
370
|
+
"type": "string",
|
|
371
|
+
"default": "全国",
|
|
372
|
+
"required": false,
|
|
373
|
+
"help": "城市名或 6 位城市码(默认 \"全国\")"
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
"name": "sort",
|
|
377
|
+
"type": "string",
|
|
378
|
+
"default": "综合",
|
|
379
|
+
"required": false,
|
|
380
|
+
"help": "排序:综合 / 最新 / 薪资 / 距离"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"name": "page",
|
|
384
|
+
"type": "int",
|
|
385
|
+
"default": 1,
|
|
386
|
+
"required": false,
|
|
387
|
+
"help": "页码(1-based)"
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"name": "limit",
|
|
391
|
+
"type": "int",
|
|
392
|
+
"default": 20,
|
|
393
|
+
"required": false,
|
|
394
|
+
"help": "返回条数(1-50)"
|
|
395
|
+
}
|
|
396
|
+
],
|
|
397
|
+
"columns": [
|
|
398
|
+
"rank",
|
|
399
|
+
"jobId",
|
|
400
|
+
"title",
|
|
401
|
+
"salary",
|
|
402
|
+
"salaryMin",
|
|
403
|
+
"salaryMax",
|
|
404
|
+
"city",
|
|
405
|
+
"district",
|
|
406
|
+
"workYear",
|
|
407
|
+
"degree",
|
|
408
|
+
"tags",
|
|
409
|
+
"company",
|
|
410
|
+
"companyFull",
|
|
411
|
+
"companyType",
|
|
412
|
+
"companySize",
|
|
413
|
+
"industry",
|
|
414
|
+
"hr",
|
|
415
|
+
"issueDate",
|
|
416
|
+
"url",
|
|
417
|
+
"companyUrl",
|
|
418
|
+
"encCoId"
|
|
419
|
+
],
|
|
420
|
+
"type": "js",
|
|
421
|
+
"modulePath": "51job/hot.js",
|
|
422
|
+
"sourceFile": "51job/hot.js",
|
|
423
|
+
"navigateBefore": false
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
"site": "51job",
|
|
427
|
+
"name": "search",
|
|
428
|
+
"description": "51job 前程无忧关键词职位搜索",
|
|
429
|
+
"domain": "we.51job.com",
|
|
430
|
+
"strategy": "cookie",
|
|
431
|
+
"browser": true,
|
|
432
|
+
"args": [
|
|
433
|
+
{
|
|
434
|
+
"name": "keyword",
|
|
435
|
+
"type": "string",
|
|
436
|
+
"required": true,
|
|
437
|
+
"positional": true,
|
|
438
|
+
"help": "搜索关键词(岗位名 / 技能 / 公司)"
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
"name": "area",
|
|
442
|
+
"type": "string",
|
|
443
|
+
"default": "全国",
|
|
444
|
+
"required": false,
|
|
445
|
+
"help": "城市名或 6 位城市码(如 \"杭州\" / \"080200\" / \"全国\")"
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
"name": "salary",
|
|
449
|
+
"type": "string",
|
|
450
|
+
"default": "",
|
|
451
|
+
"required": false,
|
|
452
|
+
"help": "薪资区间(如 \"10-15k\" / \"1-1.5万\" / \"20-30k\")"
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
"name": "experience",
|
|
456
|
+
"type": "string",
|
|
457
|
+
"default": "",
|
|
458
|
+
"required": false,
|
|
459
|
+
"help": "工作年限(如 \"应届\" / \"1-3年\" / \"3-5年\" / \"5-7年\")"
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
"name": "degree",
|
|
463
|
+
"type": "string",
|
|
464
|
+
"default": "",
|
|
465
|
+
"required": false,
|
|
466
|
+
"help": "学历要求(如 \"本科\" / \"大专\" / \"硕士\")"
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
"name": "companyType",
|
|
470
|
+
"type": "string",
|
|
471
|
+
"default": "",
|
|
472
|
+
"required": false,
|
|
473
|
+
"help": "公司性质(如 \"外资\" / \"国企\" / \"民营\")"
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
"name": "companySize",
|
|
477
|
+
"type": "string",
|
|
478
|
+
"default": "",
|
|
479
|
+
"required": false,
|
|
480
|
+
"help": "公司规模(如 \"50-150\" / \"1000-5000\")"
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"name": "sort",
|
|
484
|
+
"type": "string",
|
|
485
|
+
"default": "综合",
|
|
486
|
+
"required": false,
|
|
487
|
+
"help": "排序:综合 / 最新 / 薪资 / 距离"
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
"name": "page",
|
|
491
|
+
"type": "int",
|
|
492
|
+
"default": 1,
|
|
493
|
+
"required": false,
|
|
494
|
+
"help": "页码(1-based)"
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
"name": "limit",
|
|
498
|
+
"type": "int",
|
|
499
|
+
"default": 20,
|
|
500
|
+
"required": false,
|
|
501
|
+
"help": "返回条数(1-50)"
|
|
502
|
+
}
|
|
503
|
+
],
|
|
504
|
+
"columns": [
|
|
505
|
+
"rank",
|
|
506
|
+
"jobId",
|
|
507
|
+
"title",
|
|
508
|
+
"salary",
|
|
509
|
+
"salaryMin",
|
|
510
|
+
"salaryMax",
|
|
511
|
+
"city",
|
|
512
|
+
"district",
|
|
513
|
+
"workYear",
|
|
514
|
+
"degree",
|
|
515
|
+
"tags",
|
|
516
|
+
"company",
|
|
517
|
+
"companyFull",
|
|
518
|
+
"companyType",
|
|
519
|
+
"companySize",
|
|
520
|
+
"industry",
|
|
521
|
+
"hr",
|
|
522
|
+
"issueDate",
|
|
523
|
+
"url",
|
|
524
|
+
"companyUrl",
|
|
525
|
+
"encCoId"
|
|
526
|
+
],
|
|
527
|
+
"type": "js",
|
|
528
|
+
"modulePath": "51job/search.js",
|
|
529
|
+
"sourceFile": "51job/search.js",
|
|
530
|
+
"navigateBefore": false
|
|
531
|
+
},
|
|
274
532
|
{
|
|
275
533
|
"site": "amazon",
|
|
276
534
|
"name": "bestsellers",
|
|
@@ -1716,6 +1974,30 @@
|
|
|
1716
1974
|
"sourceFile": "bilibili/user-videos.js",
|
|
1717
1975
|
"navigateBefore": "https://www.bilibili.com"
|
|
1718
1976
|
},
|
|
1977
|
+
{
|
|
1978
|
+
"site": "bilibili",
|
|
1979
|
+
"name": "video",
|
|
1980
|
+
"description": "Get Bilibili video metadata (title, author, duration, stats, etc.)",
|
|
1981
|
+
"strategy": "cookie",
|
|
1982
|
+
"browser": true,
|
|
1983
|
+
"args": [
|
|
1984
|
+
{
|
|
1985
|
+
"name": "bvid",
|
|
1986
|
+
"type": "str",
|
|
1987
|
+
"required": true,
|
|
1988
|
+
"positional": true,
|
|
1989
|
+
"help": "BV ID, video URL, or b23.tv short link"
|
|
1990
|
+
}
|
|
1991
|
+
],
|
|
1992
|
+
"columns": [
|
|
1993
|
+
"field",
|
|
1994
|
+
"value"
|
|
1995
|
+
],
|
|
1996
|
+
"type": "js",
|
|
1997
|
+
"modulePath": "bilibili/video.js",
|
|
1998
|
+
"sourceFile": "bilibili/video.js",
|
|
1999
|
+
"navigateBefore": true
|
|
2000
|
+
},
|
|
1719
2001
|
{
|
|
1720
2002
|
"site": "binance",
|
|
1721
2003
|
"name": "asks",
|
|
@@ -3250,7 +3532,7 @@
|
|
|
3250
3532
|
{
|
|
3251
3533
|
"name": "op",
|
|
3252
3534
|
"type": "str",
|
|
3253
|
-
"default": "
|
|
3535
|
+
"default": "~/Pictures/chatgpt",
|
|
3254
3536
|
"required": false,
|
|
3255
3537
|
"help": "Output directory"
|
|
3256
3538
|
},
|
|
@@ -4118,11 +4400,14 @@
|
|
|
4118
4400
|
"default": false,
|
|
4119
4401
|
"required": false,
|
|
4120
4402
|
"help": "Enable web search"
|
|
4403
|
+
},
|
|
4404
|
+
{
|
|
4405
|
+
"name": "file",
|
|
4406
|
+
"type": "str",
|
|
4407
|
+
"required": false,
|
|
4408
|
+
"help": "Attach a file (PDF, image, text) with the prompt"
|
|
4121
4409
|
}
|
|
4122
4410
|
],
|
|
4123
|
-
"columns": [
|
|
4124
|
-
"response"
|
|
4125
|
-
],
|
|
4126
4411
|
"timeout": 180,
|
|
4127
4412
|
"type": "js",
|
|
4128
4413
|
"modulePath": "deepseek/ask.js",
|
|
@@ -6835,7 +7120,7 @@
|
|
|
6835
7120
|
{
|
|
6836
7121
|
"name": "op",
|
|
6837
7122
|
"type": "str",
|
|
6838
|
-
"default": "
|
|
7123
|
+
"default": "~/tmp/gemini-images",
|
|
6839
7124
|
"required": false,
|
|
6840
7125
|
"help": "Output directory shorthand"
|
|
6841
7126
|
},
|
|
@@ -8116,7 +8401,7 @@
|
|
|
8116
8401
|
{
|
|
8117
8402
|
"name": "path",
|
|
8118
8403
|
"type": "str",
|
|
8119
|
-
"default": "
|
|
8404
|
+
"default": "~/Downloads/Instagram",
|
|
8120
8405
|
"required": false,
|
|
8121
8406
|
"help": "Download directory"
|
|
8122
8407
|
}
|
|
@@ -8908,13 +9193,20 @@
|
|
|
8908
9193
|
"default": 20,
|
|
8909
9194
|
"required": false,
|
|
8910
9195
|
"help": "Number of results (max 50)"
|
|
9196
|
+
},
|
|
9197
|
+
{
|
|
9198
|
+
"name": "since_days",
|
|
9199
|
+
"type": "int",
|
|
9200
|
+
"required": false,
|
|
9201
|
+
"help": "Only keep rows published within N days"
|
|
8911
9202
|
}
|
|
8912
9203
|
],
|
|
8913
9204
|
"columns": [
|
|
8914
9205
|
"rank",
|
|
8915
9206
|
"content_type",
|
|
8916
9207
|
"title",
|
|
8917
|
-
"
|
|
9208
|
+
"published_at",
|
|
9209
|
+
"detail_status",
|
|
8918
9210
|
"project_code",
|
|
8919
9211
|
"budget_or_limit",
|
|
8920
9212
|
"url"
|
|
@@ -15685,7 +15977,9 @@
|
|
|
15685
15977
|
"name",
|
|
15686
15978
|
"text",
|
|
15687
15979
|
"likes",
|
|
15688
|
-
"url"
|
|
15980
|
+
"url",
|
|
15981
|
+
"has_media",
|
|
15982
|
+
"media_urls"
|
|
15689
15983
|
],
|
|
15690
15984
|
"type": "js",
|
|
15691
15985
|
"modulePath": "twitter/likes.js",
|
|
@@ -16050,7 +16344,9 @@
|
|
|
16050
16344
|
"created_at",
|
|
16051
16345
|
"likes",
|
|
16052
16346
|
"views",
|
|
16053
|
-
"url"
|
|
16347
|
+
"url",
|
|
16348
|
+
"has_media",
|
|
16349
|
+
"media_urls"
|
|
16054
16350
|
],
|
|
16055
16351
|
"type": "js",
|
|
16056
16352
|
"modulePath": "twitter/search.js",
|
|
@@ -16086,7 +16382,9 @@
|
|
|
16086
16382
|
"text",
|
|
16087
16383
|
"likes",
|
|
16088
16384
|
"retweets",
|
|
16089
|
-
"url"
|
|
16385
|
+
"url",
|
|
16386
|
+
"has_media",
|
|
16387
|
+
"media_urls"
|
|
16090
16388
|
],
|
|
16091
16389
|
"type": "js",
|
|
16092
16390
|
"modulePath": "twitter/thread.js",
|
|
@@ -16129,7 +16427,9 @@
|
|
|
16129
16427
|
"replies",
|
|
16130
16428
|
"views",
|
|
16131
16429
|
"created_at",
|
|
16132
|
-
"url"
|
|
16430
|
+
"url",
|
|
16431
|
+
"has_media",
|
|
16432
|
+
"media_urls"
|
|
16133
16433
|
],
|
|
16134
16434
|
"type": "js",
|
|
16135
16435
|
"modulePath": "twitter/timeline.js",
|
|
@@ -16163,6 +16463,47 @@
|
|
|
16163
16463
|
"sourceFile": "twitter/trending.js",
|
|
16164
16464
|
"navigateBefore": "https://x.com"
|
|
16165
16465
|
},
|
|
16466
|
+
{
|
|
16467
|
+
"site": "twitter",
|
|
16468
|
+
"name": "tweets",
|
|
16469
|
+
"description": "Fetch a Twitter user's most recent tweets (chronological, excludes pinned)",
|
|
16470
|
+
"domain": "x.com",
|
|
16471
|
+
"strategy": "cookie",
|
|
16472
|
+
"browser": true,
|
|
16473
|
+
"args": [
|
|
16474
|
+
{
|
|
16475
|
+
"name": "username",
|
|
16476
|
+
"type": "string",
|
|
16477
|
+
"required": true,
|
|
16478
|
+
"positional": true,
|
|
16479
|
+
"help": "Twitter screen name (with or without @)"
|
|
16480
|
+
},
|
|
16481
|
+
{
|
|
16482
|
+
"name": "limit",
|
|
16483
|
+
"type": "int",
|
|
16484
|
+
"default": 20,
|
|
16485
|
+
"required": false,
|
|
16486
|
+
"help": "Max tweets to return"
|
|
16487
|
+
}
|
|
16488
|
+
],
|
|
16489
|
+
"columns": [
|
|
16490
|
+
"author",
|
|
16491
|
+
"created_at",
|
|
16492
|
+
"is_retweet",
|
|
16493
|
+
"text",
|
|
16494
|
+
"likes",
|
|
16495
|
+
"retweets",
|
|
16496
|
+
"replies",
|
|
16497
|
+
"views",
|
|
16498
|
+
"url",
|
|
16499
|
+
"has_media",
|
|
16500
|
+
"media_urls"
|
|
16501
|
+
],
|
|
16502
|
+
"type": "js",
|
|
16503
|
+
"modulePath": "twitter/tweets.js",
|
|
16504
|
+
"sourceFile": "twitter/tweets.js",
|
|
16505
|
+
"navigateBefore": "https://x.com"
|
|
16506
|
+
},
|
|
16166
16507
|
{
|
|
16167
16508
|
"site": "twitter",
|
|
16168
16509
|
"name": "unblock",
|
|
@@ -16691,6 +17032,13 @@
|
|
|
16691
17032
|
"default": 3,
|
|
16692
17033
|
"required": false,
|
|
16693
17034
|
"help": "Seconds to wait after page load"
|
|
17035
|
+
},
|
|
17036
|
+
{
|
|
17037
|
+
"name": "stdout",
|
|
17038
|
+
"type": "boolean",
|
|
17039
|
+
"default": false,
|
|
17040
|
+
"required": false,
|
|
17041
|
+
"help": "Print markdown to stdout instead of saving to a file"
|
|
16694
17042
|
}
|
|
16695
17043
|
],
|
|
16696
17044
|
"columns": [
|
|
@@ -16968,6 +17316,48 @@
|
|
|
16968
17316
|
"sourceFile": "weixin/download.js",
|
|
16969
17317
|
"navigateBefore": "https://mp.weixin.qq.com"
|
|
16970
17318
|
},
|
|
17319
|
+
{
|
|
17320
|
+
"site": "weread",
|
|
17321
|
+
"name": "ai-outline",
|
|
17322
|
+
"description": "Get AI-generated outline for a book",
|
|
17323
|
+
"domain": "weread.qq.com",
|
|
17324
|
+
"strategy": "cookie",
|
|
17325
|
+
"browser": true,
|
|
17326
|
+
"args": [
|
|
17327
|
+
{
|
|
17328
|
+
"name": "book-id",
|
|
17329
|
+
"type": "str",
|
|
17330
|
+
"required": true,
|
|
17331
|
+
"positional": true,
|
|
17332
|
+
"help": "Book ID (from shelf or search results)"
|
|
17333
|
+
},
|
|
17334
|
+
{
|
|
17335
|
+
"name": "limit",
|
|
17336
|
+
"type": "int",
|
|
17337
|
+
"default": 200,
|
|
17338
|
+
"required": false,
|
|
17339
|
+
"help": "Max outline items to return"
|
|
17340
|
+
},
|
|
17341
|
+
{
|
|
17342
|
+
"name": "depth",
|
|
17343
|
+
"type": "int",
|
|
17344
|
+
"default": 4,
|
|
17345
|
+
"required": false,
|
|
17346
|
+
"help": "Max outline depth (2=topics, 3=key points, 4=details)"
|
|
17347
|
+
},
|
|
17348
|
+
{
|
|
17349
|
+
"name": "raw",
|
|
17350
|
+
"type": "boolean",
|
|
17351
|
+
"default": false,
|
|
17352
|
+
"required": false,
|
|
17353
|
+
"help": "Output structured rows (chapter/idx/level/text) for programmatic use"
|
|
17354
|
+
}
|
|
17355
|
+
],
|
|
17356
|
+
"type": "js",
|
|
17357
|
+
"modulePath": "weread/ai-outline.js",
|
|
17358
|
+
"sourceFile": "weread/ai-outline.js",
|
|
17359
|
+
"navigateBefore": "https://weread.qq.com"
|
|
17360
|
+
},
|
|
16971
17361
|
{
|
|
16972
17362
|
"site": "weread",
|
|
16973
17363
|
"name": "book",
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 51job company jobs + basic info by encCoId.
|
|
3
|
+
*
|
|
4
|
+
* Navigates to `jobs.51job.com/all/co<encCoId>.html`. Each job card is an
|
|
5
|
+
* `<a sensorsdata="…">` whose attribute is a JSON blob with jobId, title,
|
|
6
|
+
* salary, area, year, degree — so parsing is just JSON, not DOM-text fragile.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
10
|
+
import { CliError } from '@jackwener/opencli/errors';
|
|
11
|
+
import { JOBS_ORIGIN, requirePage, navigateTo, parseCompanyJobCard } from './utils.js';
|
|
12
|
+
|
|
13
|
+
cli({
|
|
14
|
+
site: '51job',
|
|
15
|
+
name: 'company',
|
|
16
|
+
description: '51job 公司简介 + 在招职位(按 encCoId)',
|
|
17
|
+
domain: 'jobs.51job.com',
|
|
18
|
+
strategy: Strategy.COOKIE,
|
|
19
|
+
browser: true,
|
|
20
|
+
navigateBefore: false,
|
|
21
|
+
args: [
|
|
22
|
+
{ name: 'encCoId', type: 'string', required: true, positional: true, help: '加密公司 ID(search 返回的 encCoId)' },
|
|
23
|
+
{ name: 'limit', type: 'int', default: 20, help: '返回职位数(1-50)' },
|
|
24
|
+
],
|
|
25
|
+
columns: [
|
|
26
|
+
'rank', 'jobId', 'title', 'salary', 'city', 'workYear', 'degree',
|
|
27
|
+
'funcType', 'issueDate', 'url',
|
|
28
|
+
'companyName', 'companyType', 'companySize', 'companyIndustry',
|
|
29
|
+
'companyIntro', 'companyUrl',
|
|
30
|
+
],
|
|
31
|
+
func: async (page, kwargs) => {
|
|
32
|
+
requirePage(page);
|
|
33
|
+
const encCoId = String(kwargs.encCoId ?? '').trim();
|
|
34
|
+
if (!encCoId) throw new CliError('INVALID_ARGUMENT', 'encCoId is required');
|
|
35
|
+
if (!/^[A-Za-z0-9_]+$/.test(encCoId)) {
|
|
36
|
+
throw new CliError('INVALID_ARGUMENT', `encCoId must be alphanumeric/underscore, got "${encCoId}"`);
|
|
37
|
+
}
|
|
38
|
+
const limit = Math.max(1, Math.min(Number(kwargs.limit) || 20, 50));
|
|
39
|
+
|
|
40
|
+
const url = `${JOBS_ORIGIN}/all/co${encCoId}.html`;
|
|
41
|
+
await navigateTo(page, url, 2);
|
|
42
|
+
|
|
43
|
+
const script = `(() => {
|
|
44
|
+
const sel = s => document.querySelector(s)?.innerText?.trim() || '';
|
|
45
|
+
const bodyText = (document.body.innerText || '').slice(0, 400);
|
|
46
|
+
if (/公司不存在|页面不存在|账号状态异常/.test(bodyText)) {
|
|
47
|
+
return { error: 'NOT_FOUND', bodyText };
|
|
48
|
+
}
|
|
49
|
+
const companyName = sel('h1') || sel('.cname');
|
|
50
|
+
// Company introduction block
|
|
51
|
+
const introEl = document.querySelector('#companyIntroRef, .c-intro');
|
|
52
|
+
const companyIntro = introEl ? (introEl.innerText || '').trim() : '';
|
|
53
|
+
// Info sidebar (type / size / industry) — labels sit in .com-info dl or .coinfo
|
|
54
|
+
const sidebarText = sel('.ci-content, .company-info, .coinfo, .com-info');
|
|
55
|
+
const links = [...document.querySelectorAll('a[sensorsdata]')]
|
|
56
|
+
.filter(a => /\\/\\d{6,}\\.html/.test(a.href || ''))
|
|
57
|
+
.slice(0, 60)
|
|
58
|
+
.map(a => {
|
|
59
|
+
return {
|
|
60
|
+
href: a.href,
|
|
61
|
+
sensorsdata: a.getAttribute('sensorsdata') || '',
|
|
62
|
+
text: (a.innerText || '').trim(),
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
// Company meta is three inline spans under .c-info.ellipsis
|
|
66
|
+
// (title/size/industry) — extract them by position.
|
|
67
|
+
const cInfo = document.querySelector('.c-info.ellipsis');
|
|
68
|
+
const cInfoParts = cInfo
|
|
69
|
+
? [...cInfo.querySelectorAll('span')].map(s => (s.innerText || '').trim()).filter(Boolean)
|
|
70
|
+
: [];
|
|
71
|
+
return {
|
|
72
|
+
companyName,
|
|
73
|
+
companyIntro,
|
|
74
|
+
links,
|
|
75
|
+
cInfoParts,
|
|
76
|
+
sidebarText: sidebarText.slice(0, 400),
|
|
77
|
+
};
|
|
78
|
+
})()`;
|
|
79
|
+
const data = await page.evaluate(script);
|
|
80
|
+
if (data.error === 'NOT_FOUND') {
|
|
81
|
+
throw new CliError('NO_DATA', `Company ${encCoId} not found`);
|
|
82
|
+
}
|
|
83
|
+
if (!data.companyName) {
|
|
84
|
+
throw new CliError('NO_DATA', `Could not parse company page ${encCoId}; layout may have changed`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const companyUrl = url;
|
|
88
|
+
const [companyType = '', companySize = '', companyIndustry = ''] = data.cInfoParts || [];
|
|
89
|
+
|
|
90
|
+
const seen = new Set();
|
|
91
|
+
const rows = [];
|
|
92
|
+
for (const link of data.links || []) {
|
|
93
|
+
const job = parseCompanyJobCard(link);
|
|
94
|
+
if (!job) continue;
|
|
95
|
+
if (seen.has(job.jobId)) continue;
|
|
96
|
+
seen.add(job.jobId);
|
|
97
|
+
rows.push({
|
|
98
|
+
rank: rows.length + 1,
|
|
99
|
+
...job,
|
|
100
|
+
companyName: data.companyName,
|
|
101
|
+
companyType,
|
|
102
|
+
companySize,
|
|
103
|
+
companyIndustry,
|
|
104
|
+
companyIntro: data.companyIntro || '',
|
|
105
|
+
companyUrl,
|
|
106
|
+
});
|
|
107
|
+
if (rows.length >= limit) break;
|
|
108
|
+
}
|
|
109
|
+
if (rows.length === 0) {
|
|
110
|
+
// Still return a sentinel row with the company info so caller isn't left with [].
|
|
111
|
+
return [{
|
|
112
|
+
rank: 0,
|
|
113
|
+
jobId: '',
|
|
114
|
+
title: '(no active jobs)',
|
|
115
|
+
salary: '', city: '', workYear: '', degree: '',
|
|
116
|
+
funcType: '', issueDate: '', url: '',
|
|
117
|
+
companyName: data.companyName,
|
|
118
|
+
companyType, companySize, companyIndustry,
|
|
119
|
+
companyIntro: data.companyIntro || '',
|
|
120
|
+
companyUrl,
|
|
121
|
+
}];
|
|
122
|
+
}
|
|
123
|
+
return rows;
|
|
124
|
+
},
|
|
125
|
+
});
|