为什么Google Apps脚本的UrlFetchApp返回HTML而不是csv文件(请求Facebook API)?

理查德

背景

当我通过Facebook见解API请求报告时,UrlFetchApp使用html文件而不是csv文件进行响应。在页面底部Facebook文档中

出口报告

我们提供了一个方便的端点,可以导出为本地可读的格式。转换为本地可读格式。

curl -G \
  -d 'report_run_id=<AD_REPORT_RUN_ID>' \
  -d 'name=myreport' \
  -d 'format=csv' \
'https://www.facebook.com/ads/ads_insights/export_report/'

我已经运行了报告,因此得到了,adReportId并且身份验证没有问题,因为我使用的是有效的access_token实际上,当我手动访问url时,将立即开始下载正确的csv文件。

问题

解析csv响应时,Google Apps脚本会引发以下错误:

无法解析文本。(文件第219行)

215-219行:

function getReportData(reportId) {
  const id = reportId || CacheService.getScriptCache().get('campaign-report-id');
  const facebookUrl = buildFacebookReportUrl(id);
  //facebookUrl:https://www.facebook.com/ads/ads_insights/export_report?report_run_id=<REPORT_ID>&format=csv&access_token=<ACCESS_TOKEN>
  var fetchRequest = UrlFetchApp.fetch(facebookUrl);
  var response = fetchRequest.getContentText();
  Logger.log(response);
  return Utilities.parseCsv(fetchRequest)
    };

function buildFacebookReportUrl(reportId) {
  const baseUrl = `https://www.facebook.com/ads/ads_insights/export_report?`;
  const paramString = `report_run_id=${reportId}&format=csv&access_token=${
    fbConfig.TOKEN}`;
  const requestUrl = `${baseUrl}${paramString}`;
  return encodeURI(requestUrl);
}

日志显示以下数据response(已截断):

<!DOCTYPE html>
<html lang="en" id="facebook" class="no_js">

