在谷歌应用程序脚本中解析 html 的最佳方法是啥
Posted
技术标签:
【中文标题】在谷歌应用程序脚本中解析 html 的最佳方法是啥【英文标题】:What is the best way to parse html in google apps script在谷歌应用程序脚本中解析 html 的最佳方法是什么 【发布时间】:2013-10-27 14:55:14 【问题描述】:var page = UrlFetchApp.fetch(contestURL);
var doc = XmlService.parse(page);
上面的代码在使用时会出现解析错误,但是如果我将 XmlService 类替换为已弃用的 Xml 类,并设置了 lenient 标志,它会正确解析 html。
var page = UrlFetchApp.fetch(contestURL);
var doc = Xml.parse(page, true);
这个问题主要是因为html的javascript部分没有CDATA,解析器报错如下。
The entity name must immediately follow the '&' in the entity reference.
即使我使用正则表达式删除了所有<script>(.*?)</script>
,它仍然会抱怨,因为<br>
标签没有关闭。
有没有一种将 html 解析为 DOM 树的干净方法。
【问题讨论】:
见***.com/a/1732454/362634 ... 您可能会获取页面并使用解析器去除不需要的标签,然后启动另一个解析,这可能是可能的。我确实知道 XmlService 运行良好,但有点问题。 【参考方案1】:我遇到了同样的问题。我可以通过首先使用已弃用的Xml.parse
来规避它,因为它仍然有效,然后选择 body XmlElement,然后将其 Xml 字符串传递给新的 XmlService.parse
方法:
var page = UrlFetchApp.fetch(contestURL);
var doc = Xml.parse(page, true);
var bodyHtml = doc.html.body.toXmlString();
doc = XmlService.parse(bodyHtml);
var root = doc.getRootElement();
注意:如果旧的 Xml.parse
从 Google 脚本中完全删除,此解决方案可能不起作用。
【讨论】:
结构完全不正确且无法验证的“html”文档和 XmlService.parse 只会阻塞它们怎么办? doc.html.body 出于某种原因对我来说是一个数组,每个元素似乎都不一样 我认为 javascript 导致元素提前结束 这很棒,因为它允许您使用记录良好的 XmlService,否则它将无法使用,因为它无法解析 HTML 文件。如果有人想知道如何选择元素,这将有所帮助:sites.google.com/site/scriptsexamples/learn-by-example/…(抱歉新提交,编辑为时已晚..) 2020 年的注意事项:Xml.parse 确实已被删除。【参考方案2】:在 2021 年,我所知道的在 .gs
端解析 HTML 的最佳方法是......
-
单击库旁边的 +
输入 1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0
点击“查找”
点击添加
示例用法:
const contentText = UrlFetchApp.fetch('https://www.somesite.com/').getContentText();
const $ = Cheerio.load(contentText);
$('.some-class').first().text();
就是这样——这可能是我们在 GAS 中最接近 jQuery 的 DOM 选择了。 .first()
很重要,否则您可能会提取比预期更多的内容(将其视为使用 querySelector()
而不是 querySelectorAll()
)。
信用到期:https://github.com/tani/cheeriogs
【讨论】:
这是我今天在所有搜索中找到的最佳答案。我对它进行了编码,它工作得非常好。将此信息与媒体 (medium.com/@stefanhyltoft/…) 上的博客和一些 Cheerio 文档相结合,我能够使其适用于解析 covid 医院数据的非常复杂的 HTML 表格。【参考方案3】:从 2020 年 5 月起,您现在可以使用 Cheerio library for Google Apps Script 执行此操作。
返回***主页的内容
const content = getContent_('https://en.wikipedia.org');
const $ = Cheerio.load(content);
Logger.log($('#mp-right').text());
返回***首页第一段<p>
的内容
const content = getContent_('https://en.wikipedia.org');
const $ = Cheerio.load(content);
Logger.log($('p').first().text());
要添加到您的项目中:
在 Google Apps 脚本编辑器中选择
Resources - Libraries...
。在Add a library
字段中输入项目密钥1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0
,然后单击“添加”。选择最高版本号,点击“保存”。
【讨论】:
奇怪的是,这个答案比一年后基本相同的答案得票少。信用到期。 @TNguyen 因为这篇文章是从另一个观点较少的问题合并而来的。【参考方案4】:我发现在 google 应用程序中解析 html 的最佳方法是避免使用 XmlService.parse 或 Xml.parse。 XmlService.parse 不适用于某些网站的不良 html 代码。
这里有一个基本示例,说明如何在不使用 XmlService.parse 或 Xml.parse 的情况下轻松解析任何网站。在此示例中,我从“wikipedia.org/wiki/President_of_the_United_States”检索总统列表 使用常规的 javascript document.getElementsByTagName(),并将值粘贴到我的 google 电子表格中。
1- 创建一个新的 Google 表格;
2- 单击菜单工具 > 脚本编辑器... 打开一个带有代码编辑器窗口的新选项卡,并将以下代码复制到您的 Code.gs 中:
function onOpen()
var ui = SpreadsheetApp.getUi();
ui.createMenu("Parse Menu")
.addItem("Parse", "parserMenuItem")
.addToUi();
function parserMenuItem()
var sideBar = HtmlService.createHtmlOutputFromFile("test");
SpreadsheetApp.getUi().showSidebar(sideBar);
function getUrlData(url)
var doc = UrlFetchApp.fetch(url).getContentText()
return doc
function writeToSpreadSheet(data)
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var row=1
for (var i = 0; i < data.length; i++)
var x = data[i];
var range = sheet.getRange(row, 1)
range.setValue(x);
var row = row+1
3- 将 HTML 文件添加到您的 Apps 脚本项目中。打开脚本编辑器并选择文件 > 新建 > Html 文件,并将其命名为“test”。然后将以下代码复制到您的 test.html 中
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<input id= "mButon" type="button" value="Click here to get list"
onclick="parse()">
<div hidden id="mOutput"></div>
</body>
<script>
window.onload = onOpen;
function onOpen()
var url = "https://en.wikipedia.org/wiki/President_of_the_United_States"
google.script.run.withSuccessHandler(writeHtmlOutput).getUrlData(url)
document.getElementById("mButon").style.visibility = "visible";
function writeHtmlOutput(x)
document.getElementById('mOutput').innerHTML = x;
function parse()
var list = document.getElementsByTagName("area");
var data = [];
for (var i = 0; i < list.length; i++)
var x = list[i];
data.push(x.getAttribute("title"))
google.script.run.writeToSpreadSheet(data);
</script>
</html>
4- 保存您的 gs 和 html 文件并返回到您的电子表格。重新加载您的电子表格。单击“解析菜单”-“解析”。然后点击侧边栏中的“单击此处获取列表”。
【讨论】:
这似乎存在一些风险,当您在 mOutput div 下添加任何内容时,允许您通过网络读取的任何内容运行脚本。如果您从第 3 方服务器加载 html,我建议将输出粘贴在禁用脚本的沙盒 iframe 中。 或者我想更好的是在字符串上使用 DOMParser 来创建一个 Document 而无需将其添加到活动 DOM 中。 developer.mozilla.org/en-US/docs/Web/API/DOMParser【参考方案5】:Xml.parse()
有一个打开宽松解析的选项,这有助于解析 HTML。请注意,Xml
服务已被弃用,而较新的 XmlService
没有此功能。
【讨论】:
【参考方案6】:对于简单的任务,例如从网页中获取一个值,您可以使用正则表达式。正则表达式在解析 HTML 方面是出了名的糟糕,因为它可能会出现各种奇怪的情况,但如果您对正在访问的 HTML 有信心,这有时可能是最简单的方法。
这是一个获取页面<title>
标签内容的示例:
var page = UrlFetchApp.fetch(contestURL);
var regExp = new RegExp("<title>(.*)</title>", "gi");
var result = regExp.exec(page.getContentText());
// [1] is the match group when using parenthesis in the pattern
var value = result ? result[1] : 'No title found';
【讨论】:
最后一行为我返回null
。
使用正则表达式解析html/xml通常是一个非常糟糕的主意(tm) :blog.codinghorror.com/parsing-html-the-cthulhu-way
@jtatria 你是对的。但如果是标题,它可能是安全的。非贪婪的版本可能会更好。【参考方案7】:
我知道这不是 OP 所要求的,但我在寻找一些 html 解析选项时发现了这个问题 - 所以它也可能对其他人有用。
有一个easy to use the library for TEXT parsing。如果您只想从 html(xml) 代码中获取一条信息,这很有用。
EDIT 2021: 脚本库 ID 为: 1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw
如上图所示
function getData()
var url = "https://chrome.google.com/webstore/detail/signaturesatori-central-s/fejomcfhljndadjlojamaklegghjnjfn?hl=en";
var fromText = '<span class="e-f-ih" title="';
var toText = '">';
var content = UrlFetchApp.fetch(url).getContentText();
var scraped = Parser
.data(content)
.from(fromText)
.to(toText)
.build();
Logger.log(scraped);
return scraped;
【讨论】:
脚本说解析器没有定义。 2021:脚本id为:1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw
【参考方案8】:
如果你正在使用
Google Apps 脚本的 Cheerio 库
Source code
Library page(⭐星吧!)
按库 ID 安装:
1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0
获取当前表情符号from unicode.org的函数:
function getEmojis()
var t = new Date();
var url = 'https://unicode.org/emoji/charts/full-emoji-list.html';
var fetch = UrlFetchApp.fetch(url);
var contentText = fetch.getContentText();
//console.log(new Date() - t);
// Cherio
var $ = Cheerio.load(contentText);
var data = [];
$("table > tbody > tr").each((index, element) =>
var row = [];
$(element).find("td").each((index, child) =>
row.push($(child).text());
);
if (row.length > 0)
data.push(row);
);
//console.log(data);
//console.log(new Date() - t);
// Result
return data;
↑示例代码展示了如何解析表格并将其放入[[array]]
可用作自定义函数:
奖金
解析网站可能是一项耗时的操作 + 您可能会达到极限。 这是一个包含完整版脚本的测试文件:
https://docs.google.com/spreadsheets/d/1iO7YjYWyfseQu_YCfRbGDPg7NskOgMu_iO1iGjr7KxY/edit#gid=93365395
↑ 它使用CasheService
来减少调用次数。
【讨论】:
【参考方案9】:本来就没有办法,除非你做你已经尝试过的事情,如果 html 不符合 xml 格式,那将无法工作。
【讨论】:
【参考方案10】:有两种选择
a) 一种是使用 JavaScript 的字符串函数。首先使用string.indexOf()
定位您的标签,然后使用string.substring()
提取您想要的数据。
b) 另一种选择是使用Xml Service。
【讨论】:
选项 a) 不够方便。如果选择了 XPath,选项 b) 会很好。我找不到这样的功能。【参考方案11】:无法在 Apps 脚本中创建 HTML DOM 服务器端。使用正则表达式可能是您的最佳选择,至少对于简单的解析而言。
【讨论】:
以上是关于在谷歌应用程序脚本中解析 html 的最佳方法是啥的主要内容,如果未能解决你的问题,请参考以下文章
在谷歌地图上覆盖 ESRI shapefile 的最佳方法?