反爬拦截不再重试: 判定为反爬类错误(403/429/503/Cloudflare/captcha/验证页等)直接放弃该页, 节省重试时间; 验证页持续8秒即判定反爬, 不再干等满超时(默认60s)
- engine.is_anti_crawl_error: 反爬错误信号关键词判定 - _retry_crawl: 反爬错误直接 break, entry.error 标注'反爬拦截, 跳过重试' - _wait_page_settle/_settle_wait: 连续8秒检测到验证页即判定反爬尽早返回 - 集成测试: 反爬页 attempts=1 且 8.1s 放弃; 非反爬错误仍 attempts=retry_count+1 正常重试
This commit is contained in:
@@ -36,6 +36,19 @@ _CHALLENGE_MARKS = [
|
|||||||
"checking your browser", "enable javascript and cookies",
|
"checking your browser", "enable javascript and cookies",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# 反爬拦截类错误信号: 命中后不再重试 (重试无意义且拖慢任务)
|
||||||
|
_ANTI_CRAWL_MARKS = [
|
||||||
|
"403", "429", "503", "forbidden", "access denied", "too many requests",
|
||||||
|
"captcha", "cloudflare", "challenge", "verify you are human",
|
||||||
|
"just a moment", "blocked", "被反爬拦截",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def is_anti_crawl_error(err):
|
||||||
|
"""判断错误是否属于反爬拦截 (此类失败重试也无法通过, 直接放弃该页)"""
|
||||||
|
s = str(err or "").lower()
|
||||||
|
return any(m in s for m in _ANTI_CRAWL_MARKS)
|
||||||
|
|
||||||
|
|
||||||
def is_challenge_page(title, html):
|
def is_challenge_page(title, html):
|
||||||
"""判断是否仍在反爬验证页 (仅关键词启发, 避免误伤正常小页面)"""
|
"""判断是否仍在反爬验证页 (仅关键词启发, 避免误伤正常小页面)"""
|
||||||
@@ -56,6 +69,7 @@ def safe_name(url, idx):
|
|||||||
def _settle_wait(page, timeout_s):
|
def _settle_wait(page, timeout_s):
|
||||||
"""等待页面稳定(无 stop/pause 检查, 供试爬取等独立流程使用)"""
|
"""等待页面稳定(无 stop/pause 检查, 供试爬取等独立流程使用)"""
|
||||||
last_title, stable = "", 0
|
last_title, stable = "", 0
|
||||||
|
challenge_hits = 0
|
||||||
start = time.time()
|
start = time.time()
|
||||||
while time.time() - start < timeout_s:
|
while time.time() - start < timeout_s:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
@@ -65,8 +79,12 @@ def _settle_wait(page, timeout_s):
|
|||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
if is_challenge_page(title, html):
|
if is_challenge_page(title, html):
|
||||||
|
challenge_hits += 1
|
||||||
|
if challenge_hits >= 8: # 持续 8 秒仍是验证页, 判定反爬, 尽早放弃
|
||||||
|
return True, title, html
|
||||||
stable = 0
|
stable = 0
|
||||||
continue
|
continue
|
||||||
|
challenge_hits = 0
|
||||||
if title == last_title:
|
if title == last_title:
|
||||||
stable += 1
|
stable += 1
|
||||||
if stable >= 2 and len(html) > 1000:
|
if stable >= 2 and len(html) > 1000:
|
||||||
@@ -306,6 +324,7 @@ class CrawlJob:
|
|||||||
|
|
||||||
def _wait_page_settle(self, page, timeout_s):
|
def _wait_page_settle(self, page, timeout_s):
|
||||||
last_title, stable = "", 0
|
last_title, stable = "", 0
|
||||||
|
challenge_hits = 0
|
||||||
start = time.time()
|
start = time.time()
|
||||||
while time.time() - start < timeout_s:
|
while time.time() - start < timeout_s:
|
||||||
if self._stop.is_set():
|
if self._stop.is_set():
|
||||||
@@ -318,8 +337,12 @@ class CrawlJob:
|
|||||||
except Exception:
|
except Exception:
|
||||||
continue # 正在跳转
|
continue # 正在跳转
|
||||||
if is_challenge_page(title, html):
|
if is_challenge_page(title, html):
|
||||||
|
challenge_hits += 1
|
||||||
|
if challenge_hits >= 8: # 持续 8 秒仍是验证页, 判定反爬, 尽早放弃
|
||||||
|
return True, title, html
|
||||||
stable = 0
|
stable = 0
|
||||||
continue
|
continue
|
||||||
|
challenge_hits = 0
|
||||||
if title == last_title:
|
if title == last_title:
|
||||||
stable += 1
|
stable += 1
|
||||||
if stable >= 2 and len(html) > 1000:
|
if stable >= 2 and len(html) > 1000:
|
||||||
@@ -460,6 +483,11 @@ class CrawlJob:
|
|||||||
entry["error"] = str(e)
|
entry["error"] = str(e)
|
||||||
entry["crawl_time"] = store.now_str()
|
entry["crawl_time"] = store.now_str()
|
||||||
self._log("warn", f"第{attempt + 1}次失败 {url}: {e}")
|
self._log("warn", f"第{attempt + 1}次失败 {url}: {e}")
|
||||||
|
if is_anti_crawl_error(e):
|
||||||
|
# 反爬拦截: 重试也过不去, 直接放弃, 不再消耗重试次数
|
||||||
|
entry["error"] = f"反爬拦截, 跳过重试: {e}"
|
||||||
|
self._log("warn", f"判定为反爬拦截, 放弃重试: {url}")
|
||||||
|
break
|
||||||
if attempt < retries:
|
if attempt < retries:
|
||||||
self._wait_if_paused()
|
self._wait_if_paused()
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
|
|||||||
Reference in New Issue
Block a user