Kaynağa Gözat

外部文章质量判断

luojunhui 6 gün önce
ebeveyn
işleme
fc3d3885e4

+ 1 - 0
src/domains/content_supply/_const.py

@@ -72,6 +72,7 @@ class ContentSupplyConst:
     CACHE_TTL_DAYS = 10  # 搜索缓存有效期(天)
     SEARCH_INTERVAL_SEC = 15  # 搜索页间延迟(秒)
     DETAIL_INTERVAL_SEC = 3  # 详情拉取条间延迟(秒)
+    MIN_QUALITY_SCORE = 40  # 标题质量分阈值(低于此分不拉详情/不抓账号)
 
     # ═══════════════════════════════════════════════════════════════
     # 账号参数

+ 21 - 6
src/domains/content_supply/_mapper.py

@@ -141,15 +141,15 @@ class ArticleSearchRelationMapper(ContentSupplyConst):
         *,
         limit: int = 500,
     ) -> List[Dict]:
-        """查询待拉详情的行 (status=0),按标题质量分逆序"""
+        """查询待拉详情的行 (status=0),quality_score >= MIN_QUALITY_SCORE,按质量分逆序"""
         query = f"""
             SELECT *
             FROM {self.RELATION_TABLE}
-            WHERE status = %s
+            WHERE status = %s AND quality_score >= %s
             ORDER BY quality_score DESC, id ASC
             LIMIT %s
         """
-        params = (self.SearchStatus.INIT, limit)
+        params = (self.SearchStatus.INIT, self.MIN_QUALITY_SCORE, limit)
         return await self.pool.fetch(query=query, params=params)
 
     async def count_by_status(
@@ -227,6 +227,19 @@ class ArticleSearchRelationMapper(ContentSupplyConst):
             params=(self.SearchStatus.FAIL, *ids, self.SearchStatus.PROCESSING),
         )
 
+    async def mark_low_quality(self, *, limit: int = 500) -> int:
+        """INIT(0) → FAIL(99):将标题质量分低于阈值的文章直接标记为失败,不拉详情"""
+        query = f"""
+            UPDATE {self.RELATION_TABLE}
+            SET status = %s
+            WHERE status = %s AND quality_score < %s AND quality_score > 0
+            LIMIT %s
+        """
+        return await self.pool.save(
+            query=query,
+            params=(self.SearchStatus.FAIL, self.SearchStatus.INIT, self.MIN_QUALITY_SCORE, limit),
+        )
+
     # ═══════════════════════════════════════════════════════════════
     # 搜索缓存
     # ═══════════════════════════════════════════════════════════════
@@ -333,18 +346,20 @@ class AccountMapper(ContentSupplyConst):
     # ═══════════════════════════════════════════════════════════════
 
     async def fetch_pending_relations(self, *, limit: int = 100) -> List[Dict]:
-        """取 save_account_status=0 的行(DISTINCT biz,按最高质量分逆序)"""
+        """取 save_account_status=0 的行(DISTINCT biz,按最高质量分逆序,低于阈值的不抓)"""
         query = f"""
             SELECT MIN(id) AS id, biz, MIN(url) AS url, MAX(quality_score) AS max_score
             FROM {self.RELATION_TABLE}
-            WHERE save_account_status = %s AND biz IS NOT NULL AND biz != ''
+            WHERE save_account_status = %s
+              AND biz IS NOT NULL AND biz != ''
+              AND quality_score >= %s
             GROUP BY biz
             ORDER BY max_score DESC, id ASC
             LIMIT %s
         """
         return await self.pool.fetch(
             query=query,
-            params=(self.AccountSaveStatus.INIT, limit),
+            params=(self.AccountSaveStatus.INIT, self.MIN_QUALITY_SCORE, limit),
         )
 
     async def fetch_relation_ids_by_biz(self, biz: str) -> List[int]:

+ 6 - 0
src/domains/content_supply/article_fetch_detail.py

@@ -40,6 +40,12 @@ class ArticleFetchDetail(ContentSupplyConst):
         """
         if limit is None:
             limit = self.DETAIL_DEAL_LIMIT
+
+        # 将低于阈值的低质文章标记为 FAIL,不拉详情
+        dropped = await self.relation_mapper.mark_low_quality(limit=limit)
+        if dropped:
+            logger.info("标记低质文章: dropped=%d (quality_score < %d)", dropped, self.MIN_QUALITY_SCORE)
+
         items = await self.relation_mapper.fetch_pending(limit=limit)
         if not items:
             logger.info("无待拉详情项")