d
This commit is contained in:
@@ -9,8 +9,12 @@
|
||||
'''
|
||||
|
||||
import re # 正则表达式模块
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
import requests # HTTP请求库
|
||||
from loguru import logger # 日志记录
|
||||
from requests.adapters import HTTPAdapter
|
||||
from typing import List, Tuple, Optional, Dict # 类型提示
|
||||
|
||||
|
||||
@@ -19,12 +23,40 @@ SO_SEARCH_URL = 'https://www.so.com/s' # 360搜索URL
|
||||
SO_REFERER_TEMPLATE = 'https://www.so.com/s?ie=utf-8&q=site%3A{domain}' # Referer模板
|
||||
SEARCH_PATTERN = r'target="_blank">([^<]+)</a></h3>' # 搜索结果匹配模式
|
||||
BLOCKED_CODE = 3 # 拦截状态码
|
||||
_SESSION_LOCAL = threading.local()
|
||||
SO_TIMEOUT_PROXY = max(
|
||||
1.0,
|
||||
float(os.getenv("DOMAINCHECK_360_TIMEOUT_PROXY", "1.4") or 1.4),
|
||||
)
|
||||
SO_TIMEOUT_DIRECT = max(
|
||||
1.2,
|
||||
float(os.getenv("DOMAINCHECK_360_TIMEOUT_DIRECT", "1.8") or 1.8),
|
||||
)
|
||||
|
||||
|
||||
def _resolve_360_timeout(proxies: Optional[Dict] = None, budget_seconds: Optional[float] = None) -> float:
|
||||
timeout = float(SO_TIMEOUT_PROXY if proxies else SO_TIMEOUT_DIRECT)
|
||||
if budget_seconds not in (None, "", 0, "0"):
|
||||
timeout = min(timeout, max(0.6, float(budget_seconds or 0.0)))
|
||||
return max(0.6, timeout)
|
||||
|
||||
|
||||
def _get_session():
|
||||
session = getattr(_SESSION_LOCAL, "session", None)
|
||||
if session is not None:
|
||||
return session
|
||||
session = requests.Session()
|
||||
session.mount("http://", HTTPAdapter(pool_connections=64, pool_maxsize=128, max_retries=0))
|
||||
session.mount("https://", HTTPAdapter(pool_connections=64, pool_maxsize=128, max_retries=0))
|
||||
_SESSION_LOCAL.session = session
|
||||
return session
|
||||
|
||||
|
||||
def check_domain(
|
||||
domain: str,
|
||||
sensitive_words: Optional[List[str]] = None,
|
||||
proxies: Optional[Dict] = None
|
||||
proxies: Optional[Dict] = None,
|
||||
budget_seconds: Optional[float] = None,
|
||||
) -> Tuple[bool, str]:
|
||||
"""
|
||||
检查域名是否包含敏感词
|
||||
@@ -60,125 +92,65 @@ def check_domain(
|
||||
'q': f'site:{domain}', # 搜索查询
|
||||
}
|
||||
|
||||
# 添加重试机制
|
||||
max_retries = 3
|
||||
for retry in range(max_retries):
|
||||
try:
|
||||
# 发送GET请求获取搜索结果
|
||||
response = requests.get(
|
||||
SO_SEARCH_URL,
|
||||
params=params,
|
||||
headers=headers,
|
||||
proxies=proxies,
|
||||
timeout=15 # 增加超时时间到15秒
|
||||
)
|
||||
try:
|
||||
session_started_at = time.perf_counter()
|
||||
logger.info(f'360阶段: domain={domain} | stage=session_init_start')
|
||||
session = _get_session()
|
||||
logger.info(
|
||||
f'360阶段: domain={domain} | stage=session_init_done '
|
||||
f'| elapsed_ms={int((time.perf_counter() - session_started_at) * 1000)}'
|
||||
)
|
||||
# 发送GET请求获取搜索结果
|
||||
request_started_at = time.perf_counter()
|
||||
logger.info(f'360阶段: domain={domain} | stage=request_start | proxy={"yes" if proxies else "no"}')
|
||||
response = session.get(
|
||||
SO_SEARCH_URL,
|
||||
params=params,
|
||||
headers=headers,
|
||||
proxies=proxies,
|
||||
timeout=_resolve_360_timeout(proxies, budget_seconds=budget_seconds),
|
||||
)
|
||||
logger.info(
|
||||
f'360阶段: domain={domain} | stage=request_done | status={response.status_code} '
|
||||
f'| elapsed_ms={int((time.perf_counter() - request_started_at) * 1000)}'
|
||||
)
|
||||
|
||||
# 解析响应内容
|
||||
response_html = response.content.decode('utf-8', errors='ignore')
|
||||
# 解析响应内容
|
||||
response_html = response.content.decode('utf-8', errors='ignore')
|
||||
|
||||
# 使用正则表达式提取搜索结果
|
||||
search_results = re.findall(SEARCH_PATTERN, response_html)
|
||||
# 使用正则表达式提取搜索结果
|
||||
search_results = re.findall(SEARCH_PATTERN, response_html)
|
||||
logger.info(f'360阶段: domain={domain} | stage=parsed | result_count={len(search_results)}')
|
||||
|
||||
# 记录搜索结果数量
|
||||
logger.info(f'360搜索结果数量: {len(search_results)}')
|
||||
# 记录搜索结果数量
|
||||
logger.info(f'360搜索结果数量: {len(search_results)}')
|
||||
|
||||
# 如果没有搜索结果,直接返回通过
|
||||
if not search_results:
|
||||
return True, ''
|
||||
|
||||
# 检查每个搜索结果是否包含敏感词
|
||||
for result in search_results:
|
||||
for sensitive_word in sensitive_words:
|
||||
# 使用正则表达式检查是否包含敏感词
|
||||
if re.search(sensitive_word, result, re.IGNORECASE):
|
||||
logger.warning(f'检测到敏感词: {sensitive_word} 在结果: {result}')
|
||||
return False, f'检测到敏感词: {sensitive_word} 在结果: {result}'
|
||||
|
||||
# 所有搜索结果都不包含敏感词,返回通过
|
||||
# 如果没有搜索结果,直接返回通过
|
||||
if not search_results:
|
||||
return True, ''
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
logger.warning(f'360搜索请求第{retry+1}次超时')
|
||||
if retry < max_retries - 1:
|
||||
import time
|
||||
time.sleep(2) # 等待2秒后重试
|
||||
else:
|
||||
# 达到最大重试次数,尝试不使用代理
|
||||
if proxies:
|
||||
logger.info('360搜索请求超时,尝试不使用代理')
|
||||
try:
|
||||
response = requests.get(
|
||||
SO_SEARCH_URL,
|
||||
params=params,
|
||||
headers=headers,
|
||||
proxies=None,
|
||||
timeout=15
|
||||
)
|
||||
response_html = response.content.decode('utf-8', errors='ignore')
|
||||
search_results = re.findall(SEARCH_PATTERN, response_html)
|
||||
logger.info(f'不使用代理的360搜索结果数量: {len(search_results)}')
|
||||
if not search_results:
|
||||
return True, ''
|
||||
for result in search_results:
|
||||
for sensitive_word in sensitive_words:
|
||||
if re.search(sensitive_word, result, re.IGNORECASE):
|
||||
logger.warning(f'检测到敏感词: {sensitive_word} 在结果: {result}')
|
||||
return False, f'检测到敏感词: {sensitive_word} 在结果: {result}'
|
||||
return True, ''
|
||||
except Exception as e:
|
||||
logger.error(f'不使用代理的360搜索请求也失败: {str(e)}')
|
||||
return False, f'360搜索请求超时'
|
||||
return False, '360搜索请求超时'
|
||||
except requests.exceptions.RequestException as e:
|
||||
error_str = str(e)
|
||||
logger.warning(f'360搜索请求第{retry+1}次失败: {error_str}')
|
||||
# 检查是否是"Too many open files"错误
|
||||
if 'Too many open files' in error_str:
|
||||
if retry < max_retries - 1:
|
||||
import time
|
||||
time.sleep(2) # 等待2秒后重试
|
||||
else:
|
||||
# 达到最大重试次数,返回failure标记,不拉黑域名
|
||||
logger.error(f'360搜索请求失败,已达到最大重试次数: {error_str}')
|
||||
return True, 'failure'
|
||||
else:
|
||||
if retry < max_retries - 1:
|
||||
import time
|
||||
time.sleep(2) # 等待2秒后重试
|
||||
else:
|
||||
# 达到最大重试次数,尝试不使用代理
|
||||
if proxies:
|
||||
logger.info('360搜索请求失败,尝试不使用代理')
|
||||
try:
|
||||
response = requests.get(
|
||||
SO_SEARCH_URL,
|
||||
params=params,
|
||||
headers=headers,
|
||||
proxies=None,
|
||||
timeout=15
|
||||
)
|
||||
response_html = response.content.decode('utf-8', errors='ignore')
|
||||
search_results = re.findall(SEARCH_PATTERN, response_html)
|
||||
logger.info(f'不使用代理的360搜索结果数量: {len(search_results)}')
|
||||
if not search_results:
|
||||
return True, ''
|
||||
for result in search_results:
|
||||
for sensitive_word in sensitive_words:
|
||||
if re.search(sensitive_word, result, re.IGNORECASE):
|
||||
logger.warning(f'检测到敏感词: {sensitive_word} 在结果: {result}')
|
||||
return False, f'检测到敏感词: {sensitive_word} 在结果: {result}'
|
||||
return True, ''
|
||||
except Exception as e2:
|
||||
logger.error(f'不使用代理的360搜索请求也失败: {str(e2)}')
|
||||
return False, f'360搜索请求失败: {str(e)}'
|
||||
return False, f'360搜索请求失败: {str(e)}'
|
||||
except Exception as e:
|
||||
logger.warning(f'360搜索第{retry+1}次未知错误: {str(e)}')
|
||||
if retry < max_retries - 1:
|
||||
import time
|
||||
time.sleep(2) # 等待2秒后重试
|
||||
else:
|
||||
return False, f'未知错误: {str(e)}'
|
||||
# 检查每个搜索结果是否包含敏感词
|
||||
for result in search_results:
|
||||
for sensitive_word in sensitive_words:
|
||||
# 使用正则表达式检查是否包含敏感词
|
||||
if re.search(sensitive_word, result, re.IGNORECASE):
|
||||
logger.warning(f'检测到敏感词: {sensitive_word} 在结果: {result}')
|
||||
return False, f'检测到敏感词: {sensitive_word} 在结果: {result}'
|
||||
|
||||
# 所有搜索结果都不包含敏感词,返回通过
|
||||
return True, ''
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
return False, '360搜索请求超时'
|
||||
except requests.exceptions.RequestException as e:
|
||||
error_str = str(e)
|
||||
logger.debug(f'360搜索请求失败: {error_str}')
|
||||
# 检查是否是"Too many open files"错误
|
||||
if 'Too many open files' in error_str:
|
||||
return True, 'failure'
|
||||
return False, f'360搜索请求失败: {error_str}'
|
||||
except Exception as e:
|
||||
return False, f'未知错误: {str(e)}'
|
||||
|
||||
|
||||
# if __name__ == '__main__':
|
||||
@@ -188,4 +160,4 @@ def check_domain(
|
||||
#
|
||||
# logger.info(f'开始检测域名: {test_domain}')
|
||||
# result = check_domain(test_domain, test_sensitive_words)
|
||||
# logger.info(f'检测结果: {result}')
|
||||
# logger.info(f'检测结果: {result}')
|
||||
|
||||
Reference in New Issue
Block a user