playwright 一些方法解决cloudflare防护页的问题

在尝试从一个使用Cloudflare Web应用程序防火墙(WAF)保护的网站获取数据时,我遇到了一些挑战.该网站的安全措施非常严格,以至于在正常浏览几个页面后,Cloudflare的检查页面就会出现.

传统的HTTP客户端方法,如直接使用httpclient来抓取页面数据,很快就会遭遇阻碍.

即便尝试使用代理IP池,问题依旧存在,因为Cloudflare的检测机制能够在短时间内多次访问后迅速触发.在多次尝试后,我决定使用playwright这个自动化库来模拟正常的浏览器行为.

虽然在使用playwright的过程中遇到了一些问题,但我最终找到了解决方案.现在,尽管速度稍慢,但我能够正常地从网站获取数据.接下来,我将分享如何克服这些挑战的经验.

直接403

这是cloudflare的基本防护,他会检查是否使用了webdriver进行模拟爬取.

解决方式:

java 复制代码
...
final BrowserContext context = browser.newContext();
...
context.setDefaultTimeout(180_000);
context.setDefaultNavigationTimeout(180_000);
context.addInitScript("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})");

这里同时也将默认超时拉长,避免在等待某些元素触发的条件下超时.

使用本地安装的浏览器

可以直接指定本地安装的浏览器:

While Playwright can download and use the recent Chromium build, it can operate against the branded Google Chrome and Microsoft Edge browsers available on the machine (note that Playwright doesn't install them by default). In particular, the current Playwright version will support Stable and Beta channels of these browsers.
Available channels are chrome, msedge, chrome-beta, msedge-beta or msedge-dev.

启动的时候指定即可:

java 复制代码
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setChannel("msedge"));

是否触发了cloudflare判断

因为触发了cloudflare页面的url并不会有明显的变化,只有多一次跳转.

这里直接使用页面元素即可, 处理代码如下:

java 复制代码
    private static void checkMeetChallenge(Page page) throws Exception {
        ElementHandle stage = page.querySelector("div#challenge-stage");
        int checkCount = 1;
        while (stage != null) {
            tryToClickChallenge(page, stage);
            if (checkCount >= 6) {
                if (page.querySelector("div#challenge-stage") != null) {
                    throw new Exception("meet challenge restart");
                }
            }
            log.info("handleCategory - meet challenge. wait 20s to check it again. count:{}", checkCount);
            checkCount++;
            page.waitForTimeout(20_000);
            stage = page.querySelector("div#challenge-stage");
        }
    }

在上层的调用代码中,我先判断了我需要的元素是否存在,如果不存在有两种可能,一种是已经爬完了,另一种是触发了cloudflare.

那个meet challenge restart是一层兜底, 如果点击失败加上长时间等待还在, 那就重启浏览器, 重启之后大概率不会重新触发防护, 也算是最后一个措施了.

处理防护页的人工点击

首先先看一下那个防护页面的结构:

html 复制代码
<div id="challenge-stage" style="display: flex;">
    <div id="turnstile-wrapper" class="captcha-prompt spacer">
        <div><iframe
                src="https://challenges.cloudflare.com/cdn-cgi/challenge-platform/xxxxxx"
                allow="cross-origin-isolated; fullscreen"
                sandbox="allow-same-origin allow-scripts allow-popups" id="cf-chl-widget-sppzq" tabindex="0"
                title="包含  Cloudflare  安全质询的小组件 "
                style="border: none; overflow: hidden; width: 300px; height: 65px;"></iframe><input
                type="hidden" name="cf-turnstile-response" id="cf-chl-widget-sppzq_response"></div>
    </div>
</div>

点击的组件被放在了一个iframe里,正常要获取元素点击比较麻烦.

但是playwright直接模拟鼠标在位置上点击即可.

具体思路是定位到外层的div#challenge-stage, 然后用page.mouse().move移动到元素上,在用click()点击.

代码:

java 复制代码
BoundingBox box = stageDiv.boundingBox();
page.mouse().move(box.x + 100, box.y + box.height / 2);
page.waitForTimeout(1_000 + ThreadLocalRandom.current().nextInt(100, 1000));
page.mouse().click(box.x + 100, box.y + box.height / 2);

其实你不点击它也没关系,我在测试的时候发现这个challenge页面会在1分钟左右自己消失,可以在检测出是challenge之后循环waitForTimeout即可.

最后就是要注意时间间隔,中间留一点时间.

这些做完基本就可以慢慢获取数据了.

我之前还做了很多随机滚动(mouse.wheel),移动到下一页点击等措施,结果发现做不做一样,可能在一些情况下比较有用.

因为playwright很多动作其实是要scheduled的,它并不立即触发,比如你click下一页之后就算waitForLoadState再用locatorquerySelector获取元素他还是会报错,这种情况可以手动waitForTimeout一下,我不知道这样处理是不是常规做法,但至少解决了我的问题.

相关参考链接:
playwright
playwright Browsers
How to Bypass Cloudflare with Playwright in 2024
original blog

相关推荐
爬山算法4 分钟前
Hibernate(78)如何在GraphQL服务中使用Hibernate?
java·hibernate·graphql
独断万古他化9 分钟前
【Spring 核心:AOP】基础到深入:思想、实现方式、切点表达式与自定义注解全梳理
java·spring·spring aop·aop·切面编程
编程彩机21 分钟前
互联网大厂Java面试:从分布式事务到微服务优化的技术场景解读
java·spring boot·redis·微服务·面试·kafka·分布式事务
bbq粉刷匠22 分钟前
Java-排序2
java·数据结构·排序算法
编程彩机25 分钟前
互联网大厂Java面试:从Spring WebFlux到分布式事务的技术场景解析
java·微服务·面试·分布式事务·spring webflux
Jm_洋洋30 分钟前
【C++进阶】虚函数、虚表与虚指针:多态底层机制剖析
java·开发语言·c++
小马爱打代码32 分钟前
MyBatis:缓存体系设计与避坑大全
java·缓存·mybatis
时艰.38 分钟前
Java 并发编程:Callable、Future 与 CompletableFuture
java·网络
码云数智-园园39 分钟前
深入理解与正确实现 .NET 中的 BackgroundService
java·开发语言
好好研究42 分钟前
SpringBoot整合SpringMVC
xml·java·spring boot·后端·mvc