使用Google Apps Script的UrlFetchApp获取PDF时遭Cloudflare拦截
问题背景
原本用于从巴基斯坦国家银行网站下载每日PDF汇率表的Google Apps Script脚本,因目标网站启用Cloudflare WAF拦截谷歌数据中心IP,导致UrlFetchApp返回Cloudflare的"Access Denied"页面(text/html类型)而非预期的PDF文件。
可复现代码:
function testDownload() { var url = "https://www.sbp.org.pk/ecodata/rates/war/2026/May/05-May-26.pdf"; var options = { muteHttpExceptions: true, headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } }; var response = UrlFetchApp.fetch(url, options); Logger.log("MimeType: " + response.getBlob().getContentType()); Logger.log("Content: " + response.getContentText().substring(0, 300)); }
拦截返回内容:
<html><body> <h1>Access Denied</h1><p>Signature ID: 1002000251<br>Message ID: 2360628808<br>Client IP: 104.22.1.181</p> <script defer src="https://static.cloudflareinsights.com/beacon.min.js..."
问题解答
1. 能否仅通过UrlFetchApp参数原生绕过Cloudflare拦截?
大概率不行。Cloudflare WAF的机器人检测逻辑不只是验证请求头,还会结合IP归属(谷歌数据中心IP普遍在Cloudflare的机器人黑名单中)、请求行为特征,甚至会要求客户端执行JavaScript完成验证(如人机挑战页面)。
UrlFetchApp仅能发送纯HTTP请求,无法执行JavaScript,且无法改变请求的出口IP。即使补充更多常见请求头(如Accept: application/pdf,text/html;q=0.9、Accept-Language: en-US、Referer: https://www.sbp.org.pk/),也很难绕过基于IP和JS验证的拦截,成功概率极低。
2. 原生绕过不可行时的最佳架构方案
以下是几种可行方案,按自动化程度和维护成本排序:
方案一:使用第三方爬虫API
选择支持Cloudflare反爬处理的爬虫API,这类服务会自动处理JS渲染、IP轮换和人机验证,你只需调用API获取PDF内容,再在Apps Script中处理。优点是无需自己维护反爬逻辑,缺点是需要付费(部分服务有免费额度)。
方案二:搭建中间代理/转发服务
通过第三方服务器或Serverless函数作为中间层,先由中间层请求目标网站(避开谷歌数据中心IP),再将PDF内容返回给Apps Script:
- Serverless函数:比如Cloudflare Workers、AWS Lambda,这类服务的出口IP不易被拉黑,甚至Cloudflare Workers的IP与目标网站的Cloudflare节点同属一个网络,更容易通过验证。你可以编写简单的转发逻辑,让Workers请求目标PDF并返回给Apps Script。
- 自建代理:用VPS搭建HTTP代理,配置Apps Script通过该代理发送请求,但需要自己维护代理的IP可用性,防止被拉黑。
方案三:人工介入+Drive导入
如果需求频率较低(如每日一次),可以手动下载PDF并上传到Google Drive,然后修改脚本从Drive读取文件。该方案零技术成本,但需要人工操作,适合非高频场景。
内容的提问来源于stack exchange,提问作者Mehdi Abbas




