自动化解决python webdriver 爬虫遇到的Cloudflare的5 秒盾_5秒盾
技术背景
首先我们要理解什么是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 timeimport tracebackfrom DrissionPage import ChromiumPage, ChromiumOptions, WebPagefrom DrissionPage.common import Keys, Byclass 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