Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Google apps script 谷歌应用程序抓取脚本定期运行,直到所有站点';是否提取用户的内部页面?_Google Apps Script_Web Scraping - Fatal编程技术网

Google apps script 谷歌应用程序抓取脚本定期运行,直到所有站点';是否提取用户的内部页面?

Google apps script 谷歌应用程序抓取脚本定期运行,直到所有站点';是否提取用户的内部页面?,google-apps-script,web-scraping,Google Apps Script,Web Scraping,我已经完成了一个抓取脚本,通过抓取,一个接一个地抓取任何站点(要输入的url)的内部页面,抓取其他内部url,然后继续抓取所有页面并提取它们的纯文本(剥离html)。 该脚本运行良好,但google脚本的运行限制为6分钟,因此对于大型站点,它将无法运行(6分钟后停止,并且在google文档文件中没有输出) 函数onOpen(){ DocumentApp.getUi()//或DocumentApp或FormApp。 .createMenu('新的刮取web文档') .addItem('输入Url'

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

函数onOpen(){
DocumentApp.getUi()//或DocumentApp或FormApp。
.createMenu('新的刮取web文档')
.addItem('输入Url','显示提示')
.addToUi();
}
函数showPrompt(){
var ui=DocumentApp.getUi();
var result=ui.prompt(
“将整个网站刮成文本!”,
'请输入网站url(带有http://):',
ui.按钮设置。确定\取消);
//处理用户的响应。
var button=result.getSelectedButton();
var url=result.getResponseText();
var-links=[];
var base_url=url;
if(button==ui.button.OK)
{     
//收集初始链接
var internal_links_arr=scrapeandplaste(url,1);//首先运行并清除文档
links=links.concat(内部链接);//向所有链接附加一个数组
var new_links=[];//新链接的数组
var processed_url=[url];//已处理的链接
无功链接,当前;
while(links.length)
{  
link=links.shift();//获取最左边的链接(内部url)
已处理的URL.push(链接);
当前=基本url+链接;
new_links=scrapeandplaste(current,0);//第二次和连续运行我们不会清除文档
//ui.alert('Processed…'+current+'\n返回的链接:'+new_links.join('\n'));
//如果合适,将新链接添加到链接数组(堆栈)中
for(新链接中的变量i){
var项目=新链接[i];
if(links.indexOf(item)==-1&&processed\u url.indexOf(item)==-1)
链接。推送(项目);
}    
}
} 
}
函数scrapeAndPaste(url,清除){
var文本;
试一试{
var html=UrlFetchApp.fetch(url.getContentText();
//一些html预处理
如果(html.indexOf(“”)!==-1){
html=html.split(“”)[1];
}
如果(html.indexOf(“”)!=-1){//,那么我们只拆分主体
html=html.split(“”)[0]+“”;
}       
//获取内部链接
var内部链接(arr)=[];
var linkRegExp=/href=“(.*)”/gi;//正则表达式对象
var match=linkRegExp.exec(html);
while(匹配!=null){
//匹配文本:匹配[0]
if(匹配[1]。indexOf('#')!==0
&&匹配[1]。indexOf('http')!==0
//&&匹配[1]。indexOf('https://')!==0
&&匹配[1]。indexOf('mailto:')!==0
&&匹配[1]。indexOf('.pdf')=-1){
内部链接(匹配[1]);
}    
//匹配开始:match.index
//捕获组n:匹配[n]
match=linkRegExp.exec(html);
}
text=getTextFromHtml(html);
outputText(url,text,clear);//使用给定的url将文本输出到当前文档中
return internal_links_arr;//我们将此文档的所有内部链接作为数组返回
}第(e)款{
MailApp.sendEmail(Session.getActiveUser().getEmail(),“在上刮取错误报告”
+formatDate(新日期(),“GMT”,“yyyy-MM-dd HH:MM:ss”),
“\r\n消息:”+e.message
+“\r\n文件:”+e.fileName+“.gs”
+“\r\n刮下的网页:”+url
+“\r\n行:”+e.lineNumber);
outputText(url,“由于html格式错误导致此页面出现刮取错误!”,清除);
} 
}
函数getTextFromHtml(html){
返回getTextFromNode(Xml.parse(html,true.getElement());
}
函数getTextFromNode(x){
开关(x.toString()){
大小写“XmlText”:返回x.toXmlString();
案例“XmlElement”:返回x.getNodes().map(getTextFromNode.join(“”);
默认值:返回“”;
}
}
函数输出文本(url、文本、清除){
var body=DocumentApp.getActiveDocument().getBody();
如果(清除){
body.clear();
}
否则{
body.appendHorizontalRule();
}
var section=body.append段落('*'+url);
章节标题(文件第页段落标题第2节);
正文.第段(案文);
} 
我的想法是使用额外的电子表格来保存已删除的链接,并在常规基础上自动重新启动脚本(使用ScriptApp.newTrigger)。但出现了一些障碍:

  • 当通过触发器调用时,脚本的运行时间仅为30秒
  • 若从触发器运行,则用户无法与脚本进行交互!我应该再次使用电子表格单元格来输入初始基本url吗
  • 由于运行时间限制(30秒或6分钟),如何在脚本停止之前将刮取的内容刷新到google文档文件中
  • 如果处理了所有站点链接,如何停止触发器调用脚本
  • 为了方便起见,你可以分别回答每个问题

    是否有更好的解决方案来抓取站点页面、刮取并将输出保存为一个文本文件?
  • 好了,你需要在两个触发器之间留出至少6分钟的时间,然后它会再运行6分钟

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

  • 您可以定期检查时间,知道它只会运行6分钟,如果达到5分钟,请粘贴全部,然后设置触发器

  • 使用需要在属性中处理的当前链接保存对象,然后当触发器调用脚本时,它只检索需要处理的URL

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

    另一种选择是使用HTMLService或setTimeout使检索调用异步运行。我在GAS中没有使用setTimeout
    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); 
    }