Google Apps 抓取脚本会定期运行,直到提取所有网站的内页吗?

2024-03-17

我已经完成了一个抓取脚本,通过爬行逐一抓取任何网站(要输入的网址)的内部页面,获取其他内部网址并继续获取所有页面并提取其纯文本(剥离的html)。 该脚本运行良好,但 google 脚本运行限制为 6 分钟,因此对于大型网站,它无法运行(6 分钟后停止,并且 google 文档文件中没有输出)。

function onOpen() { 
    DocumentApp.getUi() // Or DocumentApp or FormApp.
      .createMenu('New scrape web docs')
      .addItem('Enter Url', 'showPrompt')
      .addToUi(); 
}

function showPrompt() { 
  var ui = DocumentApp.getUi();   
  var result = ui.prompt(
      'Scrape whole website into text!',
      'Please enter website url (with http(s)://):',
      ui.ButtonSet.OK_CANCEL); 

// Process the user's response.
  var button = result.getSelectedButton();
  var url = result.getResponseText();  
  var links=[];  
  var base_url = url; 

  if (button == ui.Button.OK) 
  {     
      // gather initial links 
      var inner_links_arr = scrapeAndPaste(url, 1); // first run and clear the document
      links = links.concat(inner_links_arr); // append an array to all the links
      var new_links=[]; // array for new links  
      var processed_urls =[url]; // processed links
      var link, current;

      while (links.length) 
      {  
         link = links.shift(); // get the most left link (inner url)
         processed_urls.push(link);
         current = base_url + link;  
         new_links = scrapeAndPaste(current, 0); // second and consecutive runs we do not clear up the document
         //ui.alert('Processed... ' + current                  + '\nReturned links: ' + new_links.join('\n') );
         // add new links into links array (stack) if appropriate
         for (var i in new_links){
           var item = new_links[i];
           if (links.indexOf(item) === -1 && processed_urls.indexOf(item) === -1)
               links.push(item);
         }    
     }
  } 
}

function scrapeAndPaste(url, clear) { 
  var text; 
  try {
    var html = UrlFetchApp.fetch(url).getContentText();
    // some html pre-processing 
    if (html.indexOf('</head>') !== -1 ){ 
       html = html.split('</head>')[1];
    }
    if (html.indexOf('</body>') !== -1 ){ // thus we split the body only
       html = html.split('</body>')[0] + '</body>';
    }       
   // fetch inner links
    var inner_links_arr= [];
    var linkRegExp = /href="(.*?)"/gi; // regex expression object 
    var match = linkRegExp.exec(html);
    while (match != null) {
      // matched text: match[0]
      if (match[1].indexOf('#') !== 0 
       && match[1].indexOf('http') !== 0 
       //&& match[1].indexOf('https://') !== 0  
       && match[1].indexOf('mailto:') !== 0 
       && match[1].indexOf('.pdf') === -1 ) {
         inner_links_arr.push(match[1]);
      }    
      // match start: match.index
      // capturing group n: match[n]
      match = linkRegExp.exec(html);
    }

    text = getTextFromHtml(html);
    outputText(url, text, clear); // output text into the current document with given url
    return inner_links_arr; //we return all inner links of this doc as array  

  } catch (e) { 
    MailApp.sendEmail(Session.getActiveUser().getEmail(), "Scrape error report at " 
      + Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd  HH:mm:ss"), 
      "\r\nMessage: " + e.message
      + "\r\nFile: " +  e.fileName+ '.gs' 
      + "\r\nWeb page under scrape: " + url
      + "\r\nLine: " +  e.lineNumber); 
    outputText(url, 'Scrape error for this page cause of malformed html!', clear);   
  } 
}

function getTextFromHtml(html) {
  return getTextFromNode(Xml.parse(html, true).getElement());
}
function getTextFromNode(x) {
  switch(x.toString()) {
    case 'XmlText': return x.toXmlString();
    case 'XmlElement': return x.getNodes().map(getTextFromNode).join(' ');
    default: return '';
  }
}

function outputText(url, text, clear){
  var body = DocumentApp.getActiveDocument().getBody();
  if (clear){ 
    body.clear(); 
  }
  else {
    body.appendHorizontalRule();       
  }
  var section = body.appendParagraph(' * ' + url);
  section.setHeading(DocumentApp.ParagraphHeading.HEADING2);
  body.appendParagraph(text); 
} 

