簡體   English   中英

如何在不使用 XmlService 的情況下解析 Google Apps 腳本中的 HTML 字符串?

[英]How to parse an HTML string in Google Apps Script without using XmlService?

我想使用帶有 Google Apps 腳本的 Google 電子表格創建一個抓取工具。 我知道這是可能的,我看過一些關於它的教程和主題。

主要思想是使用:

  var html = UrlFetchApp.fetch('http://en.wikipedia.org/wiki/Document_Object_Model').getContentText();
  var doc = XmlService.parse(html);

然后獲取並使用元素。 然而,該方法

XmlService.parse()

不適用於某些頁面。 例如,如果我嘗試:

function test(){
    var html = UrlFetchApp.fetch("https://www.nespresso.com/br/pt/product/maquina-de-cafe-espresso-pixie-clips-preto-lima-neon-c60-220v").getContentText();
    var parse = XmlService.parse(html);
}

我收到以下錯誤:

Error on line 225: The entity name must immediately follow the '&' in the entity reference. (line 3, file "")

我嘗試使用string.replace()來消除顯然導致錯誤的字符,但它不起作用。 出現各種其他錯誤。 以下代碼為例:

function test(){
    var html = UrlFetchApp.fetch("https://www.nespresso.com/br/pt/product/maquina-de-cafe-espresso-pixie-clips-preto-lima-neon-c60-220v").getContentText();
    var regExp = new RegExp("&", "gi");
    html = html.replace(regExp,"");

    var parse = XmlService.parse(html);
}

給了我以下錯誤:

Error on line 358: The content of elements must consist of well-formed character data or markup. (line 6, file "")

我相信這是XmlService.parse()方法的問題。

我讀過這個線程:

Google App Script parse table from messed html以及在 Google Apps 腳本解析 html 的最佳方法是什么,可以使用稱為xml.parse()的棄用方法,該方法確實接受允許解析 HTML 的第二個參數。 但是,正如我所提到的,它已被棄用,而且我在任何地方都找不到有關它的任何文檔。 xml.parse()似乎解析字符串,但由於缺乏文檔,我無法處理這些元素。 而且它也不是最安全的長期解決方案,因為它可以隨時停用。

所以,我想知道如何在 Google Apps Script 中解析這個 HTML?

我也試過:

function test(){

    var html = UrlFetchApp.fetch("https://www.nespresso.com/br/pt/product/maquina-de-cafe-espresso-pixie-clips-preto-lima-neon-c60-220v").getContentText();
    var htmlOutput = HtmlService.createHtmlOutput(html).getContent();

    var parse = XmlService.parse(htmlOutput);
}

但它不起作用,我收到此錯誤:

格式錯誤的 HTML 內容:

我想過使用開源庫來解析 HTML,但我找不到任何。

我的最終目標是從一組頁面中獲取一些信息,例如價格、鏈接、產品名稱等。我已經使用一系列正則表達式設法做到了這一點:

var ss = SpreadsheetApp.getActiveSpreadsheet();
  var linksSheet = ss.getSheetByName("Links");
  var resultadosSheet = ss.getSheetByName("Resultados");

function scrapyLoco(){

  var links = linksSheet.getRange(1, 1, linksSheet.getLastRow(), 1).getValues();
  var arrayGrandao = [];
  for (var row =  0, len = links.length; row < len; row++){
   var link = links[row];


   var arrayDeResultados = pegarAsCoisas(link[0]);
   Logger.log(arrayDeResultados);
   arrayGrandao.push(arrayDeResultados);
  }   


  resultadosSheet.getRange(2, 1, arrayGrandao.length, arrayGrandao[0].length).setValues(arrayGrandao);

}


function pegarAsCoisas(linkDoProduto) {
  var resultadoArray = [];

  var html = UrlFetchApp.fetch(linkDoProduto).getContentText();
  var regExp = new RegExp("<h1([^]*)h1>", "gi");
  var h1Html = regExp.exec(html);
  var h1Parse = XmlService.parse(h1Html[0]);
  var h1Output = h1Parse.getRootElement().getText();
  h1Output = h1Output.replace(/(\r\n|\n|\r|(^( )*))/gm,"");

  regExp = new RegExp("Ref.: ([^(])*", "gi");
  var codeHtml = regExp.exec(html);
  var codeOutput = codeHtml[0].replace("Ref.: ","").replace(" ","");

  regExp = new RegExp("margin-top: 5px; margin-bottom: 5px; padding: 5px; background-color: #699D15; color: #fff; text-align: center;([^]*)/div>", "gi");
  var descriptionHtml = regExp.exec(html);
  var regExp = new RegExp("<p([^]*)p>", "gi");
  var descriptionHtml = regExp.exec(descriptionHtml);
  var regExp = new RegExp("^[^.]*", "gi");
  var descriptionHtml = regExp.exec(descriptionHtml);
  var descriptionOutput = descriptionHtml[0].replace("<p>","");
  descriptionOutput = descriptionOutput+".";

  regExp = new RegExp("ecom(.+?)Main.png", "gi");
  var imageHtml = regExp.exec(html);
  var comecoDaURL = "https://www.nespresso.com/";
  var imageOutput = comecoDaURL+imageHtml[0];

  var regExp = new RegExp("nes_l-float nes_big-price nes_big-price-with-out([^]*)p>", "gi");
  var precoHtml = regExp.exec(html);
  var regExp = new RegExp("[0-9]*,", "gi");
  precoHtml = regExp.exec(precoHtml);
  var precoOutput = "BRL "+precoHtml[0].replace(",","");

  resultadoArray = [codeOutput,h1Output,descriptionOutput,"Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines",
                    "Máquina",linkDoProduto,imageOutput,"new","in stock",precoOutput,"","","","Nespresso",codeOutput];

  return resultadoArray;
}

