oc-browser-relay 1.0.7 → 1.0.8

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.
@@ -442,6 +442,9 @@
442
442
  }
443
443
  },
444
444
  "executionPolicy": {
445
+ "popupGuard": {
446
+ "enabled": false
447
+ },
445
448
  "typingPolicy": {
446
449
  "mode": "human_typing",
447
450
  "minKeyDelayMs": 120,
@@ -19,12 +19,102 @@
19
19
  },
20
20
  {
21
21
  "type": "element_visible",
22
- "selector": "body"
22
+ "selector": "label:has(input[type='radio'][value='Real']), label:has(input[type='radio'][value='Day'])"
23
23
  }
24
24
  ]
25
25
  },
26
26
  "waitTimeoutMs": 15000
27
27
  },
28
+ "reusePolicy": {
29
+ "enabled": true,
30
+ "taskTypes": ["collect_douyin_fxg_homepage_api"],
31
+ "includeSameHostPages": true,
32
+ "candidatePages": [
33
+ "douyin_fxg_homepage"
34
+ ],
35
+ "resetActions": [
36
+ {
37
+ "when": "target_page",
38
+ "kind": "scroll_to_top"
39
+ },
40
+ {
41
+ "when": "same_host_non_target",
42
+ "kind": "click_locator",
43
+ "skipPopupGuard": true,
44
+ "locators": [
45
+ {
46
+ "kind": "css",
47
+ "value": "h1#fxg-pc-header-title",
48
+ "priority": 1
49
+ }
50
+ ],
51
+ "waitForUrlMatch": [
52
+ "https://fxg.jinritemai.com/ffa/mshop/homepage/index*"
53
+ ],
54
+ "waitTimeoutMs": 15000,
55
+ "settleDelayMs": 600
56
+ }
57
+ ]
58
+ },
59
+ "executionPolicy": {
60
+ "clickPolicy": {
61
+ "scrollIntoView": true,
62
+ "requireVisible": true,
63
+ "preHover": true,
64
+ "hoverDurationMsRange": [70, 150],
65
+ "preClickPauseMsRange": [40, 100]
66
+ },
67
+ "humanBehavior": {
68
+ "cursorMoveSpeedRange": [105, 170],
69
+ "cursorStepDelayMsRange": [3, 7],
70
+ "cursorVisibleDurationMsRange": [120, 220],
71
+ "minCursorStepCount": 10,
72
+ "mouseDownUpDelayMsRange": [30, 80],
73
+ "postClickPauseMsRange": [40, 120]
74
+ },
75
+ "actionPausePolicy": {
76
+ "minPauseMs": 120,
77
+ "maxPauseMs": 520
78
+ }
79
+ },
80
+ "actions": {
81
+ "switch_metric_period": {
82
+ "actionId": "switch_metric_period",
83
+ "label": "切换首页时间粒度",
84
+ "kind": "click",
85
+ "skipPopupGuard": true,
86
+ "locators": [
87
+ {
88
+ "kind": "xpath",
89
+ "value": "//input[@type='radio' and @value='Real']/ancestor::label[1]",
90
+ "priority": 1
91
+ }
92
+ ]
93
+ }
94
+ },
95
+ "captureSources": {
96
+ "homepage_metrics": {
97
+ "urlPattern": "/pc/api/home/homepage",
98
+ "method": "GET",
99
+ "capability": "hybrid",
100
+ "operation": "capture_response",
101
+ "persistent": true,
102
+ "artifactType": "hybrid",
103
+ "includeBody": true,
104
+ "locationSuffix": "douyin_fxg_homepage_metrics",
105
+ "hint": "capture douyin fxg homepage metrics"
106
+ }
107
+ },
108
+ "capturePlans": {
109
+ "homepage_metrics": {
110
+ "sourceId": "homepage_metrics",
111
+ "captureNetwork": {
112
+ "timeoutMs": 15000,
113
+ "startPhase": "before_action",
114
+ "actionScope": "step"
115
+ }
116
+ }
117
+ },
28
118
  "crawlerHints": {
29
119
  "structuredDataExtractors": {
30
120
  "homepage_operating_data": {
@@ -34,7 +124,35 @@
34
124
  "outputSchema": {
35
125
  "root": {
36
126
  "extractedAt": "sources.homepage_operating_data.extractedAt",
37
- "metrics": "sources.homepage_operating_data.metrics"
127
+ "metrics": "sources.homepage_operating_data.metrics",
128
+ "incomeExpenseMetrics": "sources.homepage_operating_data.incomeExpenseMetrics"
129
+ }
130
+ }
131
+ },
132
+ "homepage_metrics_capture": {
133
+ "adapterId": "douyin_fxg_homepage_capture",
134
+ "sourceId": "homepage_metrics_capture",
135
+ "timeoutMs": 30000,
136
+ "observationSources": [
137
+ {
138
+ "sourceId": "homepage_metrics_capture",
139
+ "nodeIdArg": "sourceNodeId",
140
+ "sourceType": "active_capture_results",
141
+ "consumeCapture": true,
142
+ "resultPath": "$self"
143
+ }
144
+ ],
145
+ "outputSchema": {
146
+ "root": {
147
+ "extractedAt": "sources.homepage_metrics_capture.extractedAt",
148
+ "periodValue": "sources.homepage_metrics_capture.periodValue",
149
+ "periodLabel": "sources.homepage_metrics_capture.periodLabel",
150
+ "title": "sources.homepage_metrics_capture.title",
151
+ "subTitle": "sources.homepage_metrics_capture.subTitle",
152
+ "rank": "sources.homepage_metrics_capture.rank",
153
+ "metrics": "sources.homepage_metrics_capture.metrics",
154
+ "incomeExpenseMetrics": "sources.homepage_metrics_capture.incomeExpenseMetrics",
155
+ "meta": "sources.homepage_metrics_capture.meta"
38
156
  }
39
157
  }
40
158
  }
@@ -28,15 +28,10 @@
28
28
  "when": "same_host_non_target",
29
29
  "kind": "click_locator",
30
30
  "locators": [
31
- {
32
- "kind": "css",
33
- "value": ".logoWrapper",
34
- "priority": 1
35
- },
36
31
  {
37
32
  "kind": "xpath",
38
- "value": "//div[contains(@class,'logoWrapper') and .//div[contains(@class,'logoText')][contains(normalize-space(.),'商家后台')]]",
39
- "priority": 2
33
+ "value": "//*[self::a or self::div or self::span][contains(normalize-space(.),'商家后台') and not(self::script)]",
34
+ "priority": 1
40
35
  }
41
36
  ],
42
37
  "waitForUrlMatch": [
@@ -54,11 +49,20 @@
54
49
  "conditions": [
55
50
  {
56
51
  "type": "url_contains",
57
- "value": "/home/"
52
+ "value": "/home"
58
53
  },
59
54
  {
60
- "type": "element_visible",
61
- "selector": "li#__msfe__side-nav_item_0.active > a[href^='/home/']"
55
+ "type": "logical_and",
56
+ "conditions": [
57
+ {
58
+ "type": "element_visible",
59
+ "selector": "a[href^='/home/']"
60
+ },
61
+ {
62
+ "type": "text_visible",
63
+ "value": "后台首页"
64
+ }
65
+ ]
62
66
  }
63
67
  ]
64
68
  },
@@ -91,15 +95,10 @@
91
95
  "label": "点击商家后台 Logo",
92
96
  "kind": "click",
93
97
  "locators": [
94
- {
95
- "kind": "css",
96
- "value": ".logoWrapper",
97
- "priority": 1
98
- },
99
98
  {
100
99
  "kind": "xpath",
101
- "value": "//div[contains(@class,'logoWrapper') and .//div[contains(@class,'logoText')][contains(normalize-space(.),'商家后台')]]",
102
- "priority": 2
100
+ "value": "//*[self::a or self::div or self::span][contains(normalize-space(.),'商家后台') and not(self::script)]",
101
+ "priority": 1
103
102
  }
104
103
  ]
105
104
  },
@@ -109,13 +108,13 @@
109
108
  "kind": "click",
110
109
  "locators": [
111
110
  {
112
- "kind": "css",
113
- "value": "li#__msfe__side-nav_item_0 > a[href^='/home/']",
111
+ "kind": "xpath",
112
+ "value": "//a[starts-with(@href,'/home/') and contains(normalize-space(.),'首页')]",
114
113
  "priority": 1
115
114
  },
116
115
  {
117
- "kind": "xpath",
118
- "value": "//li[@id='__msfe__side-nav_item_0']/a[starts-with(@href,'/home/')]",
116
+ "kind": "css",
117
+ "value": "a[href^='/home/']",
119
118
  "priority": 2
120
119
  }
121
120
  ]
@@ -126,19 +125,14 @@
126
125
  "kind": "click",
127
126
  "locators": [
128
127
  {
129
- "kind": "css",
130
- "value": "li#__msfe__side-nav_item_101 > a[href='/orders/list']",
128
+ "kind": "xpath",
129
+ "value": "//a[@href='/orders/list' and contains(normalize-space(.),'订单查询')]",
131
130
  "priority": 1
132
131
  },
133
132
  {
134
133
  "kind": "xpath",
135
- "value": "//nav[contains(@class,'side-nav')]//li[@id='__msfe__side-nav_item_101']/a[@href='/orders/list']",
134
+ "value": "//a[@href='/orders/list']",
136
135
  "priority": 2
137
- },
138
- {
139
- "kind": "xpath",
140
- "value": "//nav[contains(@class,'side-nav')]//a[@href='/orders/list' and .//span[contains(@class,'nav-item-text')][contains(normalize-space(.),'订单查询')]]",
141
- "priority": 3
142
136
  }
143
137
  ]
144
138
  }