我的想法是使用额外的电子表格来保存抓取的链接并自动在常规基础上重新启动脚本(使用 ScriptApp.newTrigger)。但也出现了一些障碍:

  1. 当通过触发器调用时,脚本的运行时间仅为 30 秒。
  2. 如果从触发器运行,用户无法与脚本交互!我应该再次使用电子表格单元格来输入初始基本网址吗?
  3. 如何在脚本因运行限制时间(30 秒或 6 分钟)而停止之前将抓取的内容刷新到 google doc 文件中?
  4. 如果所有站点链接都已处理,如何通过触发器停止脚本调用?

为了方便起见,您可以单独回答每个问题。

是否有更好的解决方案来爬行网站页面、抓取并将输出保存为一个文本文件?


  1. AFAIK,您需要在触发器之间至少间隔 6 分钟,然后它将再运行 6 分钟。

  2. 您可以一次请求所有 URL 并将它们保存在属性中,然后在触发器中调用这些属性。

  3. 您可以定期检查时间,知道它只会运行 6 分钟,如果达到 5 分钟,则粘贴所有内容然后设置触发器。

  4. 将当前需要处理的链接保存在属性中,然后当触发器调用脚本时,它只检索需要处理的 URL。

您可能无法将整个网站保存在属性中,因为它有 100kb 的限制,但您可以将每个页面拆分为不同的属性,不知道它是否会达到这种限制。

另一种替代方法是使用 HTMLService 或 setTimeout 使检索调用异步运行。我没有在 GAS 脚本中使用 setTimeout,但在 HTML Javascript 中效果很好。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Google Apps 抓取脚本会定期运行,直到提取所有网站的内页吗? 的相关文章

  • 用于提交、评分和发回 Google 课堂作业的 Google Apps 脚本

    正如下面的评论中提到的 如果只有学生可以交一些东西 那么我就需要能够评分并返回作业 即使它还没有上交 澄清一下 作业是通过 API 完成的 我可以控制班级和学生 正如下面的附加评论中提到的 即使您不返回作业 学生仍然会看到分配的成绩 这实现
  • HtmlUnit WebClient 超时

    在我之前关于 HtmlUnit 的问题中跳过 HTML 单元中特定的 Javascript 执行 https stackoverflow com questions 14439991 skip particular javascript e
  • 通过脚本删除工作表

    我正在执行此代码 function deleteSheets var ss SpreadsheetApp getActiveSpreadsheet var sheets ss getSheets var transp ss getSheet
  • 如何抓取 Hype Machine 等网站?

    我对网站抓取 即它是如何完成的等 很好奇 特别是我想编写一个脚本来执行网站的任务炒作机 http hypem com 我实际上是一名软件工程本科生 四年级 但是我们并没有真正涵盖任何 Web 编程 因此我对 Javascript RESTF
  • Google Apps 脚本:如何水平对齐 inlineImage

    我有以下代码 它是一个更大程序的一部分 我正在尝试将图像从我的 Google 驱动器插入到 Google 文档中 并调整其大小并居中 到目前为止 我能够让程序插入图像并调整其大小 但我不知道如何使 inlineImage 居中 我是使用谷歌
  • 正则表达式 - 使用正则表达式提取电子邮件文档的子字符串

    我正在尝试使用正则表达式提取电子邮件文档的子字符串 我正在在线测试正则表达式 它运行得很好 在线正则表达式测试器 https regex101 com r BbWBPk 1 我有一个功能可以检查 Google Apps 脚本上的正则表达式
  • 如何使用 cURL 和 PHP 抓取 LinkedIn 公司页面?在标头错误中找不到 CSRF 令牌

    我想用 cURL 和 PHP 抓取一些 LinkedIn 公司页面 LinkedIn 的 API 不是为此构建的 因此我必须使用 PHP 来完成此操作 如果还有其他选择 请告诉我 在抓取公司页面之前 我必须通过 cURL 使用个人帐户登录
  • 如何使 onEdit() 触发函数应用于多个工作表

    我正在处理一张 Google 表格 我有一个脚本可以填充column B当我更新时有时间戳column A在第一个选项卡上 不过 我需要它在第二个选项卡上执行相同的操作 但我无法让它在那里工作 我需要改变什么 我当前使用的脚本是 funct
  • python编写的类爬虫抛出属性错误

    用 python 编写一些代码后 我陷入了深深的麻烦 我是按照 Python 中的 OOP 设计编写代码的新手 我在代码中使用的 xpath 是完美的 当通过 page crawler 类的实例运行 info grabber 类中的 pas
  • 清除内容并从另一张纸复制

    我编写了一个脚本 旨在清除 Google Sheets 电子表格的内容并复制并粘贴另一个工作表的内容 需要清除的工作表称为 NEW SHEET 要复制的工作表称为 Database 由于某种原因 该脚本目前无法运行 当我运行它时什么也没有发
  • 复制带有内嵌图像的表格

    我正在尝试将 GDoc 的内容复制到另一个 GDoc 中 这对于所有不同的元素类型都非常有效 包括一个表 枚举DocumentApp ElementType TABLE 但是 如果表包含内联图像 EnumDocumentApp Elemen
  • javascript 对象是否像 Ruby 一样“开放”?

    在 Ruby 中 我可以使用与声明自己的语法相同的语法来添加和修改任何类 对象或方法的功能 因为 Ruby 有 开放类 JavaScript 是这样的吗 举个例子 就我而言 我想更改 Google Apps 脚本处理 URL 对象的方式 以
  • Google Apps 脚本中的地图对象支持

    Google Apps 脚本是否支持Map https developer mozilla org en docs Web JavaScript Reference Global Objects Map object 当我尝试使用它时 我得
  • Firebase GAS webapp Google 弹出窗口消失

    我正在尝试升级我的 firebase GAS web 应用程序 之前我有一个弹出窗口 可以让用户使用 Google 登录 我不确定我做错了什么 但我已经升级到新的 firebase 现在正在尝试使用新的代码格式进行相同的登录 发生的情况是
  • Python(Selenium):如何通过登录重定向/组织登录登录网站

    我不是专业程序员 所以请原谅任何愚蠢的错误 我正在做一些研究 我正在尝试使用 Selenium 登录数据库来搜索大约 1000 个术语 我有两个问题 1 重定向到组织登录页面后如何使用 Selenium 登录 2 如何检索数据库 在我解决
  • 使用 XMLHTTP 进行抓取会在特定类名处引发错误

    我正在尝试使用此代码抓取网站以提取姓名和联系人 Sub Test Dim htmlDoc As Object Dim htmlDoc2 As Object Dim elem As Variant Dim tag As Variant Dim
  • 与 google 脚本一起使用时,币安搜索 API 返回 403

    我正在使用 binance API 来获取 USDT 的价格 该 API 适用于邮递员 但不适用于 google 脚本 function fetchCryptoPricesFromApi const data page 1 rows 10
  • rvest如何通过id选择特定的css节点

    我正在尝试使用 rvest 包从网页中抓取数据 简单来说 html 代码如下所示 div class style div
  • 使用 Scala 进行网页抓取 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何从谷歌表格下载 PNG 图表

    我试图在 Google Sheet 中创建一个自定义菜单 以允许我将当前 Google Sheet 文件中所有工作表中的所有图表下载到 PNG 图像中 使用图表标题作为图像名称 保存到我的 Windows PC 的默认下载目录中 我打算使用

