Apps Script自定义函数编辑器运行正常 谷歌表格调用返回错误
问题描述
我用Apps Script的UrlFetchApp写了个获取TikTok账号粉丝数的自定义函数,初始硬编码版本运行正常,代码如下:
function tiktok_fans() { var raw_data = new RegExp(/("followerCount":)([0-9]+)/g); var handle = '@charlidamelio'; var web_content = UrlFetchApp.fetch('https://www.tiktok.com/'+ handle + '?lang=en').getContentText(); var match_text = raw_data.exec(web_content); var result = (match_text[2]); Logger.log(result) return result }
运行后日志可以正确输出粉丝数。但我把代码改成接收handle参数的版本后:
function tiktok_fans(handle) { var raw_data = new RegExp(/("followerCount":)([0-9]+)/g); //var handle = '@charlidamelio'; var web_content = UrlFetchApp.fetch('https://www.tiktok.com/'+ handle + '?lang=en').getContentText(); var match_text = raw_data.exec(web_content); var result = (match_text[2]); Logger.log(result) return result }
在谷歌表格中用=tiktok_fans(A1)调用时(A1单元格内容为@charlidamelio),单元格返回#ERROR,报错信息如下:
TypeError: Cannot read property '2' of null (line 6).
为什么该函数在脚本编辑器中运行正常,在谷歌表格中调用就报错?
补充信息
测试了@Tanaike给出的方案后仍然返回相同报错*"TypeError: Cannot read property '2' of null (line 6)."*
手动排查时发现,每次运行下方测试代码,都会随机有不同的匹配结果返回null,推测问题和ContentText大小或缓存有关,尝试在函数调用间加Utilities.sleep()也没有解决,仍然出现null值。
测试代码如下:
var raw_data = new RegExp(/("followerCount":)([0-9]+)/g); //tiktok urls var qld = UrlFetchApp.fetch('https://www.tiktok.com/@thisisqueensland?lang=en').getContentText(); var nsw = UrlFetchApp.fetch('https://www.tiktok.com/@visitnsw?lang=en').getContentText(); var syd = UrlFetchApp.fetch('https://www.tiktok.com/@sydney?lang=en').getContentText(); var tas = UrlFetchApp.fetch('https://www.tiktok.com/@tasmania?lang=en').getContentText(); var nt = UrlFetchApp.fetch('https://www.tiktok.com/@ntaustralia?lang=en').getContentText(); var nz = UrlFetchApp.fetch('https://www.tiktok.com/@purenz?lang=en').getContentText(); var aus = UrlFetchApp.fetch('https://www.tiktok.com/@australia?lang=en').getContentText(); var vic = UrlFetchApp.fetch('https://www.tiktok.com/@visitmelbourne?lang=en').getContentText(); //find folowers with regex var match_qld = raw_data.exec(qld); var match_nsw = raw_data.exec(nsw); var match_syd = raw_data.exec(syd); var match_tas = raw_data.exec(tas); var match_nt = raw_data.exec(nt); var match_nz = raw_data.exec(nz); var match_aus = raw_data.exec(aus); var match_vic = raw_data.exec(vic); Logger.log(match_qld); Logger.log(match_nsw); Logger.log(match_syd); Logger.log(match_tas); Logger.log(match_nt); Logger.log(match_nz); Logger.log(match_aus); Logger.log(match_vic);
原因说明
- 第一个问题出在正则的
g(全局匹配)修饰符上。带g修饰符的正则实例会维护lastIndex属性,上一次匹配结束后,下一次匹配会从lastIndex记录的位置继续匹配,而非从头开始。你复用同一个正则实例匹配不同页面内容时,就会随机出现匹配失败返回null的情况。你的场景只需要匹配一次粉丝数字段,完全不需要加g修饰符。 - 第二个问题是TikTok的反爬机制:谷歌表格自定义函数的请求是从谷歌公共服务器发出的,这类IP很容易被TikTok的反爬策略拦截,返回的不是正常的用户主页,而是验证码、拦截提示页,页面中不存在
followerCount字段,自然匹配不到结果。
修复方案
修改正则规则,去掉多余的g修饰符,添加请求头伪装浏览器请求,同时加空值判断避免报错,修改后的代码如下:
function tiktok_fans(handle) { // 去掉g修饰符,每次匹配都从头开始 const reg = /"followerCount":"?(\d+)"?/; // 伪装浏览器请求头,降低被反爬拦截的概率 const options = { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' }, muteHttpExceptions: true }; try { const webContent = UrlFetchApp.fetch(`https://www.tiktok.com/${handle}?lang=en`, options).getContentText(); const match = reg.exec(webContent); if (match && match[1]) { return Number(match[1]); } // 匹配失败返回提示,避免直接报错 return "匹配失败,请重试"; } catch (e) { return `请求出错:${e.message}`; } }
如果修改后仍然频繁出现匹配失败的情况,说明当前IP已经被TikTok限制,无法通过公共服务器的自定义函数稳定获取数据,建议更换抓取方式。
内容的提问来源于stack exchange,提问作者racker
相关产品推荐
相关产品推荐