@@ -2,8 +2,8 @@
2
2
  "siteId": "douyin_fxg",
3
3
  "taskType": "collect_douyin_fxg_homepage_api",
4
4
  "platform": "douyin",
5
- "name": "采集抖店首页经营看板接口",
6
- "description": "打开抖店商家后台首页,在页面会话内直接调用首页经营看板接口,并返回原始响应。",
5
+ "name": "采集抖店首页经营看板指标",
6
+ "description": "打开抖店商家后台首页,切换指定时间粒度按钮,捕获首页接口响应并返回结构化经营数据。",
7
7
  "requiredFields": [
8
8
  ],
9
9
  "optionalFields": [
@@ -12,6 +12,12 @@
12
12
  "type": "string",
13
13
  "description": "抖店首页地址",
14
14
  "default": "https://fxg.jinritemai.com/ffa/mshop/homepage/index?channel=zhaoshang"
15
+ },
16
+ {
17
+ "name": "metricPeriodValue",
18
+ "type": "string",
19
+ "description": "首页时间粒度按钮值,支持:Real、Day、Week、Month、Promotion",
20
+ "default": "Real"
15
21
  }
16
22
  ],
17
23
  "nodes": [
@@ -31,13 +37,119 @@
31
37
  "tool": "validate_page",
32
38
  "args": {}
33
39
  },
