cnks 0.2.5__py3-none-any.whl → 0.3.1__py3-none-any.whl

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.
src/cssci.py ADDED
@@ -0,0 +1,267 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ CSSCI筛选模块 (China Social Sciences Citation Index Filter)
6
+
7
+ 这个模块负责在知网等学术搜索页面中查找并勾选CSSCI来源类别筛选选项。
8
+ CSSCI(中文社会科学引文索引)是一个重要的中文社科类期刊评价体系。
9
+
10
+ 主要职责:
11
+ 1. 在搜索结果页面中定位来源类别筛选区域
12
+ 2. 查找并勾选CSSCI复选框
13
+ 3. 应用筛选并等待结果加载
14
+ """
15
+
16
+ import logging
17
+ import traceback
18
+ import asyncio
19
+ from typing import Dict, Any
20
+
21
+ # 获取logger
22
+ logger = logging.getLogger("cnks.cssci")
23
+
24
+ js_button_finder = """
25
+ () => {
26
+ try {
27
+ // 首先尝试找到带有"CSSCI"文本的链接
28
+ let foundElement = null;
29
+
30
+ // 尝试查找带有title="CSSCI"的链接
31
+ const cssciLinks = document.querySelectorAll('a[title="CSSCI"]');
32
+ if (cssciLinks.length > 0) {
33
+ foundElement = cssciLinks[0];
34
+ return {
35
+ found: true,
36
+ x: foundElement.getBoundingClientRect().left + foundElement.getBoundingClientRect().width/2,
37
+ y: foundElement.getBoundingClientRect().top + foundElement.getBoundingClientRect().height/2,
38
+ method: 'title_link',
39
+ message: "找到带有title='CSSCI'的链接元素"
40
+ };
41
+ }
42
+
43
+ // 尝试查找包含CSSCI文本的链接
44
+ const allLinks = document.querySelectorAll('a');
45
+ for (const link of allLinks) {
46
+ if (link.textContent && link.textContent.trim() === 'CSSCI') {
47
+ foundElement = link;
48
+ return {
49
+ found: true,
50
+ x: foundElement.getBoundingClientRect().left + foundElement.getBoundingClientRect().width/2,
51
+ y: foundElement.getBoundingClientRect().top + foundElement.getBoundingClientRect().height/2,
52
+ method: 'text_link',
53
+ message: "找到文本为'CSSCI'的链接元素"
54
+ };
55
+ }
56
+ }
57
+
58
+ // 尝试查找包含CSSCI文本的任何元素
59
+ const allElements = document.querySelectorAll('*');
60
+ for (const element of allElements) {
61
+ if (element.textContent &&
62
+ element.textContent.includes('CSSCI') &&
63
+ element.getBoundingClientRect().width > 0 &&
64
+ element.getBoundingClientRect().height > 0) {
65
+ foundElement = element;
66
+ return {
67
+ found: true,
68
+ x: foundElement.getBoundingClientRect().left + foundElement.getBoundingClientRect().width/2,
69
+ y: foundElement.getBoundingClientRect().top + foundElement.getBoundingClientRect().height/2,
70
+ method: 'any_element',
71
+ message: "找到包含'CSSCI'的元素"
72
+ };
73
+ }
74
+ }
75
+
76
+ // 未找到任何相关元素
77
+ return {
78
+ found: false,
79
+ message: "未找到任何包含'CSSCI'的可点击元素"
80
+ };
81
+ } catch (error) {
82
+ // 发生错误,返回错误信息
83
+ return {
84
+ found: false,
85
+ error: error.toString(),
86
+ message: "查找CSSCI元素时发生错误: " + error.toString()
87
+ };
88
+ }
89
+ }
90
+ """
91
+
92
+ async def apply_cssci_filter(page) -> Dict[str, Any]:
93
+ """
94
+ 在搜索结果页面中应用CSSCI筛选
95
+
96
+ Args:
97
+ page: Playwright页面对象
98
+
99
+ Returns:
100
+ Dict: 包含操作结果的字典,包括是否成功、消息等
101
+ """
102
+ logger.info("开始应用CSSCI筛选")
103
+ result = {
104
+ "success": True, # 默认为True,即使没找到也算成功(跳过继续处理)
105
+ "message": "",
106
+ "filter_applied": False
107
+ }
108
+
109
+ try:
110
+ # 使用JavaScript查找CSSCI元素
111
+ cssci_result = await page.evaluate(js_button_finder)
112
+ logger.info(f"CSSCI元素查找结果: {cssci_result}")
113
+
114
+ if cssci_result.get('found', False):
115
+ logger.info(f"通过方法 '{cssci_result.get('method', 'unknown')}' 找到CSSCI元素,准备点击")
116
+
117
+ # 使用鼠标点击坐标来模拟点击
118
+ x, y = cssci_result.get('x'), cssci_result.get('y')
119
+ await page.mouse.click(x, y)
120
+ logger.info(f"已点击坐标 ({x}, {y}) 处的CSSCI元素")
121
+
122
+ # 点击后等待短暂时间让页面响应,但不主动刷新
123
+ await page.wait_for_timeout(1000) # 等待1秒,让页面有时间响应
124
+
125
+ result["filter_applied"] = True
126
+ result["message"] = f"成功点击CSSCI元素({cssci_result.get('method', 'unknown')}方法),由页面自行处理更新"
127
+ else:
128
+ # 如果没找到CSSCI元素,记录消息但仍然继续处理
129
+ result["message"] = cssci_result.get('message', "未找到CSSCI元素,跳过筛选步骤")
130
+ logger.info(result["message"])
131
+
132
+ return result
133
+
134
+ except Exception as e:
135
+ logger.error(f"应用CSSCI筛选时发生错误: {str(e)}")
136
+ logger.error(traceback.format_exc())
137
+
138
+ result["message"] = f"应用CSSCI筛选时发生错误: {str(e)}"
139
+ return result
140
+
141
+ async def _click_apply_button(page):
142
+ """
143
+ 尝试点击筛选按钮以应用筛选
144
+
145
+ Args:
146
+ page: Playwright页面对象
147
+ """
148
+ # 等待一秒,确保页面状态已更新
149
+ await asyncio.sleep(1)
150
+
151
+ apply_buttons = [
152
+ '.filter-button',
153
+ '.apply-filter',
154
+ 'button[text="筛选"]',
155
+ 'button[text="应用"]',
156
+ 'button[text="确定"]',
157
+ 'input[type="button"][value="确定"]',
158
+ '.btn-primary',
159
+ '#btn_search'
160
+ ]
161
+
162
+ for btn_selector in apply_buttons:
163
+ try:
164
+ button = await page.query_selector(btn_selector)
165
+ if button:
166
+ logger.info(f"点击筛选应用按钮: {btn_selector}")
167
+ await button.click()
168
+ await page.wait_for_load_state("networkidle", timeout=10000)
169
+ return True
170
+ except Exception as e:
171
+ logger.warning(f"点击按钮 '{btn_selector}' 失败: {str(e)}")
172
+
173
+ # 如果没有找到标准按钮,尝试通过JavaScript应用筛选
174
+ logger.info("尝试通过JavaScript应用筛选")
175
+ apply_js = """
176
+ () => {
177
+ try {
178
+ // 尝试找到并点击筛选应用按钮
179
+ const buttons = document.querySelectorAll('button, input[type="button"], a.btn');
180
+ for (const button of buttons) {
181
+ if (button.textContent &&
182
+ (button.textContent.includes('筛选') ||
183
+ button.textContent.includes('应用') ||
184
+ button.textContent.includes('确定') ||
185
+ button.textContent.includes('搜索'))) {
186
+ button.click();
187
+ return { clicked: true, text: button.textContent.trim() };
188
+ }
189
+ }
190
+
191
+ // 尝试查找搜索按钮
192
+ const searchBtn = document.querySelector('#btn_search, .search-button, button[onclick*="search"]');
193
+ if (searchBtn) {
194
+ searchBtn.click();
195
+ return { clicked: true, type: 'search' };
196
+ }
197
+
198
+ // 尝试提交表单
199
+ const form = document.querySelector('form');
200
+ if (form) {
201
+ form.submit();
202
+ return { clicked: true, type: 'form' };
203
+ }
204
+
205
+ return { clicked: false };
206
+ } catch (e) {
207
+ return { clicked: false, error: e.toString() };
208
+ }
209
+ }
210
+ """
211
+
212
+ apply_result = await page.evaluate(apply_js)
213
+ if apply_result.get('clicked', False):
214
+ logger.info(f"通过JavaScript应用筛选成功: {apply_result}")
215
+ await page.wait_for_load_state("networkidle", timeout=10000)
216
+ return True
217
+
218
+ logger.warning("未找到应用筛选的按钮")
219
+ return False
220
+
221
+
222
+ # 用于独立测试的函数
223
+ async def test_cssci_filter(page_url):
224
+ """
225
+ 独立测试CSSCI筛选功能
226
+
227
+ Args:
228
+ page_url: 要测试的页面URL
229
+ """
230
+ from playwright.async_api import async_playwright
231
+
232
+ async with async_playwright() as p:
233
+ browser = await p.chromium.launch(headless=False)
234
+ page = await browser.new_page()
235
+
236
+ try:
237
+ await page.goto(page_url, wait_until="domcontentloaded")
238
+ await page.wait_for_load_state("networkidle")
239
+
240
+ result = await apply_cssci_filter(page)
241
+ print(f"测试结果: {result}")
242
+
243
+ # 截图保存结果
244
+ await page.screenshot(path="cssci_filter_test.png")
245
+ print("已保存测试结果截图")
246
+
247
+ # 等待查看结果
248
+ await asyncio.sleep(5)
249
+
250
+ finally:
251
+ await browser.close()
252
+
253
+ # 如果直接运行脚本
254
+ if __name__ == "__main__":
255
+ import sys
256
+
257
+ # 配置日志
258
+ logging.basicConfig(
259
+ level=logging.INFO,
260
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
261
+ )
262
+
263
+ # 获取命令行参数或使用默认URL
264
+ url = sys.argv[1] if len(sys.argv) > 1 else "https://kns.cnki.net/kns8s/search"
265
+
266
+ print(f"测试在页面 {url} 上应用CSSCI筛选")
267
+ asyncio.run(test_cssci_filter(url))
src/extractlink.py ADDED
@@ -0,0 +1,262 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ 链接提取模块(Extract Link Module)
6
+
7
+ 这是一个独立处理链接提取的模块,专门负责从知网搜索结果中提取有效的文章链接。
8
+ 使用多种选择器和模式匹配技术提取文章链接,确保提取到实际文章页面而非导航页。
9
+
10
+ 主要职责:
11
+ 1. 分析知网搜索结果页面结构
12
+ 2. 提取文章详情和摘要链接
13
+ 3. 过滤非文章链接
14
+ 4. 返回有效的文章链接列表
15
+ """
16
+
17
+ import logging
18
+ import traceback
19
+ import re
20
+ from typing import List, Dict, Any
21
+
22
+ # 设置日志记录器
23
+ logger = logging.getLogger("cnks.extractlink")
24
+
25
+ async def extract_links_from_page(page) -> List[str]:
26
+ """
27
+ 从知网搜索结果页面提取文章链接
28
+
29
+ Args:
30
+ page: Playwright页面对象
31
+
32
+ Returns:
33
+ List[str]: 提取到的文章链接列表
34
+ """
35
+ logger.info("开始从页面提取文章链接")
36
+
37
+ try:
38
+ # 首先尝试使用更精确的选择器直接查找文章链接
39
+ specific_selectors = [
40
+ # 知网常见文章链接选择器
41
+ '.result-table-list .result-table-item .left a.fz14', # 新版知网结果列表
42
+ '.search-result .dl_li .t_title a', # 部分旧版结果列表
43
+ '.result-list .article-item h3 a', # 另一版本
44
+ '.searchresult .list_item .title a', # 再一版本
45
+ '.resultlist .item_title a', # 另一种可能格式
46
+ 'a[href*="/detail/abstract?"]', # 包含abstract的链接
47
+ 'a[href*="/article/detail?"]', # 包含article/detail的链接
48
+ 'a[href*="dbcode="]', # 包含dbcode参数的链接
49
+ ]
50
+
51
+ # 使用JavaScript执行提取逻辑
52
+ js_extract = """
53
+ (selectors) => {
54
+ const results = {
55
+ links: [],
56
+ debug: {}
57
+ };
58
+
59
+ // 收集各选择器匹配数量作为调试信息
60
+ for (const selector of selectors) {
61
+ const elements = document.querySelectorAll(selector);
62
+ results.debug[selector] = elements.length;
63
+
64
+ for (const el of elements) {
65
+ const href = el.getAttribute('href');
66
+ if (href && !href.includes('javascript:') && !href.includes('mailto:')) {
67
+ // 收集链接和相关文本信息帮助验证
68
+ results.links.push({
69
+ url: href,
70
+ text: el.textContent.trim(),
71
+ selector: selector
72
+ });
73
+ }
74
+ }
75
+ }
76
+
77
+ // 如果上述选择器没有找到任何链接,尝试一个更通用但不太精确的方法
78
+ if (results.links.length === 0) {
79
+ // 查找所有链接并分析
80
+ const allLinks = document.querySelectorAll('a');
81
+ results.debug['allLinks'] = allLinks.length;
82
+
83
+ for (const link of allLinks) {
84
+ const href = link.getAttribute('href');
85
+ const text = link.textContent.trim();
86
+
87
+ // 检查链接是否可能是文章链接
88
+ if (href &&
89
+ !href.includes('javascript:') &&
90
+ !href.includes('mailto:') &&
91
+ (href.includes('/detail/') ||
92
+ href.includes('/article/') ||
93
+ href.includes('cnki.net') && href.includes('dbcode=') ||
94
+ text.length > 10 && !link.querySelector('img') && // 长文本且不包含图片可能是标题
95
+ !href.includes('/index') && // 排除导航链接
96
+ !href.includes('/search') && // 排除搜索链接
97
+ !href.includes('/help'))) { // 排除帮助链接
98
+
99
+ results.links.push({
100
+ url: href,
101
+ text: text,
102
+ selector: 'generic'
103
+ });
104
+ }
105
+ }
106
+ }
107
+
108
+ // 如果仍然没有找到链接,记录页面结构用于调试
109
+ if (results.links.length === 0) {
110
+ results.debug.html = document.body.innerHTML.substring(0, 5000); // 前5000字符
111
+ }
112
+
113
+ return results;
114
+ }
115
+ """
116
+
117
+ # 执行JavaScript获取链接
118
+ extract_result = await page.evaluate(js_extract, specific_selectors)
119
+
120
+ # 分析提取结果
121
+ if not extract_result.get('links'):
122
+ logger.warning("未找到任何文章链接")
123
+ # 记录选择器匹配情况
124
+ for selector, count in extract_result.get('debug', {}).items():
125
+ if selector != 'html': # 不打印HTML内容
126
+ logger.debug(f"选择器 '{selector}' 匹配到 {count} 个元素")
127
+
128
+ # 进行截图以便分析
129
+ screenshot_path = "search_results.png"
130
+ await page.screenshot(path=screenshot_path)
131
+ logger.info(f"已保存搜索结果页面截图到 {screenshot_path}")
132
+
133
+ # 如果提供了HTML调试信息
134
+ if 'html' in extract_result.get('debug', {}):
135
+ logger.debug("页面结构片段:\n" + extract_result['debug']['html'][:500] + "...")
136
+
137
+ return []
138
+
139
+ # 从返回的对象中提取URL
140
+ raw_links = [item['url'] for item in extract_result['links']]
141
+ logger.info(f"初步提取到 {len(raw_links)} 个链接")
142
+
143
+ # 确保所有链接是绝对URL
144
+ page_url = page.url
145
+ processed_links = []
146
+ for link in raw_links:
147
+ # 如果是相对链接,转换为绝对链接
148
+ if not link.startswith('http'):
149
+ if link.startswith('/'):
150
+ # 从页面URL获取基本域名
151
+ match = re.match(r'(https?://[^/]+)', page_url)
152
+ if match:
153
+ base_url = match.group(1)
154
+ absolute_link = base_url + link
155
+ processed_links.append(absolute_link)
156
+ continue
157
+ # 如果无法处理,跳过
158
+ logger.warning(f"无法处理相对链接: {link}")
159
+ continue
160
+
161
+ processed_links.append(link)
162
+
163
+ # 过滤处理后的链接
164
+ filtered_links = filter_article_links(processed_links)
165
+ logger.info(f"过滤后保留 {len(filtered_links)} 个有效文章链接")
166
+
167
+ # 打印样本链接进行分析
168
+ if filtered_links:
169
+ sample_size = min(5, len(filtered_links))
170
+ sample_links = filtered_links[:sample_size]
171
+ logger.info(f"样本链接分析:")
172
+ for i, link in enumerate(sample_links):
173
+ logger.info(f"样本 {i+1}: {link}")
174
+
175
+ return filtered_links
176
+
177
+ except Exception as e:
178
+ logger.error(f"提取链接时出错: {str(e)}")
179
+ logger.error(traceback.format_exc())
180
+ return []
181
+
182
+ def filter_article_links(links: List[str]) -> List[str]:
183
+ """
184
+ 过滤链接列表,只保留可能的知网文章链接
185
+
186
+ Args:
187
+ links: 需要过滤的链接列表
188
+
189
+ Returns:
190
+ List[str]: 过滤后的文章链接列表
191
+ """
192
+ # 知网文章URL的常见模式
193
+ article_patterns = [
194
+ # 常见知网文章地址模式
195
+ r'kns\.cnki\.net/([^/]+/)+detail/abstract',
196
+ r'kns\.cnki\.net/([^/]+/)*article/detail',
197
+ r'cnki\.net/kcms/detail/detail\.aspx',
198
+ r'cnki\.net/KCMS/detail/detail\.aspx',
199
+ r'cnki\.net/.*?dbcode=',
200
+ r'academic\.cnki\.net/.*?doi=',
201
+ r'cnki\.com\.cn/Article/CJFDTotal-',
202
+ # 排除明确不是文章的链接
203
+ r'kns\.cnki\.net/.*?/article/',
204
+ r'.*dblp=.*', # 包含dblp参数
205
+ r'.*dbta=.*' # 包含dbta参数
206
+ ]
207
+
208
+ # 编译正则表达式提高效率
209
+ patterns = [re.compile(pattern, re.IGNORECASE) for pattern in article_patterns]
210
+
211
+ # 过滤链接
212
+ filtered_links = []
213
+ for link in links:
214
+ # 跳过明显的非文章链接
215
+ if any(x in link.lower() for x in [
216
+ 'index.html', 'help.cnki.net', 'service.cnki.net',
217
+ 'piccache.cnki.net', 'login', 'register', 'my.cnki',
218
+ 'homepage', 'download.aspx', 'member.cnki'
219
+ ]):
220
+ continue
221
+
222
+ # 检查是否匹配任何文章模式
223
+ is_article = False
224
+ for pattern in patterns:
225
+ if pattern.search(link):
226
+ is_article = True
227
+ break
228
+
229
+ if is_article:
230
+ filtered_links.append(link)
231
+
232
+ # 确保链接唯一
233
+ return list(set(filtered_links))
234
+
235
+ # 独立测试函数
236
+ async def test_extract_links(page):
237
+ """
238
+ 测试链接提取功能
239
+
240
+ Args:
241
+ page: Playwright页面对象
242
+
243
+ Returns:
244
+ Dict: 测试结果
245
+ """
246
+ try:
247
+ links = await extract_links_from_page(page)
248
+ return {
249
+ "success": True,
250
+ "links": links,
251
+ "count": len(links)
252
+ }
253
+ except Exception as e:
254
+ return {
255
+ "success": False,
256
+ "error": str(e),
257
+ "message": "提取链接测试失败"
258
+ }
259
+
260
+ # 如果直接执行此脚本
261
+ if __name__ == "__main__":
262
+ print("链接提取模块 - 必须通过其他模块调用")
src/ifverify.py ADDED
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ 验证检测模块(IfVerify Module)
6
+
7
+ 这个模块用于检测页面是否需要人工验证(如CAPTCHA、验证码等)。
8
+ 可以被工作者模块和其他需要验证检测的模块引用。
9
+
10
+ 主要职责:
11
+ 1. 分析页面内容,检测可能的验证元素
12
+ 2. 辅助交互自动化流程中的人工验证步骤
13
+ """
14
+
15
+ import logging
16
+ import traceback
17
+ from typing import Dict, Any
18
+
19
+ # 获取logger
20
+ logger = logging.getLogger("cnks.ifverify")
21
+
22
+ async def check_verification_needed(page) -> bool:
23
+ """
24
+ 检查页面是否需要人工验证
25
+
26
+ Args:
27
+ page: Playwright页面对象
28
+
29
+ Returns:
30
+ bool: 是否需要人工验证
31
+ """
32
+ try:
33
+ # 检查是否存在验证相关元素
34
+ verification_elements = [
35
+ # 验证码图片
36
+ 'img[src*="captcha"]',
37
+ 'img[src*="verify"]',
38
+ # 验证码输入框
39
+ 'input[name*="captcha"]',
40
+ 'input[placeholder*="验证码"]',
41
+ # 验证提示文本
42
+ 'div:has-text("请输入验证码")',
43
+ 'div:has-text("安全验证")',
44
+ 'div:has-text("请完成验证")'
45
+ ]
46
+
47
+ for selector in verification_elements:
48
+ element = await page.query_selector(selector)
49
+ if element:
50
+ logger.info(f"检测到验证元素: {selector}")
51
+ return True
52
+
53
+ # 检查页面标题或URL是否包含验证相关关键词
54
+ title = await page.title()
55
+ url = page.url
56
+ verification_keywords = ["verification", "verify", "captcha", "验证", "安全检查"]
57
+
58
+ for keyword in verification_keywords:
59
+ if keyword.lower() in title.lower() or keyword.lower() in url.lower():
60
+ logger.info(f"页面标题或URL包含验证关键词: {keyword}")
61
+ return True
62
+
63
+ logger.info("未检测到需要人工验证的元素")
64
+ return False
65
+
66
+ except Exception as e:
67
+ logger.warning(f"检查验证页面时出错: {str(e)}")
68
+ logger.warning(traceback.format_exc())
69
+ # 如果出错,保险起见认为需要验证
70
+ return True
71
+
72
+ async def handle_verification(page, wait_time: int = 10000) -> bool:
73
+ """
74
+ 处理可能的人工验证需求
75
+
76
+ Args:
77
+ page: Playwright页面对象
78
+ wait_time: 等待人工验证的时间(毫秒)
79
+
80
+ Returns:
81
+ bool: 是否成功处理验证
82
+ """
83
+ try:
84
+ # 检查是否需要验证
85
+ needs_verification = await check_verification_needed(page)
86
+
87
+ if needs_verification:
88
+ logger.info(f"检测到需要人工验证,等待{wait_time/1000}秒钟...")
89
+ # 等待指定时间让用户进行验证
90
+ await page.wait_for_timeout(wait_time)
91
+
92
+ # 再次检查是否仍需验证
93
+ still_needs_verification = await check_verification_needed(page)
94
+ if still_needs_verification:
95
+ logger.warning("验证可能尚未完成,但等待时间已到")
96
+ return False
97
+ else:
98
+ logger.info("验证已完成,继续执行")
99
+ return True
100
+ else:
101
+ logger.info("无需人工验证")
102
+ return True
103
+
104
+ except Exception as e:
105
+ logger.error(f"处理验证过程中出错: {str(e)}")
106
+ logger.error(traceback.format_exc())
107
+ return False
108
+
109
+ def test_verification_selectors() -> Dict[str, Any]:
110
+ """
111
+ 返回用于验证检测的元素选择器列表,
112
+ 可用于测试或扩展验证检测能力
113
+
114
+ Returns:
115
+ Dict: 包含各类验证元素选择器的字典
116
+ """
117
+ return {
118
+ "image_selectors": [
119
+ 'img[src*="captcha"]',
120
+ 'img[src*="verify"]'
121
+ ],
122
+ "input_selectors": [
123
+ 'input[name*="captcha"]',
124
+ 'input[placeholder*="验证码"]'
125
+ ],
126
+ "text_selectors": [
127
+ 'div:has-text("请输入验证码")',
128
+ 'div:has-text("安全验证")',
129
+ 'div:has-text("请完成验证")'
130
+ ],
131
+ "verification_keywords": [
132
+ "verification", "verify", "captcha", "验证", "安全检查"
133
+ ]
134
+ }