【问题标题】:Trouble writing result to a spreadsheet using batch update使用批量更新将结果写入电子表格时遇到问题
【发布时间】:2022-01-22 18:03:20
【问题描述】:

我创建了一个脚本,使用谷歌应用脚​​本从webpage 中抓取两个字段。该脚本似乎工作正常,但它以每行为基础将结果写入电子表格。

我所做的是从登录页面获取所有商店的链接,然后在另一个函数中重用这些链接来解析内页中的 shop namewebsite link。虽然这两个字段在登录页面中也可用,但我希望从它们的内页解析它们。

但是,我希望将结果写入电子表格中进行批量更新。我怎样才能做到这一点?

目前的做法:

function parseYellowpages() {
  var options = {
    "method" : "GET",
    "headers" : {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like  Gecko) Chrome/88.0.4324.150 Safari/537.36"
     }
    };
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var activeSheet = ss.getSheetByName('Sheet1');
  var base = "https://www.yellowpages.com"
  var webURL = "https://www.yellowpages.com/search?search_terms=pizza&geo_location_terms=New+York%2C+NY";

  var row = 1;

  var response = UrlFetchApp.fetch(webURL,options);
  var $ = Cheerio.load(response.getContentText()); 

  const items = $("[class='result'] [class='info']");
  for (i=0;i<items.length;i++){
      var shopLink = base + $(items[i]).find('h2[class="n"] > a.business-name').attr('href');
      var resultContainer;
      resultContainer = getInnerpageInfo(shopLink,options);
      activeSheet.getRange(row,1).setValue(resultContainer[0]);
      activeSheet.getRange(row,2).setValue(resultContainer[1]);
      console.log(resultContainer[0],resultContainer[1]);
      row++;
    };
}

function getInnerpageInfo(innerLink,options) {
    var response = UrlFetchApp.fetch(innerLink,options);
    var $ = Cheerio.load(response.getContentText()); 
    var shopName = $('.sales-info > h1').first().text();
    var website = $('a.website-link').first().attr('href');
    return [shopName,website];

}

如何将结果写入电子表格进行批量更新?

【问题讨论】:

  • 我担心在Stackoverflow中,当连续请求完成时,会出现错误。因此,在您的情况下,如果您的预期值可以通过 Stack Exchange API 检索,我建议您使用它。 Ref 但是,如果您不能使用 API,我很抱歉。
  • 感谢您的评论@Tanaike。我在上面的脚本中使用的站点链接只是一个占位符。我想知道实现这一目标的逻辑。但是,我故意选择该站点链接,认为它是无害的。
  • @MITHU 使用example.com 作为占位符。不要使用有效链接作为占位符。您的函数名称也表明它是您尝试解析的站点。
  • 好的,我现在已经在脚本中更改了站点链接。
  • edit 明确您的问题,首先编辑标题并显示您尝试使用批量更新的内容。

标签: function google-apps-script web-scraping google-sheets


【解决方案1】:

您可以通过将重复的.setValue() 调用替换为一次将所有结果一次性写入电子表格的.setValues() 调用来显着提高性能。

要收集结果,在循环中将它们一一推入数组中,或者将循环替换为Element.map(),如下所示:

  const result = items.map((index, item) => {
    const path = $(item).find('h2[class="n"] > a.business-name').attr('href');
    const shopLink = base + path;
    return [getInnerpageInfo(shopLink, options)];
  }).get();

要写入结果,获取一个大小与结果尺寸匹配的范围并使用.setValues(),如下所示:

  activeSheet.getRange('A1')
    .offset(0, 0, result.length, result[0].length)
    .setValues(result);

问题中的代码在一段时间内似乎没有执行任何操作的原因是 Google Apps 脚本缓存了对电子表格的写入。在许多情况下,所有的写入都只会在脚本终止时执行。

如果您需要立即应用挂起的写入,请使用SpreadsheetApp.flush()

另见Apps Script best practicesUrlFetchApp.fetchAll()

【讨论】:

  • 可用的解决方案here 以正确的方式解决了您提供的解决方案可能失败的原因。
  • The script 已经在我的帖子中运行是这样的。您建议的 version 首先抛出错误。
  • 我已经成功使用了这个code。我不确定这是否是正确的方法,因为我对它很陌生。您的解决方案会生成此output。谢谢。
  • 好的,我明白了。问题的原因是 Cheerio (jQuery) .map() 的签名与 Array.map() 的签名不同,并且要获得数组结果,需要 .get()。编辑了答案。如果您仍然遇到.map() 的问题,只需使用新的.each() 解决方案——该模式可能不是声明性的,但性能基本相同,只要您使用一个.setValues() 调用而不是重复调用.setValue() 来电。很高兴您找到了解决方案。
  • 现在,当我打印结果 console.log(result); 时,您的脚本似乎工作正常。它抛出这个error 指向这条线activeSheet.getRange('A1').offset。我想我理解它为什么会发生(结果在一个列表中,而不是列表列表中),但我不知道如何解决它。这是我在控制台中看到的result
猜你喜欢
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
  • 2019-02-26
  • 1970-01-01
  • 2019-02-20
  • 1970-01-01
  • 2014-06-02
  • 2013-08-22
相关资源
最近更新 更多