自动化突破Cloudflare的5秒盾,Python WebDriver爬虫应对策略详解

技术背景

首先我们要理解什么是5秒盾:
这里的5秒盾指 Cloudflare 的“5 秒盾”(也叫 Cloudflare 5s Challenge)。这是 Cloudflare 用来防止机器人访问网站的一种机制,通常会显示一个“请稍等 5 秒钟”的页面,然后自动重定向到目标页面。

当我们使用webdirver爬取页面的时候,遇到这种问题经常束手无策,网上有的方案是人工点击,获取token注入cookie等,但是避免不了手动点击。
是否有个方案自动化解决? 答案是有的,本文采用的方案 能100%的跳过5秒盾,方案成熟,对 Bing Chat(https://copilot.microsoft.com/),Perplexity(https://www.perplexity.ai/) 做过多次测试。

实现方案

技术方案: selenium + DissPage(https://drissionpage.cn/)
本文以perplexity 网站5s盾为用例

检测是否有弹窗


解决问题,首先要检测并且定位是否页面出现了5秒盾

def check_robots():
    try:
        main_content = driver.find_element(By.CLASS_NAME, "main-content")
        h1_element = main_content.find_element(By.CLASS_NAME, "zone-name-title")
        h1_element.find_element(By.XPATH, "following-sibling::div")
        return True
    except:
        return False

用新的tab也打开目标链接

一般情况下,遇到这个验证,几秒之后自动会跳走,但是当服务端发现客户端请求异常(比如检测到大量多次请求,检测到可能是自动化程序等),这个验证会一直过不去,并且即使非程序点击,人工点击后也一样。一直重复提示验证。
那么我们可以变向的,在当前tab下重新打开一个标签页面,在那个页面去验证人工校验。

def close_other_tab():
    try:
        window_handles = driver.window_handles
        current_window = driver.current_window_handle
        if len(current_window) > 1:
            for handle in window_handles:
                if handle != current_window:
                    driver.switch_to.window(handle)
                    driver.close()
            driver.switch_to.window(current_window)
    except:
        print(traceback.format_exc())

调用DissPage点击弹窗

直接使用selenium 是无法通过的,即使点击了人工校验也会重复失败。我们使用 drissionpage 来处理点击人工校验部分。

def auto_robots():
    idx = 0
    while True:
        idx = idx + 1
        if idx > 3:
            print("check Failed")
            return False
        if check_robots():
            try:
                drissObj = Driss(browser_port)
                drissObj.to_click()
                time.sleep(10)
                close_other_tab()
                switch_to_chat_page()
            except:
                continue
        else:
            return True
    return False

Driss 相关处理(diss.py)


import time
import traceback
from DrissionPage import ChromiumPage, ChromiumOptions, WebPage
from DrissionPage.common import Keys, By
class Driss:
    def __init__(self, port):
        self.port = port
        self.driver = self.getDriver()

    def getDriver(self):
        co = ChromiumOptions()
        co.set_pref('credentials_enable_service', False)
        co.set_argument('--hide-crash-restore-bubble')
        co_page = ChromiumOptions().set_local_port(self.port)
        return ChromiumPage(co_page)

    def initDriver(self):
        self.driver = self.getDriver()

    def auto_robots(self):
        try:
            dom = self.driver. \
                ele((By.CLASS_NAME, "main-content")). \
                ele((By.CLASS_NAME, "zone-name-title h1")). \
                ele((By.XPATH, "following-sibling::div")). \
                ele((By.TAG_NAME, "div")).ele((By.TAG_NAME, "div")).shadow_root. \
                ele((By.TAG_NAME, "iframe")).ele((By.TAG_NAME, "body")).shadow_root. \
                ele((By.TAG_NAME, "input"))
            dom.click()
            return True
        except:
            print(traceback.format_exc())
            return False
            
    def to_click(self):
        print("DISS create new tab")
        self.driver = self.driver.new_tab()
        time.sleep(2)
        print("DISS to chat page")
        self.driver.get('https://www.perplexity.ai/')
        time.sleep(15)
        self.auto_robots()
        print("DISS handle ok")

技术难点解析

难点:不管那个站点,遇到人工校验首先要检测和定位。
部分网站可能做了影子元素不好定位,可以直接使用影子元素定位的方式来定位,比如

host_element = driver.find_element(By.CSS_SELECTOR, '.xxxx').shadow_root()

部分的影子元素可能是关闭的,需要执行js来打开。

from selenium import webdriver

# 创建WebDriver实例
driver = webdriver.Chrome()

# 打开目标网页
driver.get('http://example.com')

# 执行JavaScript脚本
script = """
    let host = document.querySelector('#host');
    if (host.shadowRoot === null) {
        host.attachShadow({ mode: 'open' });
    }
    let shadowRoot = host.shadowRoot;
    let child = document.createElement('div');
    child.textContent = 'Hello, World!';
    shadowRoot.appendChild(child);
"""

driver.execute_script(script)

# 关闭浏览器
driver.quit()

甚至部分网站限定了webdirver的各种检测访问,可以在启动浏览器的时候添加一些参数。

难点:原标签不能验证,那么使用新标签
部分网站,使用新标签 5s后会自动验证通过,但是有些网站做了一些安全防护后,这个自动就过不去了。需要手动点击或者模拟手动点击后才会通过。
因为selenium 比较流行,很多验证有对是否selenium 的检测,我们可以使用DissPage 从某些方面来规避该问题

最后,调试过程可能遇到各种问题,可以私我。
微信:Uminicmf

作者:youmypig

物联沃分享整理
物联沃-IOTWORD物联网 » 自动化突破Cloudflare的5秒盾,Python WebDriver爬虫应对策略详解

发表回复