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 Sheet 中的输入在我的个人 Google Drive 中创建文件夹 来源 Youtube 上的 Google Sheet Community 但是 当我尝试在共享的
  • 谷歌电子表格中的“MMMM yy”日期

    我有一个谷歌电子表格 其中我想要一个仅包含月份和年份名称的日期 例如September 2011 而且我还希望月份和年份能够轻松更改 有没有办法获得自定义日期格式来做到这一点 我发现我可以这样做 TEXT 40295 MMMM yy 但是日
  • 无法使用 BeautifulSoup 和 Requests 抓取下拉菜单

    我想抓取百年灵网站上的产品页面以获取各种信息 示例页面 https www breitling com gb en watches navitimer b01 chronograph 46 AB0127211C1A1 https www b
  • curl 无法获取网页内容,为什么?

    我正在使用curl 脚本转到链接并获取其内容以进行进一步操作 以下是链接和curl脚本
  • 如何在 Google 文档之间复制内容和格式?

    我需要复制 Google 文档的内容 并将其附加到另一个文档 如果我使用这样的东西 newDoc getBody appendParagraph template getText 我得到了文本 但丢失了原始文件中的格式 Bold Itali
  • 自动递增 ID 号 Google Apps 脚本

    我想在向工作表添加新值时自动增加 ID 我尝试从当前的 ID 列表创建一个列表 但它只计数到 5 因此当自动递增时 它只会到达一个点并为每个输入保存该数字 以下是我尝试获取 ID 号列表的方法 但它没有获取整个列表 我缺少什么 var ss
  • 加快网络抓取速度

    我正在使用一个非常简单的网络抓取工具抓取 23770 个网页scrapy 我对 scrapy 甚至 python 都很陌生 但设法编写了一个可以完成这项工作的蜘蛛 然而 它确实很慢 爬行 23770 个页面大约需要 28 小时 我看过scr
  • 将身份验证从一个 Google Apps 脚本网络应用程序传递到另一 Google Apps 脚本网络应用程序

    我的 Google Apps 帐户中有两个 Google Apps 脚本 两者均已发布为具有以下设置的网络应用程序 脚本A 像我一样执行谁有权访问网络应用程序 XXXXXXX com 内的任何人 脚本B 以访问应用程序的用户身份执行谁有权访
  • Crypto-Js 库的 hmac-256 脚本返回函数结构而不是 Google Apps 脚本中的值,在外部工作正常吗?

    我正在设置一个谷歌电子表格项目来连接到我的 CryptoExchange API 但是当涉及到这个简单的 CryptoJs Hmac sha256 脚本时 它不起作用 它返回函数结构而不是值 而在外部它工作正常 看我的jsfiddle ht
  • Google Apps 脚本 - 是否可以仅通过 Google Apps 脚本更改表格中的某些单元格?

    我在 Google SpreadSheet 中制作了一个目录 我的电子表格有一个表格 用户可以在其中添加信息 该表是通过从数据库表获取数据的脚本动态创建的 用户可以编辑表中的某些单元格 然后单击按钮将更改保存回数据库表中 我想限制他可以手动
  • 如何使用Google脚本获取当前单元格下单元格的值?

    我找不到看起来像这样的选项 var spreadsheet SpreadsheetApp getActive var sheet spreadsheet getActiveSheet sheet getRange sheet getCurr
  • 无法在 selenium 和 requests 之间传递 cookie,以便使用后者进行抓取

    我用 python 结合 selenium 编写了一个脚本来登录网站 然后从driver to requests这样我就可以继续使用requests进行进一步的活动 I used item soup select one div class
  • 将查询参数添加到 URL

    我正在尝试自动从网站下载数据 我需要将动态参数传递到每天更改的站点 html 的结构是表格而不是表单 如何传递参数并从 url 获取结果 这是我尝试过的 它需要在 python 2 7 中 import urllib url https d
  • 当我打印“查询”时获取 PY_VAR1

    我正在制作一个简单的网络抓取代码 当我尝试打印一个值时 它给了我其他东西 def PeopleSearch query SearchTerm query what is query print str query SearchTerm St
  • Selenium/BeautifulSoup - WebScrape 该字段

    我的代码运行良好 并打印除带有下拉列表的行之外的所有行的标题 例如 如果单击第 4 行 则会出现一个下拉菜单 我实现了一个 尝试 理论上会单击下拉菜单 然后拉出标题 但是 当我执行 click 并尝试打印时 对于具有这些下拉列表的行 它们不
  • 将数据从一张纸复制到另一张纸的APP脚本

    我尝试使用此脚本将数据从一张工作表复制到另一张工作表 但是当我更新源工作表中的数据并运行脚本时 整个数据都会被复制 我只想将更新的数据复制到目标工作表而不重叠 谁能建议该怎么做 function copyPaste var ss Sprea
  • 谷歌表格在一行上的不同单元格范围上添加时间戳

    我一直试图在与该行上两个不同单元格范围相对应的行上放置两个时间戳 我已成功使用此脚本对行上的任何更改 第 5 列之后 添加时间戳 我想要的是 如果单元格范围 F 到 L 发生任何更改 则在 E 列中放置一个时间戳 然后 如果从 N 列到 Z
  • 在搜索栏中输入查询并抓取结果

    我有一个数据库 其中包含不同书籍的 ISBN 号 我使用 Python 和 Beautifulsoup 收集了它们 接下来我想为书籍添加类别 书籍类别有一个标准 一个网站叫https www bol com nl https www bol
  • 向文档添加动态页眉/页脚

    我想知道是否有一种方法可以向文档添加动态页眉或页脚 即在页脚中添加每个页面都不同的 页面标题 据我所知 编辑内置页眉或页脚将反映在每个页面上 我想知道是否有人想到了一种解决方法 通过访问页面上的第一行 最后一行并在那里插入文本来 强制 它
  • 通过 RSelenium 单击按钮

    我正在尝试使用 Rselarium 和 Rvest 来抓取 REI 的评论 吊床 我想点击底部的按钮 x 次 这样我就可以抓取所有评论 我有点失落 这是我到目前为止所拥有的 如果您也知道如何在取景器中预览您正在做的事情 而不是屏幕打印 那就

随机推荐

  • 有没有办法更改 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 分