|
8 | 8 | @email: boris@bzkj.tech |
9 | 9 | """ |
10 | 10 |
|
| 11 | +import importlib |
11 | 12 | import threading |
12 | 13 | from queue import Queue |
13 | 14 |
|
|
16 | 17 | from feapder.db.redisdb import RedisDB |
17 | 18 | from feapder.dedup import Dedup |
18 | 19 | from feapder.network.item import Item, UpdateItem |
19 | | -from feapder.utils.export_data import ExportData |
| 20 | +from feapder.piplines import BasePipline |
20 | 21 | from feapder.utils.log import log |
21 | 22 |
|
22 | 23 | MAX_ITEM_COUNT = 5000 # 缓存中最大item数 |
23 | 24 | UPLOAD_BATCH_MAX_SIZE = 1000 |
24 | 25 |
|
| 26 | +MYSQL_PIPLINE_PATH = "feapder.piplines.mysql_pipline.MysqlPipline" |
| 27 | + |
25 | 28 |
|
26 | 29 | class Singleton(object): |
27 | 30 | def __new__(cls, *args, **kwargs): |
@@ -56,23 +59,34 @@ def __init__(self, redis_key): |
56 | 59 | # 'xxx:xxx_item': ['id', 'name'...] # 记录redis中item名与需要更新的key对应关系 |
57 | 60 | } |
58 | 61 |
|
59 | | - self._export_data = ExportData() if setting.ADD_ITEM_TO_MYSQL else None |
| 62 | + self._piplines = self.load_piplines() |
60 | 63 |
|
61 | | - self.db_tip() |
| 64 | + self._have_mysql_pipline = MYSQL_PIPLINE_PATH in setting.ITEM_PIPLINES |
| 65 | + self._mysql_pipline = None |
62 | 66 |
|
63 | 67 | if setting.ITEM_FILTER_ENABLE and not self.__class__.dedup: |
64 | 68 | self.__class__.dedup = Dedup(to_md5=False) |
65 | 69 |
|
66 | | - def db_tip(self): |
67 | | - msg = "" |
68 | | - if setting.ADD_ITEM_TO_MYSQL: |
69 | | - msg += "item 自动入mysql " |
70 | | - if setting.ADD_ITEM_TO_REDIS: |
71 | | - msg += "item 自动入redis " |
72 | | - if not msg: |
73 | | - log.warning("*** 请注意检查item是否入库 !!!") |
74 | | - else: |
75 | | - log.info(msg) |
| 70 | + def load_piplines(self): |
| 71 | + piplines = [] |
| 72 | + for pipline_path in setting.ITEM_PIPLINES: |
| 73 | + module, class_name = pipline_path.rsplit(".", 1) |
| 74 | + pipline_cls = importlib.import_module(module).__getattribute__(class_name) |
| 75 | + pipline = pipline_cls() |
| 76 | + if not isinstance(pipline, BasePipline): |
| 77 | + raise ValueError(f"{pipline_path} 需继承 feapder.piplines.BasePipline") |
| 78 | + piplines.append(pipline) |
| 79 | + |
| 80 | + return piplines |
| 81 | + |
| 82 | + @property |
| 83 | + def mysql_pipline(self): |
| 84 | + if not self._mysql_pipline: |
| 85 | + module, class_name = MYSQL_PIPLINE_PATH.rsplit(".", 1) |
| 86 | + pipline_cls = importlib.import_module(module).__getattribute__(class_name) |
| 87 | + self._mysql_pipline = pipline_cls() |
| 88 | + |
| 89 | + return self._mysql_pipline |
76 | 90 |
|
77 | 91 | def run(self): |
78 | 92 | while not self._thread_stop: |
@@ -225,48 +239,29 @@ def __pick_items(self, items, is_update_item=False): |
225 | 239 | return datas_dict |
226 | 240 |
|
227 | 241 | def __export_to_db(self, tab_item, datas, is_update=False, update_keys=()): |
228 | | - export_success = False |
229 | | - # 打点 校验 |
230 | 242 | to_table = tools.get_info(tab_item, ":s_(.*?)_item$", fetch_one=True) |
231 | | - item_name = to_table + "_item" |
232 | | - self.check_datas(table=to_table, datas=datas) |
233 | 243 |
|
234 | | - if setting.ADD_ITEM_TO_MYSQL: # 任务表需要入mysql |
235 | | - if isinstance(setting.ADD_ITEM_TO_MYSQL, (list, tuple)): |
236 | | - for item in setting.ADD_ITEM_TO_MYSQL: |
237 | | - if item in item_name: |
238 | | - export_success = ( |
239 | | - self._export_data.export_items(to_table, datas) |
240 | | - if not is_update |
241 | | - else self._export_data.update_items( |
242 | | - to_table, datas, update_keys=update_keys |
243 | | - ) |
244 | | - ) |
| 244 | + # 打点 校验 |
| 245 | + self.check_datas(table=to_table, datas=datas) |
245 | 246 |
|
246 | | - else: |
247 | | - export_success = ( |
248 | | - self._export_data.export_items(to_table, datas) |
249 | | - if not is_update |
250 | | - else self._export_data.update_items( |
251 | | - to_table, datas, update_keys=update_keys |
| 247 | + for pipline in self._piplines: |
| 248 | + if is_update: |
| 249 | + if not pipline.update_items(to_table, datas, update_keys=update_keys): |
| 250 | + log.error( |
| 251 | + f"{pipline.__class__.__name__} 更新数据失败. table: {to_table} items: {datas}" |
252 | 252 | ) |
253 | | - ) |
254 | | - |
255 | | - if setting.ADD_ITEM_TO_REDIS: |
256 | | - if isinstance(setting.ADD_ITEM_TO_REDIS, (list, tuple)): |
257 | | - for item in setting.ADD_ITEM_TO_REDIS: |
258 | | - if item in item_name: |
259 | | - self._db.sadd(tab_item, datas) |
260 | | - export_success = True |
261 | | - log.info("共导出 %s 条数据 到redis %s" % (len(datas), tab_item)) |
262 | | - break |
| 253 | + return False |
263 | 254 |
|
264 | 255 | else: |
265 | | - self._db.sadd(tab_item, datas) |
266 | | - export_success = True |
267 | | - log.info("共导出 %s 条数据 到redis %s" % (len(datas), tab_item)) |
| 256 | + if not pipline.save_items(to_table, datas): |
| 257 | + log.error( |
| 258 | + f"{pipline.__class__.__name__} 保存数据失败. table: {to_table} items: {datas}" |
| 259 | + ) |
| 260 | + return False |
268 | 261 |
|
269 | | - return export_success |
| 262 | + # 若是任务表, 且上面的pipline里没mysql,则需调用mysql更新任务 |
| 263 | + if not self._have_mysql_pipline and is_update and to_table.endswith("_task"): |
| 264 | + self.mysql_pipline.update_items(to_table, datas, update_keys=update_keys) |
270 | 265 |
|
271 | 266 | def __add_item_to_db( |
272 | 267 | self, items, update_items, requests, callbacks, items_fingerprints |
|
0 commit comments