fast-crawl-core 0.0.1__tar.gz
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.
- fast_crawl_core-0.0.1/MANIFEST.in +0 -0
- fast_crawl_core-0.0.1/PKG-INFO +16 -0
- fast_crawl_core-0.0.1/README.rst +4 -0
- fast_crawl_core-0.0.1/fast_crawl_core/__init__.py +1 -0
- fast_crawl_core-0.0.1/fast_crawl_core/client/__init__.py +0 -0
- fast_crawl_core-0.0.1/fast_crawl_core/client/mongo_client.py +104 -0
- fast_crawl_core-0.0.1/fast_crawl_core/client/portainer_client.py +85 -0
- fast_crawl_core-0.0.1/fast_crawl_core/client/redis_client.py +22 -0
- fast_crawl_core-0.0.1/fast_crawl_core/dao/__init__.py +0 -0
- fast_crawl_core-0.0.1/fast_crawl_core/dao/auth_user_spider_group.py +69 -0
- fast_crawl_core-0.0.1/fast_crawl_core/dao/batch_spider.py +47 -0
- fast_crawl_core-0.0.1/fast_crawl_core/dao/batch_spider_group.py +67 -0
- fast_crawl_core-0.0.1/fast_crawl_core/dao/meta.py +32 -0
- fast_crawl_core-0.0.1/fast_crawl_core/dao/node.py +27 -0
- fast_crawl_core-0.0.1/fast_crawl_core/dao/spider.py +58 -0
- fast_crawl_core-0.0.1/fast_crawl_core/dao/spider_group.py +67 -0
- fast_crawl_core-0.0.1/fast_crawl_core/dao/stream_spider.py +41 -0
- fast_crawl_core-0.0.1/fast_crawl_core/dao/stream_spider_group.py +40 -0
- fast_crawl_core-0.0.1/fast_crawl_core/model/__init__.py +0 -0
- fast_crawl_core-0.0.1/fast_crawl_core/model/base.py +59 -0
- fast_crawl_core-0.0.1/fast_crawl_core/model/batch.py +110 -0
- fast_crawl_core-0.0.1/fast_crawl_core/model/entity.py +212 -0
- fast_crawl_core-0.0.1/fast_crawl_core/model/enums.py +93 -0
- fast_crawl_core-0.0.1/fast_crawl_core/model/rabbit.py +38 -0
- fast_crawl_core-0.0.1/fast_crawl_core/model/stream.py +68 -0
- fast_crawl_core-0.0.1/fast_crawl_core/publish/__init__.py +0 -0
- fast_crawl_core-0.0.1/fast_crawl_core/publish/batch.py +252 -0
- fast_crawl_core-0.0.1/fast_crawl_core/publish/stream.py +234 -0
- fast_crawl_core-0.0.1/fast_crawl_core/receive/__init__.py +0 -0
- fast_crawl_core-0.0.1/fast_crawl_core/receive/async_receuver.py +86 -0
- fast_crawl_core-0.0.1/fast_crawl_core/receive/exceptions.py +11 -0
- fast_crawl_core-0.0.1/fast_crawl_core/receive/key_builder.py +27 -0
- fast_crawl_core-0.0.1/fast_crawl_core/receive/model.py +66 -0
- fast_crawl_core-0.0.1/fast_crawl_core/receive/processor.py +46 -0
- fast_crawl_core-0.0.1/fast_crawl_core/receive/receiver.py +192 -0
- fast_crawl_core-0.0.1/fast_crawl_core/service/__init__.py +0 -0
- fast_crawl_core-0.0.1/fast_crawl_core/service/base.py +23 -0
- fast_crawl_core-0.0.1/fast_crawl_core/service/batch_spider.py +10 -0
- fast_crawl_core-0.0.1/fast_crawl_core/service/batch_spider_group.py +26 -0
- fast_crawl_core-0.0.1/fast_crawl_core/service/spider.py +16 -0
- fast_crawl_core-0.0.1/fast_crawl_core/service/spider_group.py +35 -0
- fast_crawl_core-0.0.1/fast_crawl_core/service/stream_spider.py +20 -0
- fast_crawl_core-0.0.1/fast_crawl_core/service/stream_spider_group.py +50 -0
- fast_crawl_core-0.0.1/fast_crawl_core/util/__init__.py +0 -0
- fast_crawl_core-0.0.1/fast_crawl_core/util/cfg.py +60 -0
- fast_crawl_core-0.0.1/fast_crawl_core/util/decator.py +13 -0
- fast_crawl_core-0.0.1/fast_crawl_core/util/exceptions.py +11 -0
- fast_crawl_core-0.0.1/fast_crawl_core/util/logger.py +51 -0
- fast_crawl_core-0.0.1/fast_crawl_core/util/rabbit_key.py +21 -0
- fast_crawl_core-0.0.1/fast_crawl_core/util/redis_key.py +21 -0
- fast_crawl_core-0.0.1/fast_crawl_core/util/sequence.py +34 -0
- fast_crawl_core-0.0.1/fast_crawl_core/util/time.py +151 -0
- fast_crawl_core-0.0.1/fast_crawl_core.egg-info/PKG-INFO +16 -0
- fast_crawl_core-0.0.1/fast_crawl_core.egg-info/SOURCES.txt +57 -0
- fast_crawl_core-0.0.1/fast_crawl_core.egg-info/dependency_links.txt +1 -0
- fast_crawl_core-0.0.1/fast_crawl_core.egg-info/requires.txt +1 -0
- fast_crawl_core-0.0.1/fast_crawl_core.egg-info/top_level.txt +1 -0
- fast_crawl_core-0.0.1/setup.cfg +4 -0
- fast_crawl_core-0.0.1/setup.py +20 -0
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: fast-crawl-core
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: fast crawl core for zsodata
|
|
5
|
+
Home-page: http://www.zsodata.com
|
|
6
|
+
Author: zsodata
|
|
7
|
+
Author-email: team@zso.io
|
|
8
|
+
License: BSD License
|
|
9
|
+
Platform: all
|
|
10
|
+
Requires-Python: >=3.7
|
|
11
|
+
Requires-Dist: zcbot-url-parser
|
|
12
|
+
|
|
13
|
+
pip uninstall fast-crawl-core
|
|
14
|
+
|
|
15
|
+
pip install --upgrade fast-crawl-core -i https://pypi.python.org/simple
|
|
16
|
+
pip show fast-crawl-core
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
File without changes
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import pytz
|
|
3
|
+
from motor.motor_asyncio import AsyncIOMotorClient
|
|
4
|
+
|
|
5
|
+
from ..util import cfg
|
|
6
|
+
from ..util.exceptions import NoConfigException
|
|
7
|
+
from ..util.decator import singleton
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@singleton
|
|
11
|
+
class Mongo(object):
|
|
12
|
+
"""
|
|
13
|
+
Mongo异步客户端简易封装(使用motor)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, mongo_uri: str = None, mongo_db: str = None, *args, **kwargs):
|
|
17
|
+
self.mongo_uri = mongo_uri or cfg.get('ZCBOT_CORE_MONGO_URL')
|
|
18
|
+
self.mongo_db = mongo_db or cfg.get('ZCBOT_CORE_MONGO_DB')
|
|
19
|
+
if not self.mongo_uri:
|
|
20
|
+
raise NoConfigException('mongodb uri not config!')
|
|
21
|
+
if not self.mongo_db:
|
|
22
|
+
raise NoConfigException('mongodb database not config!')
|
|
23
|
+
|
|
24
|
+
self.client = AsyncIOMotorClient(self.mongo_uri, tz_aware=True, tzinfo=pytz.timezone('Asia/Shanghai'))
|
|
25
|
+
self.db = self.client[self.mongo_db]
|
|
26
|
+
|
|
27
|
+
# 获取集合
|
|
28
|
+
def get_collection(self, coll):
|
|
29
|
+
return self.db.get_collection(coll)
|
|
30
|
+
|
|
31
|
+
# 查询对象
|
|
32
|
+
async def get(self, collection, query={}):
|
|
33
|
+
result = await self.db[collection].find_one(query)
|
|
34
|
+
return result
|
|
35
|
+
|
|
36
|
+
# 统计数量
|
|
37
|
+
async def count(self, collection, query={}):
|
|
38
|
+
return await self.db[collection].count_documents(query)
|
|
39
|
+
|
|
40
|
+
# 查询列表
|
|
41
|
+
async def list(self, collection, query={}, fields=None, sort=[]):
|
|
42
|
+
if fields:
|
|
43
|
+
cursor = self.db[collection].find(query, fields, sort=sort)
|
|
44
|
+
else:
|
|
45
|
+
cursor = self.db[collection].find(query, sort=sort)
|
|
46
|
+
return await cursor.to_list(length=None)
|
|
47
|
+
|
|
48
|
+
# 查询去重列表
|
|
49
|
+
async def distinct(self, collection, dist_key, query={}, fields=None):
|
|
50
|
+
return await self.db[collection].find(query, fields).distinct(dist_key)
|
|
51
|
+
|
|
52
|
+
# 聚合查询
|
|
53
|
+
async def aggregate(self, collection, pipeline=[]):
|
|
54
|
+
cursor = self.db[collection].aggregate(pipeline, allowDiskUse=True)
|
|
55
|
+
return await cursor.to_list(length=None)
|
|
56
|
+
|
|
57
|
+
# 查询分页列表
|
|
58
|
+
async def list_with_page(self, collection, query={}, page_size=10000, fields=None):
|
|
59
|
+
rows = list()
|
|
60
|
+
total = await self.db[collection].count_documents(query)
|
|
61
|
+
if total > 0 and page_size > 0:
|
|
62
|
+
total_page = round(total / page_size)
|
|
63
|
+
for page in range(0, total_page):
|
|
64
|
+
if fields:
|
|
65
|
+
cursor = self.db[collection].find(query, fields).skip(page_size * page).limit(page)
|
|
66
|
+
else:
|
|
67
|
+
cursor = self.db[collection].find(query).skip(page_size * page).limit(page)
|
|
68
|
+
curr_batch = await cursor.to_list(length=None)
|
|
69
|
+
if curr_batch:
|
|
70
|
+
rows.append(curr_batch)
|
|
71
|
+
return rows
|
|
72
|
+
|
|
73
|
+
# 插入或更新
|
|
74
|
+
async def insert_or_update(self, collection, data, id_key='_id'):
|
|
75
|
+
return await self.db[collection].update_one({id_key: data[id_key]}, {'$set': data}, upsert=True)
|
|
76
|
+
|
|
77
|
+
# 更新
|
|
78
|
+
async def update(self, collection, filter, data, multi=False):
|
|
79
|
+
if multi:
|
|
80
|
+
return await self.db[collection].update_many(filter, {'$set': data})
|
|
81
|
+
return await self.db[collection].update_one(filter, {'$set': data})
|
|
82
|
+
|
|
83
|
+
# 以主键更新
|
|
84
|
+
async def update_by_pk(self, collection, pk_val, data):
|
|
85
|
+
return await self.db[collection].update_one({'_id': pk_val}, {'$set': data})
|
|
86
|
+
|
|
87
|
+
# 批量更新
|
|
88
|
+
async def batch_update(self, collection, filter, datas, multi=False):
|
|
89
|
+
if multi:
|
|
90
|
+
return await self.db[collection].update_many(filter, datas)
|
|
91
|
+
return await self.db[collection].update_one(filter, datas)
|
|
92
|
+
|
|
93
|
+
# 删除
|
|
94
|
+
async def delete(self, collection, filter):
|
|
95
|
+
return await self.db[collection].delete_many(filter)
|
|
96
|
+
|
|
97
|
+
# 批量写入
|
|
98
|
+
async def bulk_write(self, collection, bulk_list):
|
|
99
|
+
if bulk_list:
|
|
100
|
+
return await self.db[collection].bulk_write(bulk_list, ordered=False, bypass_document_validation=True)
|
|
101
|
+
|
|
102
|
+
# 关闭链接
|
|
103
|
+
def close(self):
|
|
104
|
+
self.client.close()
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import json
|
|
3
|
+
import aiohttp
|
|
4
|
+
from ..util import logger
|
|
5
|
+
from ..util.decator import singleton
|
|
6
|
+
from ..model.entity import PortainerNode, BatchSpider
|
|
7
|
+
|
|
8
|
+
LOGGER = logger.get('容器')
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@singleton
|
|
12
|
+
class PortainerClient(object):
|
|
13
|
+
"""
|
|
14
|
+
Portainer异步客户端简易封装(使用aiohttp)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
self.user_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3775.400 QQBrowser/10.6.4208.400'
|
|
19
|
+
# 客户端
|
|
20
|
+
self.create_api = '{}/api/endpoints/{}/docker/containers/create?name={}'
|
|
21
|
+
self.start_api = '{}/api/endpoints/{}/docker/containers/{}/start'
|
|
22
|
+
self.stop_api = '{}/api/endpoints/{}/docker/containers/{}/kill'
|
|
23
|
+
|
|
24
|
+
async def create_container(self, node: PortainerNode, spider: BatchSpider, container_name: str, param_data):
|
|
25
|
+
container_conf = {
|
|
26
|
+
"Cmd": [
|
|
27
|
+
"/bin/sh",
|
|
28
|
+
"-c",
|
|
29
|
+
spider.param % param_data
|
|
30
|
+
],
|
|
31
|
+
"Env": spider.env,
|
|
32
|
+
"Image": spider.dockerImage
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async with aiohttp.ClientSession() as session:
|
|
36
|
+
async with session.post(
|
|
37
|
+
url=self.create_api.format(node.apiBaseUrl, node.endpointId, container_name),
|
|
38
|
+
headers={
|
|
39
|
+
'X-API-Key': node.apiToken,
|
|
40
|
+
'User-Agent': self.user_agent,
|
|
41
|
+
'Content-Type': 'application/json;charset=UTF-8',
|
|
42
|
+
},
|
|
43
|
+
data=json.dumps(container_conf)
|
|
44
|
+
) as resp:
|
|
45
|
+
text = await resp.text()
|
|
46
|
+
if resp.status in [200, 201]:
|
|
47
|
+
data = json.loads(text) or {}
|
|
48
|
+
if data.get('Id', None):
|
|
49
|
+
id = data.get('Id', '')
|
|
50
|
+
LOGGER.info(f'创建成功: id={id}, endpoint={node.endpointId} name={container_name}')
|
|
51
|
+
return id
|
|
52
|
+
|
|
53
|
+
LOGGER.error(f'创建失败: result={text}, endpoint={node.endpointId} name={container_name}')
|
|
54
|
+
|
|
55
|
+
async def start(self, node: PortainerNode, container_id: str):
|
|
56
|
+
async with aiohttp.ClientSession() as session:
|
|
57
|
+
async with session.post(
|
|
58
|
+
url=self.start_api.format(node.apiBaseUrl, node.endpointId, container_id),
|
|
59
|
+
headers={
|
|
60
|
+
'X-API-Key': node.apiToken,
|
|
61
|
+
'User-Agent': self.user_agent,
|
|
62
|
+
'Content-Type': 'application/json;charset=UTF-8',
|
|
63
|
+
}
|
|
64
|
+
) as resp:
|
|
65
|
+
if resp.status in [204, 200]:
|
|
66
|
+
LOGGER.info(f'启动成功: id={container_id}')
|
|
67
|
+
return container_id
|
|
68
|
+
|
|
69
|
+
LOGGER.error(f'启动失败: id={container_id}')
|
|
70
|
+
|
|
71
|
+
async def stop(self, node: PortainerNode, container_id: str):
|
|
72
|
+
async with aiohttp.ClientSession() as session:
|
|
73
|
+
async with session.post(
|
|
74
|
+
url=self.stop_api.format(node.apiBaseUrl, node.endpointId, container_id),
|
|
75
|
+
headers={
|
|
76
|
+
'X-API-Key': node.apiToken,
|
|
77
|
+
'User-Agent': self.user_agent,
|
|
78
|
+
'Content-Type': 'application/json;charset=UTF-8',
|
|
79
|
+
}
|
|
80
|
+
) as resp:
|
|
81
|
+
if resp.status in [204, 200]:
|
|
82
|
+
LOGGER.info(f'停止成功: id={container_id}')
|
|
83
|
+
return container_id
|
|
84
|
+
|
|
85
|
+
LOGGER.error(f'停止失败: id={container_id}')
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import redis.asyncio as aioredis
|
|
3
|
+
from ..util import cfg
|
|
4
|
+
from ..util.decator import singleton
|
|
5
|
+
from ..util.exceptions import NoConfigException
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@singleton
|
|
9
|
+
class Redis(object):
|
|
10
|
+
"""
|
|
11
|
+
Redis异步客户端简易封装(单例,使用redis.asyncio)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, redis_uri: str = None, redis_db: int = None, decode_responses=True):
|
|
15
|
+
self.redis_uri = redis_uri or cfg.get('ZCBOT_CORE_REDIS_URL')
|
|
16
|
+
self.redis_db = redis_db or cfg.get('ZCBOT_CORE_REDIS_DB')
|
|
17
|
+
if not self.redis_uri:
|
|
18
|
+
raise NoConfigException('redis uri not config!')
|
|
19
|
+
if not self.redis_db:
|
|
20
|
+
raise NoConfigException('redis database not config!')
|
|
21
|
+
|
|
22
|
+
self.client = aioredis.Redis.from_url(url=self.redis_uri, db=self.redis_db, decode_responses=decode_responses)
|
|
File without changes
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from typing import List
|
|
3
|
+
from ..client.mongo_client import Mongo
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# 获取支持网站平台
|
|
7
|
+
async def get_platforms_by_group(group_code: str, enable: int = None):
|
|
8
|
+
_query = {}
|
|
9
|
+
if group_code:
|
|
10
|
+
_query["groupCode"] = group_code
|
|
11
|
+
if enable is not None:
|
|
12
|
+
_query["enable"] = enable
|
|
13
|
+
|
|
14
|
+
return await Mongo().list('zcbot_auth_user_spider_group', query=_query)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def get_platforms_by_group_code(group_code: str, enable):
|
|
18
|
+
_query = {
|
|
19
|
+
"groupCode": group_code
|
|
20
|
+
}
|
|
21
|
+
_fields = {
|
|
22
|
+
"spiders": 0,
|
|
23
|
+
"_id": 0
|
|
24
|
+
}
|
|
25
|
+
return await Mongo().aggregate('zcbot_platforms', [
|
|
26
|
+
{
|
|
27
|
+
'$lookup': {
|
|
28
|
+
'from': 'zcbot_auth_user_spider_group',
|
|
29
|
+
'localField': '_id',
|
|
30
|
+
'foreignField': 'platCode',
|
|
31
|
+
'as': 'spider'
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
'$match': {'spider.groupCode': group_code}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
'$project': {'spider': 0}
|
|
39
|
+
},
|
|
40
|
+
{'$sort': {'sort': 1}}
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# 根据爬虫组编号,获取可选的爬虫清单
|
|
45
|
+
async def get_spider_group(tenant_code: str = None, group_code: str = None, plat_code: str = None, enable: int = None):
|
|
46
|
+
_query = {}
|
|
47
|
+
if tenant_code:
|
|
48
|
+
_query["_id"] = f'{tenant_code}:{group_code}:{plat_code}:group'
|
|
49
|
+
if group_code:
|
|
50
|
+
_query["groupCode"] = group_code
|
|
51
|
+
if plat_code:
|
|
52
|
+
_query["platCode"] = plat_code
|
|
53
|
+
if enable is not None:
|
|
54
|
+
_query["enable"] = enable
|
|
55
|
+
|
|
56
|
+
return await Mongo().get('zcbot_auth_user_spider_group', query=_query)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# 根据爬虫组编号,获取爬虫组清单
|
|
60
|
+
async def get_spider_group_list(group_code: str = None, plat_codes: List[str] = None, enable: int = None):
|
|
61
|
+
_query = {}
|
|
62
|
+
if group_code:
|
|
63
|
+
_query["groupCode"] = group_code
|
|
64
|
+
if plat_codes and len(plat_codes):
|
|
65
|
+
_query["platCode"] = {"$in": plat_codes}
|
|
66
|
+
if enable is not None:
|
|
67
|
+
_query["enable"] = enable
|
|
68
|
+
|
|
69
|
+
return await Mongo().list('zcbot_auth_user_spider_group', query=_query)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from ..client.mongo_client import Mongo
|
|
4
|
+
from ..model.entity import BatchSpider
|
|
5
|
+
from ..model.enums import CommonStatus
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _build_task_group_key(task_group, plat_code):
|
|
9
|
+
return {'_id': f'{task_group}:{plat_code}:group'}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _build_stream_spider_key(task_type, plat_code):
|
|
13
|
+
return f'{task_type}:{plat_code}'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# 获取爬虫任务组配置
|
|
17
|
+
async def get_spider_group(task_group, plat_code):
|
|
18
|
+
return await Mongo().get('zcbot_batch_spider_group', _build_task_group_key(task_group, plat_code))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# 获取portainer爬虫配置
|
|
22
|
+
async def get_batch_spider(spider_id: str) -> Optional[BatchSpider]:
|
|
23
|
+
row = await Mongo().get('zcbot_batch_spider', {'spiderId': spider_id, 'status': CommonStatus.ON.name})
|
|
24
|
+
if not row:
|
|
25
|
+
return None
|
|
26
|
+
return BatchSpider(**row)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# 获取支持网站平台
|
|
30
|
+
async def get_platforms_by_spider_group(task_type: str):
|
|
31
|
+
return await Mongo().aggregate('zcbot_platforms', [
|
|
32
|
+
{
|
|
33
|
+
'$lookup': {
|
|
34
|
+
'from': 'zcbot_batch_spider_group',
|
|
35
|
+
'localField': '_id',
|
|
36
|
+
'foreignField': 'plat_code',
|
|
37
|
+
'as': 'spider'
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
'$match': {'spider.task_type': task_type.lower()}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
'$project': {'spider': 0}
|
|
45
|
+
},
|
|
46
|
+
{'$sort': {'sort': 1}}
|
|
47
|
+
])
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from typing import List
|
|
3
|
+
from ..client.mongo_client import Mongo
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# 获取支持网站平台
|
|
7
|
+
async def get_platforms_by_group(group_code: str, enable: int = None):
|
|
8
|
+
_query = {}
|
|
9
|
+
if group_code:
|
|
10
|
+
_query["groupCode"] = group_code
|
|
11
|
+
if enable is not None:
|
|
12
|
+
_query["enable"] = enable
|
|
13
|
+
|
|
14
|
+
return await Mongo().list('zcbot_batch_spider_group', query=_query)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def get_platforms_by_group_code(group_code: str, enable):
|
|
18
|
+
_query = {
|
|
19
|
+
"groupCode": group_code
|
|
20
|
+
}
|
|
21
|
+
_fields = {
|
|
22
|
+
"spiders": 0,
|
|
23
|
+
"_id": 0
|
|
24
|
+
}
|
|
25
|
+
return await Mongo().aggregate('zcbot_platforms', [
|
|
26
|
+
{
|
|
27
|
+
'$lookup': {
|
|
28
|
+
'from': 'zcbot_batch_spider_group',
|
|
29
|
+
'localField': '_id',
|
|
30
|
+
'foreignField': 'platCode',
|
|
31
|
+
'as': 'spider'
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
'$match': {'spider.groupCode': group_code}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
'$project': {'spider': 0}
|
|
39
|
+
},
|
|
40
|
+
{'$sort': {'sort': 1}}
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# 根据爬虫组编号,获取可选的爬虫清单
|
|
45
|
+
async def get_spider_group(group_code: str = None, plat_code: str = None, enable: int = None):
|
|
46
|
+
_query = {}
|
|
47
|
+
if group_code:
|
|
48
|
+
_query["groupCode"] = group_code
|
|
49
|
+
if plat_code:
|
|
50
|
+
_query["platCode"] = plat_code
|
|
51
|
+
if enable is not None:
|
|
52
|
+
_query["enable"] = enable
|
|
53
|
+
|
|
54
|
+
return await Mongo().get('zcbot_batch_spider_group', query=_query)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# 根据爬虫组编号,获取爬虫组清单
|
|
58
|
+
async def get_spider_group_list(group_code: str = None, plat_codes: List[str] = None, enable: int = None):
|
|
59
|
+
_query = {}
|
|
60
|
+
if group_code:
|
|
61
|
+
_query["groupCode"] = group_code
|
|
62
|
+
if plat_codes and len(plat_codes):
|
|
63
|
+
_query["platCode"] = {"$in": plat_codes}
|
|
64
|
+
if enable is not None:
|
|
65
|
+
_query["enable"] = enable
|
|
66
|
+
|
|
67
|
+
return await Mongo().list('zcbot_batch_spider_group', query=_query)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from ..client.mongo_client import Mongo
|
|
3
|
+
from ..model.base import Rule
|
|
4
|
+
from ..client.redis_client import Redis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# 获取链接分拣规则配置
|
|
8
|
+
async def get_url_parse_rule(host: str = None):
|
|
9
|
+
if host:
|
|
10
|
+
return Rule(**await Mongo().get(collection='zcbot_url_parse_rule', query={'_id': host}))
|
|
11
|
+
|
|
12
|
+
return [Rule(**x) for x in await Mongo().list(collection='zcbot_url_parse_rule')]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# 获取支持网站平台
|
|
16
|
+
async def get_platforms():
|
|
17
|
+
return await Mongo().list(collection='zcbot_platforms', sort=[('sort', 1)])
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# 获取文件命名规则配置
|
|
21
|
+
async def get_file_name_config(config_id):
|
|
22
|
+
return await Mongo().get(collection='zcbot_file_name_config', query={'_id': config_id})
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def create_pipeline():
|
|
26
|
+
pipe = Redis().client.pipeline()
|
|
27
|
+
return pipe
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
async def run_pipeline(pipe):
|
|
31
|
+
await pipe.execute()
|
|
32
|
+
del pipe
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from typing import Optional, List
|
|
3
|
+
from ..client.mongo_client import Mongo
|
|
4
|
+
from ..model.entity import PortainerNode
|
|
5
|
+
from ..model.enums import CommonStatus
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# 获取节点信息
|
|
9
|
+
async def get_node(node_id) -> Optional[PortainerNode]:
|
|
10
|
+
rs = await Mongo().get(collection='zcbot_portainer_node', query={'_id': node_id})
|
|
11
|
+
if not rs:
|
|
12
|
+
return None
|
|
13
|
+
|
|
14
|
+
return PortainerNode(**rs)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# 获取节点信息列表
|
|
18
|
+
async def get_node_list(query: dict = None, fields: dict = None, include_disable: bool = False) -> List[PortainerNode]:
|
|
19
|
+
_query = query or {}
|
|
20
|
+
_fields = fields or {}
|
|
21
|
+
if not include_disable:
|
|
22
|
+
_query['status'] = CommonStatus.ON.name
|
|
23
|
+
rows = await Mongo().list(collection='zcbot_portainer_node', query=_query, fields=_fields)
|
|
24
|
+
if rows:
|
|
25
|
+
return [PortainerNode(**row) for row in rows]
|
|
26
|
+
|
|
27
|
+
return []
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from typing import Optional, List
|
|
3
|
+
from ..client.mongo_client import Mongo
|
|
4
|
+
from ..model.entity import BatchSpider
|
|
5
|
+
from ..model.enums import CommonStatus
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _build_task_group_key(task_group, plat_code):
|
|
9
|
+
return {'_id': f'{task_group}:{plat_code}:group'}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _build_stream_spider_key(task_type, plat_code):
|
|
13
|
+
return f'{task_type}:{plat_code}'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# 获取爬虫任务组配置
|
|
17
|
+
async def get_spider_group(task_group, plat_code):
|
|
18
|
+
return await Mongo().get('zcbot_spider_group', _build_task_group_key(task_group, plat_code))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# 获取portainer爬虫配置
|
|
22
|
+
async def get_spider(spider_id: str, status: CommonStatus = CommonStatus.ON) -> Optional[BatchSpider]:
|
|
23
|
+
row = await Mongo().get('zcbot_spider', {'spiderId': spider_id, 'status': status.name})
|
|
24
|
+
if not row:
|
|
25
|
+
return None
|
|
26
|
+
return BatchSpider(**row)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# 获取支持网站平台
|
|
30
|
+
async def get_platforms_by_spider_group(task_type: str):
|
|
31
|
+
return await Mongo().aggregate('zcbot_platforms', [
|
|
32
|
+
{
|
|
33
|
+
'$lookup': {
|
|
34
|
+
'from': 'zcbot_spider_group',
|
|
35
|
+
'localField': '_id',
|
|
36
|
+
'foreignField': 'plat_code',
|
|
37
|
+
'as': 'spider'
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
'$match': {'spider.task_type': task_type.lower()}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
'$project': {'spider': 0}
|
|
45
|
+
},
|
|
46
|
+
{'$sort': {'sort': 1}}
|
|
47
|
+
])
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def get_spiders_by_id(spider_ids: List):
|
|
51
|
+
_query = {
|
|
52
|
+
"_id": {
|
|
53
|
+
"$in": spider_ids
|
|
54
|
+
},
|
|
55
|
+
"status": "ON"
|
|
56
|
+
}
|
|
57
|
+
rs = await Mongo().list("zcbot_spider", query=_query)
|
|
58
|
+
return rs
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from typing import List
|
|
3
|
+
from ..client.mongo_client import Mongo
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# 获取支持网站平台
|
|
7
|
+
async def get_platforms_by_group(group_code: str, enable: int = None):
|
|
8
|
+
_query = {}
|
|
9
|
+
if group_code:
|
|
10
|
+
_query["groupCode"] = group_code
|
|
11
|
+
if enable is not None:
|
|
12
|
+
_query["enable"] = enable
|
|
13
|
+
|
|
14
|
+
return await Mongo().list('zcbot_spider_group', query=_query)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def get_platforms_by_group_code(group_code: str, enable):
|
|
18
|
+
_query = {
|
|
19
|
+
"groupCode": group_code
|
|
20
|
+
}
|
|
21
|
+
_fields = {
|
|
22
|
+
"spiders": 0,
|
|
23
|
+
"_id": 0
|
|
24
|
+
}
|
|
25
|
+
return await Mongo().aggregate('zcbot_platforms', [
|
|
26
|
+
{
|
|
27
|
+
'$lookup': {
|
|
28
|
+
'from': 'zcbot_spider_group',
|
|
29
|
+
'localField': '_id',
|
|
30
|
+
'foreignField': 'platCode',
|
|
31
|
+
'as': 'spider'
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
'$match': {'spider.groupCode': group_code}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
'$project': {'spider': 0}
|
|
39
|
+
},
|
|
40
|
+
{'$sort': {'sort': 1}}
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# 根据爬虫组编号,获取可选的爬虫清单
|
|
45
|
+
async def get_spider_group(group_code: str = None, plat_code: str = None, enable: int = None):
|
|
46
|
+
_query = {}
|
|
47
|
+
if group_code:
|
|
48
|
+
_query["groupCode"] = group_code
|
|
49
|
+
if plat_code:
|
|
50
|
+
_query["platCode"] = plat_code
|
|
51
|
+
if enable is not None:
|
|
52
|
+
_query["enable"] = enable
|
|
53
|
+
|
|
54
|
+
return await Mongo().get('zcbot_spider_group', query=_query)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# 根据爬虫组编号,获取爬虫组清单
|
|
58
|
+
async def get_spider_group_list(group_code: str = None, plat_codes: List[str] = None, enable: int = None):
|
|
59
|
+
_query = {}
|
|
60
|
+
if group_code:
|
|
61
|
+
_query["groupCode"] = group_code
|
|
62
|
+
if plat_codes and len(plat_codes):
|
|
63
|
+
_query["platCode"] = {"$in": plat_codes}
|
|
64
|
+
if enable is not None:
|
|
65
|
+
_query["enable"] = enable
|
|
66
|
+
|
|
67
|
+
return await Mongo().list('zcbot_spider_group', query=_query)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from typing import Optional, List
|
|
3
|
+
from ..client.mongo_client import Mongo
|
|
4
|
+
from ..model.entity import StreamSpider, StreamSpiderModel
|
|
5
|
+
from ..model.enums import CommonStatus
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# 获取portainer爬虫配置
|
|
9
|
+
async def get_stream_spiders(spider_ids: List[str], status: CommonStatus) -> List[StreamSpider]:
|
|
10
|
+
rows = await Mongo().list("zcbot_stream_spider", {'spiderId': {'$in': spider_ids}, 'status': status.name})
|
|
11
|
+
if not rows:
|
|
12
|
+
return []
|
|
13
|
+
return [StreamSpider(**x) for x in rows]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def get_stream_spider(spider_id: str, status: CommonStatus) -> Optional[StreamSpiderModel]:
|
|
17
|
+
row = await Mongo().get('zcbot_stream_spider', {'spiderId': spider_id, 'status': status.name})
|
|
18
|
+
if not row:
|
|
19
|
+
return None
|
|
20
|
+
return StreamSpiderModel(**row)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# 获取支持网站平台
|
|
24
|
+
async def get_platforms_by_spider_id(spider_ids: List[str], status: CommonStatus):
|
|
25
|
+
return await Mongo().aggregate('zcbot_platforms', [
|
|
26
|
+
{
|
|
27
|
+
'$lookup': {
|
|
28
|
+
'from': 'zcbot_stream_spider',
|
|
29
|
+
'localField': '_id',
|
|
30
|
+
'foreignField': 'plat_code',
|
|
31
|
+
'as': 'spider'
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
'$match': {'spider._id': {'$in': spider_ids}, 'status': status.name}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
'$project': {'spider': 0}
|
|
39
|
+
},
|
|
40
|
+
{'$sort': {'sort': 1}}
|
|
41
|
+
])
|