随机推荐

  • 有没有办法更改 Nifi 中 PublishJMS 处理器的交付模式?

    我使用 Nifi PublishJMS 处理器向 IBM MQ 发送消息 消息在 MQ 中具有持久性 持久性 我想将其更改为非持久性 Nifi PublishJms 处理器中是否有属性可以纠正此问题 或者是从MQ端完成的 我无权访问 MQ
  • 如何从Python解码pdf加密文件

    我有一个 PDF 文件和关联的密码 我想仅使用 python 将加密文件转换为清晰版本 I found here https stackoverflow com questions 6413441 python pdf library一些
  • 为什么javascript函数的返回值未定义?

    我有一个函数来检测图像的大小 我希望它返回一个包含宽度和高度的对象 在下面的代码中 sz width 和 sz heightwithin该函数保存这些值 但在返回该值后 该值是未定义的 我缺少什么 function getImgSize i
  • 如何将数据库适配器传递给另一个活动?

    我在理解 Android SDK 中的搜索对话框时遇到一些困难 我的应用程序的 主要活动 提供了一个按钮 如果用户单击此按钮 则会调用搜索对话框 然后 搜索本身在异步任务中完成 因为它可能需要一些时间 到目前为止 一切都很好 主活动还创建一
  • UITextView委托问题

    我正在尝试访问 UITextView 委托并遇到问题 我有一个带有 UITextViewDelegate 协议的 UIViewController 和一个包含 textView 的 Nib 如果我在 viewDidLoad 中设置委托 如
  • 这是以编程方式终止(取消)芹菜任务的最佳方法

    根据 Celery 的文档 我们不应该使用terminate选项中revoke 取消正在执行的任务的函数 当任务陷入困境时 终止选项是管理员的最后手段 它不是为了终止任务 而是为了终止正在执行任务的进程 并且该进程可能在发送信号时已经开始处
  • relativeSource 适用于(嵌套)子属性,而 ElementName 则不适用于

    下面代码的问题是 绑定到SomeClassProp SubTextProp不起作用 源属性未设置为文本框内容 而TextProp确实如此 XAML
  • EXC_BAD_ACCESS 当行数为​​ 0 时 UITableView 崩溃

    当我将表中的行数设置为零时 我的 UITableView 发生了一致的崩溃 它因 EXC BAD ACCESS 错误而崩溃 崩溃是 UITableView 内部的 所以我无法直接看到出了什么问题 尽管这对我来说应该是一个愚蠢的错误 堆栈跟踪
  • C 中快速高效的最小二乘拟合算法?

    我正在尝试对两个数据数组实现线性最小二乘拟合 时间与幅度 到目前为止 我知道的唯一技术是测试 y m x b 中所有可能的 m 和 b 点 然后找出最适合我的数据的组合 以便其误差最小 然而 我认为迭代这么多组合有时是没有用的 因为它测试了
  • matlab中字符串的最大长度

    我是 matlab 的新手 我正在尝试解决以下场景 我有大字符串 需要对其进行异或编码才能获得值 我正在使用以下代码片段来执行该操作 clear clc first abceeeeeeeeeeeeeeeddddddddddddd secon
  • 单击时显示 NSUserNotification 附加操作

    在上图中 您可以在 OS X 上看到两个通知 第一个来自我的应用程序 第二个来自 Apple 的 Reminders app 在图像中你可以看到otherButtonTitle 完成 和actionButtonTitle 之后 第二个通知
  • Plotly R:根据不同的条形颜色更改hoverinfo字体颜色

    我有这个数据框 df2 data frame value c 9 2 7 3 6 key c ar or br gt ko 这是我必须生成的代码这个情节 https i stack imgur com gZCg1 png df2 gt pl
  • 令人困惑的 PHP 按位 NOT 行为

    在 PHP 中 如果我运行以下简单程序 number 9 var dump number 我的输出是 int 10 这让我很困惑 我thought 是按位NOT操作员 所以我期待类似的事情 if binary 9 is 0000000000
  • Android Studio 上的 Android Tesseract OCR [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 一段时间以来 我一直在尝试将 tesseract 包含在 Android Studio 上的 Andro
  • 用户代码可以安全地使用结构体填充吗?

    假设我有一个如下所示的结构 struct Struct char Char int Int and sizeof int 大于 1 编译器会添加填充Char成员变量 编译器生成的代码是否允许更改填充字节的值 我的意思是 如果我使用指针算术并
  • 使用 Apache POI 访问数据透视表的字段设置

    我正在创建一个工作簿 其中包含来自数据源的填充数据的工作表 然后使用该数据的数据透视表视图创建第二个工作表 一切工作正常 但我似乎无法更改数据透视表的默认外观 我正在尝试获取设置 行标签 gt 从列表中单击一个 gt 字段设置 gt 小计
  • 所有对mock的调用在设置字符串参数时都必须有相应的设置

    我正在测试一个简单的方法 当我运行测试时出现错误 模拟上的所有调用都必须有相应的设置 在最后一行 dataField DefaultValue orderNumber ToString 什么会导致这种情况呢 我只是设置一个字段 void I
  • 为什么foldr可以在Haskell中的无限列表上工作,而foldl却不能?

    我一直在努力理解foldl vs foldr vs foldl 在哈斯克尔 我理解共识是使用foldr when f第二个参数是惰性的 因为它反映了列表的结构 foldl 当我们知道需要处理整个列表并且f其论点很严格 我对这样的情况特别感兴
  • 在 Perl 中是否有更好的方法来确定经过的时间?

    my start time Time HiRes gettimeofday my diff Time HiRes tv interval start time print n n diff n 可能吧 取决于你所说的 更好 是什么意思 如果
  • Google Apps 抓取脚本会定期运行,直到提取所有网站的内页吗?

    我已经完成了一个抓取脚本 通过爬行逐一抓取任何网站 要输入的网址 的内部页面 获取其他内部网址并继续获取所有页面并提取其纯文本 剥离的html 该脚本运行良好 但 google 脚本运行限制为 6 分钟 因此对于大型网站 它无法运行 6 分