<head>
    <meta charset="utf-8" />
    <meta name="referrer" content="default" id="meta_referrer" />
    <script>
        window._cstart = +new Date();
    </script>
    <script>
        function envFlush(a) {
            function b(b) {
                for (var c in a) b[c] = a[c]
            }
            window.requireLazy ? window.requireLazy(["Env"], b) : (window.Env = window.Env || {}, b(window.Env))
        }
        envFlush({
            "ajaxpipe_token": "AXjyFTuniyv5Ka6j",
            "timeslice_heartbeat_config": {
                "pollIntervalMs": 33,
                "idleGapThresholdMs": 60,
                "ignoredTimesliceNames": {
                    "requestAnimationFrame": true,
                    "Event listenHandler mousemove": true,
                    "Event listenHandler mouseover": true,
                    "Event listenHandler mouseout": true,
                    "Event listenHandler scroll": true
                },
                "isHeartbeatEnabled": true,
                "isArtilleryOn": false
            },
            "shouldLogCounters": true,
            "timeslice_categories": {
                "react_render": true,
                "reflow": true
            },
            "sample_continuation_stacktraces": true,
            "dom_mutation_flag": true,
            "stack_trace_limit": 30,
            "deferred_stack_trace_rate": 1000,
            "timesliceBufferSize": 5000,
            "show_invariant_decoder": false,
            "compat_iframe_token": "AQ7vXO7c6UeVAX4i",
            "isCQuick": false
        });
    </script>
    <style></style>
    <script>
        __DEV__ = 0;
        CavalryLogger = window.CavalryLogger || function(a) {
            this.lid = a, this.transition = !1, this.metric_collected = !1, this.is_detailed_profiler = !1, this.instrumentation_started = !1, this.pagelet_metrics = {}, this.events = {}, this.ongoing_watch = {}, this.values = {
                t_cstart: window._cstart
            }, this.piggy_values = {}, this.bootloader_metrics = {}, this.resource_to_pagelet_mapping = {}, this.initializeInstrumentation && this.initializeInstrumentation()
        }, CavalryLogger.prototype.setIsDetailedProfiler = function(a) {
            this.is_detailed_profiler = a;
            return this
        }, CavalryLogger.prototype.setTTIEvent = function(a) {
            this.tti_event = a;
            return this
        }, CavalryLogger.prototype.setValue = function(a, b, c, d) {
            d = d ? this.piggy_values : this.values;
            (typeof d[a] === "undefined" || c) && (d[a] = b);
            return this
        }, CavalryLogger.prototype.getLastTtiValue = function() {
            return this.lastTtiValue
        }, CavalryLogger.prototype.setTimeStamp = CavalryLogger.prototype.setTimeStamp || function(a, b, c, d) {
            this.mark(a);
            var e = this.values.t_cstart || this.values.t_start;
            e = d ? e + d : CavalryLogger.now();
            this.setValue(a, e, b, c);
            this.tti_event && a == this.tti_event && (this.lastTtiValue = e, this.setTimeStamp("t_tti", b));
            return this
        }, CavalryLogger.prototype.mark = typeof console === "object" && console.timeStamp ? function(a) {
            console.timeStamp(a)
        } : function() {}, CavalryLogger.prototype.addPiggyback = function(a, b) {
            this.piggy_values[a] = b;
            return this
        }, CavalryLogger.instances = {}, CavalryLogger.id = 0, CavalryLogger.disableArtilleryOnUntilOffLogging = !1, CavalryLogger.getInstance = function(a) {
            typeof a === "undefined" && (a = CavalryLogger.id);
            CavalryLogger.instances[a] || (CavalryLogger.instances[a] = new CavalryLogger(a));
            return CavalryLogger.instances[a]
        }, CavalryLogger.setPageID = function(a) {
            if (CavalryLogger.id === 0) {
                var b = CavalryLogger.getInstance();
                CavalryLogger.instances[a] = b;
                CavalryLogger.instances[a].lid = a;
                delete CavalryLogger.instances[0]
            }
            CavalryLogger.id = a
        }, CavalryLogger.now = function() {
            return window.performance && performance.timing && performance.timing.navigationStart && performance.now ? performance.now() + performance.timing.navigationStart : new Date().getTime()
        }, CavalryLogger.prototype.measureResources = function() {}, CavalryLogger.prototype.profileEarlyResources = function() {}, CavalryLogger.getBootloaderMetricsFromAllLoggers = function() {}, CavalryLogger.start_js = function() {}, CavalryLogger.done_js = function() {};
        CavalryLogger.getInstance().setTTIEvent("t_domcontent");
        CavalryLogger.prototype.measureResources = function(a, b) {
            if (!this.log_resources) return;
            var c = "bootload/" + a.name;
            if (this.bootloader_metrics[c] !== void 0 || this.ongoing_watch[c] !== void 0) return;
            var d = CavalryLogger.now();
            this.ongoing_watch[c] = d;
            "start_" + c in this.bootloader_metrics || (this.bootloader_metrics["start_" + c] = d);
            b && !("tag_" + c in this.bootloader_metrics) && (this.bootloader_metrics["tag_" + c] = b);
            if (a.type === "js") {
                c = "js_exec/" + a.name;
                this.ongoing_watch[c] = d
            }
        }, CavalryLogger.prototype.stopWatch = function(a) {
            if (this.ongoing_watch[a]) {
                var b = CavalryLogger.now(),
                    c = b - this.ongoing_watch[a];
                this.bootloader_metrics[a] = c;
                var d = this.piggy_values;
                a.indexOf("bootload") === 0 && (d.t_resource_download || (d.t_resource_download = 0), d.resources_downloaded || (d.resources_downloaded = 0), d.t_resource_download += c, d.resources_downloaded += 1, d["tag_" + a] == "_EF_" && (d.t_pagelet_cssload_early_resources = b));
                delete this.ongoing_watch[a]
            }
            return this
        }, CavalryLogger.getBootloaderMetricsFromAllLoggers = function() {
            var a = {};
            Object.values(window.CavalryLogger.instances).forEach(function(b) {
                b.bootloader_metrics && Object.assign(a, b.bootloader_metrics)
            });
            return a
        }, CavalryLogger.start_js = function(a) {
            for (var b = 0; b < a.length; ++b) CavalryLogger.getInstance().stopWatch("js_exec/" + a[b])
        }, CavalryLogger.done_js = function(a) {
            for (var b = 0; b < a.length; ++b) CavalryLogger.getInstance().stopWatch("bootload/" + a[b])
        }, CavalryLogger.prototype.profileEarlyResources = function(a) {
            for (var b = 0; b < a.length; b++) this.measureResources({
                name: a[b][0],
                type: a[b][1] ? "js" : ""
            }, "_EF_")
        };
        CavalryLogger.getInstance().log_resources = true;
        CavalryLogger.getInstance().setIsDetailedProfiler(true);
        window.CavalryLogger && CavalryLogger.getInstance().setTimeStamp("t_start");
    </script>
    <title id="pageTitle">Facebook</title>
    <link rel="shortcut icon" href="https://static.xx.fbcdn.net/rsrc.php/yz/r/KFyVIAWzntM.ico" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/y2/l/0,cross/3kNz1uzYvN2.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="SUv1J" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yW/l/0,cross/9NGO1GuacRK.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="nOHzA" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yA/l/0,cross/rvNB4fphdT0.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="T1Fcr" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yJ/l/0,cross/kDxV0y2UotM.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="cNDmN" />
    <script src="https://static.xx.fbcdn.net/rsrc.php/v3/yh/r/53ZB62AZOTo.js?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="QPWJc"></script>
    <script>
        requireLazy(["gkx"], function(gkx) {
            gkx.add({
                "676837": {
                    "result": false,
                    "hash": "AT5qgm2lluu0ObEm"
                },
                "676920": {
                    "result": false,
                    "hash": "AT4fRx_5a-x5BCKq"
                },
                "676921": {
                    "result": false,
                    "hash": "AT7L2NIsWs1k6mzF"
                },
                "676922": {
                    "result": false,
                    "hash": "AT434PRa2zIf0VNU"
                },
                "676940": {
                    "result": false,
                    "hash": "AT75c1NCKpiznkoK"
                },
                "946894": {
                    "result": false,
                    "hash": "AT4KxZoaFuONM6jW"
                },
                "996939": {
                    "result": false,
                    "hash": "AT7CXDiWhrCd8u4n"
                },
                "996940": {
                    "result": false,
                    "hash": "AT4S6r3cOh4ebic8"
                },
                "1073500": {
                    "result": false,
                    "hash": "AT6ny6L_AsBsjSUH"
                },
                "1113247": {
                    "result": false,
                    "hash": "AT6aSDBxHRQgvz2h"
                },
                "1263340": {
                    "result": false,
                    "hash": "AT4j6MH_K-2kudmO"
                },
                "1167394": {
                    "result": false,
                    "hash": "AT7tg1d7ZhRzO_3p"
                }
            });
        });
        requireLazy(["qex"], function(qex) {
            qex.add({
                "1211266": {
                    "r": null
                }
            });
        });
        require("TimeSliceImpl").guard(function() {
                    (require("ServerJSDefine")).handleDefines([
                                ["cr:696703", [], {
                                    "__rc": [null, "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:708886", ["EventProfilerImpl"], {
                                    "__rc": ["EventProfilerImpl", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:717822", ["TimeSliceImpl"], {
                                    "__rc": ["TimeSliceImpl", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:806696", ["clearTimeoutBlue"], {
                                    "__rc": ["clearTimeoutBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:807042", ["setTimeoutBlue"], {
                                    "__rc": ["setTimeoutBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:896462", ["setIntervalAcrossTransitionsBlue"], {
                                    "__rc": ["setIntervalAcrossTransitionsBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:986633", ["setTimeoutAcrossTransitionsBlue"], {
                                    "__rc": ["setTimeoutAcrossTransitionsBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:1003267", ["clearIntervalBlue"], {
                                    "__rc": ["clearIntervalBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:1100101", ["requestAni [20 - 01 - 28 15: 24: 04: 186 CET] < !DOCTYPE html >
                                        < html lang = "en"
                                        id = "facebook"
                                        class = "no_js" >
                                        < head > < meta charset = "utf-8" / > < meta name = "referrer"
                                        content = "default"
                                        id = "meta_referrer" / > < script > window._cstart = +new Date();
    </script>
    <script>
        function envFlush(a) {
            function b(b) {
                for (var c in a) b[c] = a[c]
            }
            window.requireLazy ? window.requireLazy(["Env"], b) : (window.Env = window.Env || {}, b(window.Env))
        }
        envFlush({
            "ajaxpipe_token": "AXjyFTuniyv5Ka6j",
            "timeslice_heartbeat_config": {
                "pollIntervalMs": 33,
                "idleGapThresholdMs": 60,
                "ignoredTimesliceNames": {
                    "requestAnimationFrame": true,
                    "Event listenHandler mousemove": true,
                    "Event listenHandler mouseover": true,
                    "Event listenHandler mouseout": true,
                    "Event listenHandler scroll": true
                },
                "isHeartbeatEnabled": true,
                "isArtilleryOn": false
            },
            "shouldLogCounters": true,
            "timeslice_categories": {
                "react_render": true,
                "reflow": true
            },
            "sample_continuation_stacktraces": true,
            "dom_mutation_flag": true,
            "stack_trace_limit": 30,
            "deferred_stack_trace_rate": 1000,
            "timesliceBufferSize": 5000,
            "show_invariant_decoder": false,
            "compat_iframe_token": "AQ7vXO7c6UeVAX4i",
            "isCQuick": false
        });
    </script>
    <style></style>
    <script>
        __DEV__ = 0;
        CavalryLogger = window.CavalryLogger || function(a) {
            this.lid = a, this.transition = !1, this.metric_collected = !1, this.is_detailed_profiler = !1, this.instrumentation_started = !1, this.pagelet_metrics = {}, this.events = {}, this.ongoing_watch = {}, this.values = {
                t_cstart: window._cstart
            }, this.piggy_values = {}, this.bootloader_metrics = {}, this.resource_to_pagelet_mapping = {}, this.initializeInstrumentation && this.initializeInstrumentation()
        }, CavalryLogger.prototype.setIsDetailedProfiler = function(a) {
            this.is_detailed_profiler = a;
            return this
        }, CavalryLogger.prototype.setTTIEvent = function(a) {
            this.tti_event = a;
            return this
        }, CavalryLogger.prototype.setValue = function(a, b, c, d) {
            d = d ? this.piggy_values : this.values;
            (typeof d[a] === "undefined" || c) && (d[a] = b);
            return this
        }, CavalryLogger.prototype.getLastTtiValue = function() {
            return this.lastTtiValue
        }, CavalryLogger.prototype.setTimeStamp = CavalryLogger.prototype.setTimeStamp || function(a, b, c, d) {
            this.mark(a);
            var e = this.values.t_cstart || this.values.t_start;
            e = d ? e + d : CavalryLogger.now();
            this.setValue(a, e, b, c);
            this.tti_event && a == this.tti_event && (this.lastTtiValue = e, this.setTimeStamp("t_tti", b));
            return this
        }, CavalryLogger.prototype.mark = typeof console === "object" && console.timeStamp ? function(a) {
            console.timeStamp(a)
        } : function() {}, CavalryLogger.prototype.addPiggyback = function(a, b) {
            this.piggy_values[a] = b;
            return this
        }, CavalryLogger.instances = {}, CavalryLogger.id = 0, CavalryLogger.disableArtilleryOnUntilOffLogging = !1, CavalryLogger.getInstance = function(a) {
            typeof a === "undefined" && (a = CavalryLogger.id);
            CavalryLogger.instances[a] || (CavalryLogger.instances[a] = new CavalryLogger(a));
            return CavalryLogger.instances[a]
        }, CavalryLogger.setPageID = function(a) {
            if (CavalryLogger.id === 0) {
                var b = CavalryLogger.getInstance();
                CavalryLogger.instances[a] = b;
                CavalryLogger.instances[a].lid = a;
                delete CavalryLogger.instances[0]
            }
            CavalryLogger.id = a
        }, CavalryLogger.now = function() {
            return window.performance && performance.timing && performance.timing.navigationStart && performance.now ? performance.now() + performance.timing.navigationStart : new Date().getTime()
        }, CavalryLogger.prototype.measureResources = function() {}, CavalryLogger.prototype.profileEarlyResources = function() {}, CavalryLogger.getBootloaderMetricsFromAllLoggers = function() {}, CavalryLogger.start_js = function() {}, CavalryLogger.done_js = function() {};
        CavalryLogger.getInstance().setTTIEvent("t_domcontent");
        CavalryLogger.prototype.measureResources = function(a, b) {
            if (!this.log_resources) return;
            var c = "bootload/" + a.name;
            if (this.bootloader_metrics[c] !== void 0 || this.ongoing_watch[c] !== void 0) return;
            var d = CavalryLogger.now();
            this.ongoing_watch[c] = d;
            "start_" + c in this.bootloader_metrics || (this.bootloader_metrics["start_" + c] = d);
            b && !("tag_" + c in this.bootloader_metrics) && (this.bootloader_metrics["tag_" + c] = b);
            if (a.type === "js") {
                c = "js_exec/" + a.name;
                this.ongoing_watch[c] = d
            }
        }, CavalryLogger.prototype.stopWatch = function(a) {
            if (this.ongoing_watch[a]) {
                var b = CavalryLogger.now(),
                    c = b - this.ongoing_watch[a];
                this.bootloader_metrics[a] = c;
                var d = this.piggy_values;
                a.indexOf("bootload") === 0 && (d.t_resource_download || (d.t_resource_download = 0), d.resources_downloaded || (d.resources_downloaded = 0), d.t_resource_download += c, d.resources_downloaded += 1, d["tag_" + a] == "_EF_" && (d.t_pagelet_cssload_early_resources = b));
                delete this.ongoing_watch[a]
            }
            return this
        }, CavalryLogger.getBootloaderMetricsFromAllLoggers = function() {
            var a = {};
            Object.values(window.CavalryLogger.instances).forEach(function(b) {
                b.bootloader_metrics && Object.assign(a, b.bootloader_metrics)
            });
            return a
        }, CavalryLogger.start_js = function(a) {
            for (var b = 0; b < a.length; ++b) CavalryLogger.getInstance().stopWatch("js_exec/" + a[b])
        }, CavalryLogger.done_js = function(a) {
            for (var b = 0; b < a.length; ++b) CavalryLogger.getInstance().stopWatch("bootload/" + a[b])
        }, CavalryLogger.prototype.profileEarlyResources = function(a) {
            for (var b = 0; b < a.length; b++) this.measureResources({
                name: a[b][0],
                type: a[b][1] ? "js" : ""
            }, "_EF_")
        };
        CavalryLogger.getInstance().log_resources = true;
        CavalryLogger.getInstance().setIsDetailedProfiler(true);
        window.CavalryLogger && CavalryLogger.getInstance().setTimeStamp("t_start");
    </script>
    <title id="pageTitle">Facebook</title>
    <link rel="shortcut icon" href="https://static.xx.fbcdn.net/rsrc.php/yz/r/KFyVIAWzntM.ico" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/y2/l/0,cross/3kNz1uzYvN2.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="SUv1J" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yW/l/0,cross/9NGO1GuacRK.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="nOHzA" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yA/l/0,cross/rvNB4fphdT0.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="T1Fcr" />
    <link type="text/css" rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/yJ/l/0,cross/kDxV0y2UotM.css?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="cNDmN" />
    <script src="https://static.xx.fbcdn.net/rsrc.php/v3/yh/r/53ZB62AZOTo.js?_nc_x=Ij3Wp8lg5Kz" data-bootloader-hash="QPWJc"></script>
    <script>
        requireLazy(["gkx"], function(gkx) {
            gkx.add({
                "676837": {
                    "result": false,
                    "hash": "AT5qgm2lluu0ObEm"
                },
                "676920": {
                    "result": false,
                    "hash": "AT4fRx_5a-x5BCKq"
                },
                "676921": {
                    "result": false,
                    "hash": "AT7L2NIsWs1k6mzF"
                },
                "676922": {
                    "result": false,
                    "hash": "AT434PRa2zIf0VNU"
                },
                "676940": {
                    "result": false,
                    "hash": "AT75c1NCKpiznkoK"
                },
                "946894": {
                    "result": false,
                    "hash": "AT4KxZoaFuONM6jW"
                },
                "996939": {
                    "result": false,
                    "hash": "AT7CXDiWhrCd8u4n"
                },
                "996940": {
                    "result": false,
                    "hash": "AT4S6r3cOh4ebic8"
                },
                "1073500": {
                    "result": false,
                    "hash": "AT6ny6L_AsBsjSUH"
                },
                "1113247": {
                    "result": false,
                    "hash": "AT6aSDBxHRQgvz2h"
                },
                "1263340": {
                    "result": false,
                    "hash": "AT4j6MH_K-2kudmO"
                },
                "1167394": {
                    "result": false,
                    "hash": "AT7tg1d7ZhRzO_3p"
                }
            });
        });
        requireLazy(["qex"], function(qex) {
            qex.add({
                "1211266": {
                    "r": null
                }
            });
        });
        require("TimeSliceImpl").guard(function() {
                    (require("ServerJSDefine")).handleDefines([
                                ["cr:696703", [], {
                                    "__rc": [null, "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:708886", ["EventProfilerImpl"], {
                                    "__rc": ["EventProfilerImpl", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:717822", ["TimeSliceImpl"], {
                                    "__rc": ["TimeSliceImpl", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:806696", ["clearTimeoutBlue"], {
                                    "__rc": ["clearTimeoutBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:807042", ["setTimeoutBlue"], {
                                    "__rc": ["setTimeoutBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:896462", ["setIntervalAcrossTransitionsBlue"], {
                                    "__rc": ["setIntervalAcrossTransitionsBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:986633", ["setTimeoutAcrossTransitionsBlue"], {
                                    "__rc": ["setTimeoutAcrossTransitionsBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:1003267", ["clearIntervalBlue"], {
                                    "__rc": ["clearIntervalBlue", "Aa2d-W5-1nWg1sVgO19izjYy_tqPH8dlVHuIPPgy4FLx3zt-Nw63rJWoc0DdN3TfViSyYfbhpyQGjKQRzfCxl1I"]
                                }, -1],
                                ["cr:1100101", ["requestAni

我尝试过的(其他stackoverflow解决方案)

  • 这个问题声称类似的urlFetch请求产生了csv内容,但是我不理解他添加的其他选项(我认为我不需要它,因为身份验证是没有问题的,并且在手动访问url时可以使用)
  • 这个问题具有相同的问题,但是唯一的答案是针对身份验证的问题,在我的情况下可以排除。
  • 在尝试解压缩Blob时,我也尝试了此实现(获取Blob),并导致Google Apps脚本错误。
  • 这个问题使我检查了csv文件是否存在任何可能的格式错误,但是在检查和手动导入到Google表格后,一切看起来都很好:在此处输入图片说明
  • 感谢@TheMaster指出了编码,我还添加了该buildFacebookReportUrl()函数的上方,并且还尝试了tokenURI和reportId的encodeURIComponent()-尽管没有成功:
function buildFacebookReportUrl(reportId) {
  const baseUrl = `https://www.facebook.com/ads/ads_insights/export_report?`;
  const paramString = `report_run_id=${encodeURIComponent(reportId)}&format=csv&access_token=${encodeURIComponent(
    fbConfig.TOKEN
  )}`;
  const requestUrl = `${baseUrl}${paramString}`;
  return encodeURI(requestUrl);
}

如何繁殖

  1. Facebook Insights API快速入门
  2. 向/ insights端点发送POST请求,该请求以广告报告运行的ID进行响应。
  3. 像上面的例子一样导出报告

我希望有人可以重现此错误或立即发现我的请求有什么问题。

让我知道您是否需要更多背景信息!(没有很多经验,但是尝试了我最好的帮助背景)

理查德

我终于找到问题出在发布答案时。

问题是我发出了异步请求来创建报告,并想在作业完成之前下载它。

Facebook文档

  1. <AD_OBJECT>/insights端点发送POST请求,并以的ID进行响应Ad Report Run
  2. Ad Report Run包含有关此异步作业的信息,例如async_status轮询此字段,直到async_statusisJob Completedasync_percent_completionis为止100
  3. 然后,您可以查询<AD_REPORT_RUN_ID>/insightsedge以获取最终结果。

在第2步中的条件得到满足之前,我尝试执行3.。

解决方案

我添加了一个while循环,async_status按建议轮询该字段。

function fetchReportAndSaveToSheet() {
  const reportId = createReportAndReturnId();
  //THE FOLLOWING CODE HAS SOLVED MY ISSUE
  let jobIsCompleted = false;
  const runReportAdsUrl = `https://graph.facebook.com/v5.0/${reportId}?access_token=${fbConfig.TOKEN}`;
  while (!jobIsCompleted) {
    const fetchRequest = UrlFetchApp.fetch(runReportAdsUrl));
    const runReportAds = JSON.parse(fetchRequest.getContentText());
    jobIsCompleted= runReportAds.async_status === 'Job Completed';
    if (runReportAds.async_status === 'Job Failed') {
      Logger.log((runReportAds.async_status))
      break
    }
  //END OF CODE MODIFICATION
  }
  cacheId(reportId);
  const data = getReportData(reportId);
  clearData();
  pushReportToSheet(data);
}
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么 Google Books API 不返回完整的响应?

如何在Google Apps脚本中使用UrlFetchApp发出Drive API批处理请求

Shopify API,来自Google Apps脚本UrlFetchApp的PUT请求的406响应

如何使用UrlFetchApp.fetch(url,params)在Google Apps脚本中正确查询Facebook Graph API?

为什么Google Distance Matrix Api返回无效的请求状态?(使用Flutter)

请求API但返回空,为什么?

Google Compute Engine对需要固定IP的API的GET请求被拒绝-为什么?

为什么我对Google Custom Search API的调用失败,并显示请求错误(无效参数)?

为什么我的 Google Maps API 回调在前面的内联脚本之前执行?

无法理解Google Translate REST API为什么返回HTTP 400的原因

为什么Google QPX Express API不返回所有航空公司的结果?

为什么 JsonParser 使用 com.google.gson API 在返回值中给出双引号

为什么Google API V3无法返回子级?

为什么 Youtube/Google API 返回的回复不超过 5 个?

Google Drive API为什么用空名称创建文件

为什么删除的文件在通过 Google Drive API 查询时仍然显示在结果中

为什么我的Google Maps API被嵌入但没有显示在HTML页面上?

为什么 Google Apps 脚本给我这个 UrlFetchApp 脚本代码 429?

Google Apps脚本:UrlFetchApp发布文件

我的Directions API请求无效,为什么?

Facebook API为什么图片无法上传?

为什么Instagram API返回空结果?

为什么 Gmail API 返回 401 错误?

为什么我从 Google Apps 脚本中的 UrlFetchApp 得到空响应?

为什么在 Google API 中尝试使用 iOS 版 Place Autocomplete 时只得到 5 个结果而不是更多?

为什么我的代码中的REST API响应不是JSON格式,而是Google扩展名“ restman”的正确格式?

运行Google Spreadsheet API脚本时,为什么会看到“引用错误:“ Calendar”未定义“?

为什么Google+ API第一次不返回电子邮件地址?

为什么 Google API(目录列表)不断返回 403?有进化吗?新版本?GPDR / LGPD 问题?