40
+ {
41
+ "nodeId": "s2b",
42
+ "name": "prepare_realtime_metrics",
43
+ "goal": "当目标为实时粒度时先切到近1天,确保回切实时会触发接口刷新",
44
+ "when": "equals(payload.metricPeriodValue, 'Real')",
45
+ "tool": "trigger_action",
46
+ "args": {
47
+ "action": "switch_metric_period",
48
+ "locators": [
49
+ {
50
+ "kind": "xpath",
51
+ "value": "//input[@type='radio' and @value='Day']/ancestor::label[1]",
52
+ "priority": 1
53
+ }
54
+ ]
55
+ }
56
+ },
57
+ {
58
+ "nodeId": "s2c_day",
59
+ "name": "prepare_day_metrics",
60
+ "goal": "当目标为近1天时先切到实时,确保重新切回近1天会触发接口刷新",
61
+ "when": "equals(payload.metricPeriodValue, 'Day')",
62
+ "tool": "trigger_action",
63
+ "args": {
64
+ "action": "switch_metric_period",
65
+ "locators": [
66
+ {
67
+ "kind": "xpath",
68
+ "value": "//input[@type='radio' and @value='Real']/ancestor::label[1]",
69
+ "priority": 1
70
+ }
71
+ ]
72
+ }
73
+ },
74
+ {
75
+ "nodeId": "s2c_week",
76
+ "name": "prepare_week_metrics",
77
+ "goal": "当目标为近7天时先切到实时,确保重新切回近7天会触发接口刷新",
78
+ "when": "equals(payload.metricPeriodValue, 'Week')",
79
+ "tool": "trigger_action",
80
+ "args": {
81
+ "action": "switch_metric_period",
82
+ "locators": [
83
+ {
84
+ "kind": "xpath",
85
+ "value": "//input[@type='radio' and @value='Real']/ancestor::label[1]",
86
+ "priority": 1
87
+ }
88
+ ]
89
+ }
90
+ },
91
+ {
92
+ "nodeId": "s2c_month",
93
+ "name": "prepare_month_metrics",
94
+ "goal": "当目标为近30天时先切到实时,确保重新切回近30天会触发接口刷新",
95
+ "when": "equals(payload.metricPeriodValue, 'Month')",
96
+ "tool": "trigger_action",
97
+ "args": {
98
+ "action": "switch_metric_period",
99
+ "locators": [
100
+ {
101
+ "kind": "xpath",
102
+ "value": "//input[@type='radio' and @value='Real']/ancestor::label[1]",
103
+ "priority": 1
104
+ }
105
+ ]
106
+ }
107
+ },
108
+ {
109
+ "nodeId": "s2c_promotion",
110
+ "name": "prepare_promotion_metrics",
111
+ "goal": "当目标为大促时先切到实时,确保重新切回大促会触发接口刷新",
112
+ "when": "equals(payload.metricPeriodValue, 'Promotion')",
113
+ "tool": "trigger_action",
114
+ "args": {
115
+ "action": "switch_metric_period",
116
+ "locators": [
117
+ {
118
+ "kind": "xpath",
119
+ "value": "//input[@type='radio' and @value='Real']/ancestor::label[1]",
120
+ "priority": 1
121
+ }
122
+ ]
123
+ }
124
+ },
34
125
  {
35
126
  "nodeId": "s3",
36
- "name": "invoke_homepage_api",
37
- "goal": "从页面经营数据卡片中提取经营数据",
127
+ "name": "refresh_homepage_metrics",
128
+ "goal": "点击指定时间粒度按钮并捕获首页经营指标接口响应",
129
+ "tool": "trigger_action",
130
+ "args": {
131
+ "action": "switch_metric_period",
132
+ "locators": [
133
+ {
134
+ "kind": "xpath",
135
+ "value": "//input[@type='radio' and @value='{{data.metricPeriodValue}}']/ancestor::label[1]",
136
+ "priority": 1
137
+ }
138
+ ],
139
+ "captureNetwork": {
140
+ "capturePlanId": "homepage_metrics"
141
+ }
142
+ }
143
+ },
144
+ {
145
+ "nodeId": "s4",
146
+ "name": "collect_homepage_metrics",
147
+ "goal": "从首页接口响应中投影经营数据与全店收支数据",
38
148
  "tool": "collect_structured_data",
39
149
  "args": {
40
- "extractor": "homepage_operating_data"
150
+ "extractor": "homepage_metrics_capture",
151
+ "sourceNodeId": "s3",
152
+ "metricPeriodValue": "{{data.metricPeriodValue}}"
41
153
  },
42
154
  "storeAs": "homepageApiResult",
43
155
  "outputs": [
@@ -23,6 +23,12 @@
23
23
  "description": "目标抓取问大家数量,默认 60",
24
24
  "default": 60
25
25
  },
26
+ {
27
+ "name": "includeAskAnswers",
28
+ "type": "boolean",
29
+ "description": "是否采集问大家,默认 false",
30
+ "default": false
31
+ },
26
32
  {
27
33
  "name": "returnHostPatterns",
28
34
  "type": "array",
@@ -106,7 +112,8 @@
106
112
  "tool": "trigger_action",
107
113
  "args": {
108
114
  "action": "open_ask_answers"
109
- }
115
+ },
116
+ "when": "equals(payload.includeAskAnswers, true)"
110
117
  },
111
118
  {
112
119
  "nodeId": "s8",
@@ -121,7 +128,8 @@
121
128
  "targetAskAnswerCount": "payload.targetAskAnswerCount"
122
129
  },
123
130
  "storeAs": "askAnswersData",
124
- "outputs": ["askAnswersData"]
131
+ "outputs": ["askAnswersData"],
132
+ "when": "equals(payload.includeAskAnswers, true)"
125
133
  },
126
134
  {
127
135
  "nodeId": "s9",