web-dev-qa-db-ja.com

XmlServiceを使用せずにGoogle Apps ScriptでHTML文字列を解析する方法は?

GoogleスプレッドシートとGoogle Apps Scriptを使用してスクレーパーを作成したい。私はそれが可能であることを知っており、それに関するいくつかのチュートリアルとスレッドを見てきました。

主なアイデアは以下を使用することです:

_  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()メソッドの問題だと思います。

私はこのスレッドで読んだことがあります:

混乱したHTMLからのGoogleアプリスクリプト解析テーブル および GoogleアプリスクリプトでHTMLを解析する最良の方法は何ですかxml.parse()と呼ばれる非推奨のメソッドを使用できますHTMLの解析を許可する2番目のパラメーターを受け入れます。しかし、私が述べたように、それは非推奨であり、どこにもドキュメントがありません。 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を解析することを考えましたが、見つかりませんでした。

私の最終的な目標は、価格、リンク、製品名などの一連のページから情報を取得することです。一連のRegExを使用してこれを管理しています。

_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を解析し、その要素に簡単にアクセスする方法が必要です。実際にはアドオンではありません。しかし、シンプルなGoogleアプリのスクリプト..

15
user3347814

私はこれを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;
}
8
Fabian Thommen

これについては前に説明しました。こちらをご覧ください: Google Appsスクリプトでhtmlを解析する最良の方法は何ですか

[〜#〜] xml [〜#〜]サービスとは異なり、XMLService不正な形式のhtmlをあまり許しません。 Justin Bicknellによる答えのトリックが仕事をします。 [〜#〜] xml [〜#〜]サービスは廃止されましたが、引き続き機能します。

7
Sujay Phadke

私はあなたの問題を応援しました。 jQueryのようなAPIであるcheerioとしてGASで動作します。このようにすることができます。

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

https://github.com/asciian/cheeriogs も参照してください

6
asciian

特定のウェブサイトではコンテンツの自動スクレイピングが許可されていない場合がありますので、Apps Scriptを使用してコンテンツを抽出する前に、利用規約またはサービスを参照してください。

XmlServiceは有効なXMLドキュメントに対してのみ機能し、ほとんどのHTML(特にHTML5)は有効なXMLではありません。単純にXmlServiceと呼ばれるXmlの以前のバージョンでは、「寛容な」解析が可能で、これによりHTMLも解析できます。このサービスは2013年に廃止されましたが、当面は機能します。リファレンスドキュメントは使用できなくなりましたが、この 古いチュートリアル は使用方法を示しています。

別の代替方法は、 Kimono のようなサービスを使用することです。これは、スクレイピングおよび解析パーツを処理し、UrlFetchApp経由で呼び出して構造化データを取得できる単純なAPIを提供します。

2
Eric Koleda

javascriptを使用 htmlを解析できますか? Google Appsスクリプトがhtmlを文字列として取得し、それをjavascript関数に返した場合、Google Appsスクリプトの外部で問題なく解析できるようです。スクレイピングするタグは、コンテンツを保存する専用のGoogle Apps機能に送信できます。

これはおそらくもっと簡単に実現できます jQueryを使用

0
Eric Dauenhauer

Google App Scriptを使用してスクレイプする非常に適切な代替手段を見つけました。 PhantomJS Cloud と呼ばれます。 rlFetchApp を使用してAPIにアクセスできます。これにより、ページでJqueryコードを実行できるようになり、作業が非常に簡単になります。

0
user3347814

おそらく最もクリーンなアプローチではありませんが、単純な文字列処理は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."
0
vchrizz