但這對編程來說非常耗時,很難動態更改並且不是很可靠。

我需要一種方法來解析此 HTML 並輕松訪問其元素。 它實際上不是一個附加項。 但一個簡單的谷歌應用程序腳本..

我為你的問題做了啦啦隊。 它在 GAS 上作為 Cheerio 工作,它是類似 jQuery 的 api。 你可以這樣做。

const content = UrlFetchApp.fetch('https://example.co/').getContentText();
const $ = Cheerio.load(content);
Logger.log($('p .blah').first().text()); // blah blah blah ...

另見https://github.com/asciian/cheeriogs

這個之前已經討論過了。 請參閱此處: 在 google 應用程序腳本中解析 html 的最佳方法是什么

XML服務不同, XMLService對格式錯誤的 html 的容忍度並不高。 賈斯汀·比克內爾 (Justin Bicknell) 的答案中的技巧可以完成這項工作。 即使XML服務已被棄用,它仍然可以繼續工作。

我在 vanilla js 中做到了這一點。 不是真正的 html 解析。 嘗試從字符串(url)中獲取一些內容:

function getLKKBTC() {
  var url = 'https://www.lykke.com/exchange';
  var html = UrlFetchApp.fetch(url).getContentText();
  var searchstring = '<td class="ask_BTCLKK">';
  var index = html.search(searchstring);
  if (index >= 0) {
    var pos = index + searchstring.length
    var rate = html.substring(pos, pos + 6);
    rate = parseFloat(rate)
    rate = 1/rate
    return parseFloat(rate);
  }
  throw "Failed to fetch/parse data from " + url;
}

請注意,某些網站可能不允許自動抓取其內容,因此請在使用 Apps 腳本提取內容之前查閱其條款或服務。

XmlService僅適用於有效的 XML 文檔,並且大多數 HTML(尤其是 HTML5)不是有效的 XML。 以前版本的XmlService ,簡稱為Xml ,允許“寬松”解析,這也將允許它解析 HTML。 這項服務在 2013 年已停止,但目前仍在運作。 參考文檔不再可用,但這個舊教程顯示了它的用法。

另一種選擇是使用Kimono 之類的服務,它處理抓取和解析部分,並提供一個簡單的 API,您可以通過UrlFetchApp調用以檢索結構化數據。

我找到了一個非常巧妙的替代方案來使用 Google App Script 進行抓取。 它被稱為PhantomJS Cloud 可以使用urlFetchApp訪問 API。 這允許在頁面上執行 Jquery 代碼,這使生活變得更加簡單。

能用javascript來解析html嗎? 如果您的 Google Apps 腳本將 html 作為字符串檢索,然后將其返回給 javascript 函數,那么您似乎可以在 Google Apps 腳本之外很好地解析它。 您可以將要抓取的任何標簽發送到專用的 Google Apps 功能來保存內容。

您可能可以使用 jQuery更輕松地完成此操作。

也許不是最干凈的方法,但簡單的字符串處理也可以在沒有 xmlservice 的情況下完成這項工作:

var url = 'https://somewebsite.com/?q=00:11:22:33:44:55';
var html = UrlFetchApp.fetch(url).getContentText();
// we want only the link text displayed from here:
//<td><a href="/company/ubiquiti-networks-inc">Ubiquiti Networks Inc.</a></td>
var string1 = html.split('<td><a href="/company/')[1]; // all after '<td><a href="/company/'
var string2 = string1.split('</a></td>')[0];           // all before '</a></td>'
var string3 = string2.split('>')[1];                   // all after '>'
Logger.log('link text: '+string3);                     // string3 => "Ubiquiti Networks Inc."

我今天只是通過按摩 html 獲得了一些好運:

// close unclosed tags
html = html.replace(/(<(?=link|meta|br|input)[^>]*)(?<!\/)>/ig, '$1/>')
// force script / style content into cdata
html = html.replace(/(<(script|style)[^>]*>)/ig, '$1<![CDATA[').replace(/(<\/(script|style)[^>]*>)/ig, ']]>$1')
// change & to &amp;
html = html.replace(/&(?!amp;)/g, '&amp;')
// now it works! (tested with original url)
let document = XmlService.parse(html)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM