如何将整个文档的HTML作为字符串获取?

326

有没有一种方法在JS中获取整个HTML作为字符串,包括html标签内的内容?

document.documentElement.??

28
唯一正确的答案:https://dev59.com/3nRA5IYBdhLWcg3wzhXZ(**停止给inner/outerHTML答案点赞,它们不提供整个源代码!**) - John
5
document.body.parentElement.innerHTML 翻译为:文档.正文.父元素.内部HTML。 - Radvylf Programs
@John 他们没有提供什么? - B''H Bi'ezras -- Boruch Hashem
@bluejayke doctype和<html>标签本身不包含在innerHTML中,而且doctype在outerHTML中也不存在。请参考paulo62的答案;它给出了两者的输出。 - Pixelated Fish
2
Op 没有要求整个源代码,请冷静一点 John。 - Seth Jeffery
5
不要赞同John加粗的评论!他链接的答案将 && 替换为 &amp;&amp; ,这会破坏所有内联 <script> 标签!你应该使用 document.documentElement.outerHTML ,但请注意它不会获取 <!DOCTYPE html>,所以你需要自己添加。 - joe
17个回答

405

微软在一段时间前添加了outerHTMLinnerHTML属性。

根据MDNouterHTML在Firefox 11、Chrome 0.2、Internet Explorer 4.0、Opera 7、Safari 1.3、Android、Firefox Mobile 11、IE Mobile、Opera Mobile和Safari Mobile中得到支持。 outerHTMLDOM解析和序列化规范中。

请查看quirksmode以获取适用于您的浏览器兼容性信息。 所有浏览器都支持innerHTML

var markup = document.documentElement.innerHTML;
alert(markup);

43
outerHTML 不包含文档类型声明。 - CMCDragonkai
2
运行得非常好!谢谢!是否有办法获取链接到文档的所有文件(包括JS和CSS文件)的大小? - www139
@CMCDragonkai:你可以单独获取doctype,并将其添加到标记字符串之前。虽然不是理想的方法,但是可行的。 - Mike Branski
请注意,以下内容以及任何答案都不一定会给您提供与将页面保存到文件或由view-source生成的文件完全相同的哈希等效内容。似乎DOM会规范化来自字面响应内容的某些字段,例如将DOCTYPE标题大写化。 - wesinat0r

141

10
根据日期/时间戳,这是第一个正确的答案。页面上的某些部分,如XML声明,将被包括在内,并且在使用其他“答案”时,浏览器将操纵代码。这是唯一应该被点赞的帖子(dos在三天后发布了)。人们需要注意! - John
5
这并不完全正确,因为serializeToString会执行HTML编码。例如,如果您的代码包含定义字体的样式,如“Times New Roman”,Times和serif,那么引号将被转义为HTML实体。也许对你们中的一些人来说这不太重要,但对我来说是... - Marko
6
OP实际上要求“在HTML标签内的整个HTML内容”。而Colin Burnett选择的最佳答案确实达到了这一点。Erik的答案将包括html标签和文档类型声明。话虽如此,对我来说,这完全是意外之喜,正是我所需要的!您的评论也有帮助,因为它让我花更多时间研究这个答案,所以谢谢 :) - evanrmurphy
5
我认为人们应该小心处理此问题,因为它返回的值并不是浏览器实际接收到的HTML。在我的情况下,它向“html”标签添加了服务器实际未发送的属性:( - onassar
1
它在每个浏览器中都得到了支持。这怎么算是差劲的浏览器支持呢? - user187676
显示剩余7条评论

54

我尝试了各种答案以查看返回的内容。我正在使用最新版本的Chrome。

建议document.documentElement.innerHTML;返回<head>...</body>

Gaby的建议document.getElementsByTagName('html')[0].innerHTML;返回相同内容。

建议document.documentElement.outerHTML;返回除了“doctype”之外的所有内容<html><head> ... </body></html>

你可以使用document.doctype;来检索doctype对象。 这会返回一个对象,而不是字符串,因此,如果需要提取所有doctype(包括HTML5)的详细信息作为字符串,则在此处描述:使用Javascript获取HTML的DocType作为字符串

我只想要HTML5,因此以下内容对我来说已足够创建整个文档:

alert('<!DOCTYPE HTML>' + '\n' + document.documentElement.outerHTML);


8
这是最完整的答案,应该被采纳。截至2016年,浏览器兼容性已经完全,因此不再需要详细说明(如当前被采纳的答案)。 - Dan Dascalescu

51
我相信document.documentElement.outerHTML应该为您返回结果。
根据MDNouterHTML在Firefox 11、Chrome 0.2、Internet Explorer 4.0、Opera 7、Safari 1.3、Android、Firefox Mobile 11、IE Mobile、Opera Mobile和Safari Mobile中得到支持。 outerHTMLDOM解析和序列化规范中。 outerHTML属性的MSDN页面指出,它在IE 5+中得到支持。Colin的答案链接到W3C quirksmode页面,该页面提供了跨浏览器兼容性的良好比较(对于其他DOM功能也是如此)。

5
有没有一种方法可以获取包括doctype和html标签在内的所有内容? - trusktr
这个答案与Colin的几乎相同(并且参考了它)。也许可以合并一下? - Dan Dascalescu
1
我的其实是第一个。:P - Noldorin
@Noldorin,你为什么引用MSDN? - Pacerier
@Pacerier:你是说我为什么要引用它吗?这已经8年前的事情了哈哈!但事实是,我想我只是想强调IE的支持。而且由于IE是由微软生产的,MSDN似乎是一个很好的权威机构... - Noldorin
显示剩余4条评论

11

你也可以这样做:

document.getElementsByTagName('html')[0].innerHTML

你将无法获取文档类型或html标签,但可以获得其他所有内容...


7
document.documentElement.outerHTML

1
不是所有的浏览器都支持此功能。 - Colin Burnett
2
支持Firefox 11,Chrome 0.2,Internet Explorer 4.0,Opera 7,Safari 1.3,Android,Firefox Mobile 11,IE Mobile,Opera Mobile和Safari Mobile([MDN](https://developer.mozilla.org/en-US/docs/DOM/element.outerHTML))。 outerHTMLDOM解析和序列化规范中。 - XP1
Colin的回答更加详细。 - Dan Dascalescu

6

可能只在IE浏览器中出现:

>     webBrowser1.DocumentText

从 1.0 版本开始使用的 FF:

//serialize current DOM-Tree incl. changes/edits to ss-variable
var ns = new XMLSerializer();
var ss= ns.serializeToString(document);
alert(ss.substr(0,300));

可能在火狐浏览器中工作。(显示源文本最开始的前300个字符,主要是doctype-defs)

但请注意,火狐浏览器的正常“另存为”对话框可能不会保存当前页面状态,而是原始加载的X/h/tml源文本!(将ss POST到某个临时文件并重定向到该文件可以提供可保存的源文本和之前进行过的更改/编辑。)

尽管火狐浏览器令人惊喜地通过“返回”实现了良好的恢复,并且对于类似输入字段、文本区域等的内容可以在“保存(为)...”中包含状态/值,但不能在contenteditable/designMode中的元素中使用...

如果不是xhtml- resp. xml文件(mime类型,不仅仅是文件扩展名!), 可以使用document.open/write/close将合适的内容设置为源层,这将在用户从火狐浏览器的文件/保存菜单中保存时保存。

参见:http://www.w3.org/MarkUp/2004/xhtml-faq#docwrite 或者 https://developer.mozilla.org/en-US/docs/Web/API/document.write

对于X(ht)ML问题中立,尝试将“view-source:http://...”作为一个(由脚本制作的?)iframe的src属性值,以在火狐浏览器中访问iframe文档:

<iframe-elementnode>.contentDocument,查看google“mdn contentDocument”以获取适当的成员,例如'textContent'。


3
document.documentElement.innerHTML

这不会返回<html ...>标签。 - Dan Dascalescu

3
为了获取位于 <html>...</html> 之外的内容,尤其是 <!DOCTYPE ...> 声明,您可以遍历 document.childNodes,并将每个节点转换为字符串:
const html = [...document.childNodes]
    .map(node => nodeToString(node))
    .join('\n') // could use '' instead, but whitespace should not matter.

function nodeToString(node) {
    switch (node.nodeType) {
        case node.ELEMENT_NODE:
            return node.outerHTML
        case node.TEXT_NODE:
            // Text nodes should probably never be encountered, but handling them anyway.
            return node.textContent
        case node.COMMENT_NODE:
            return `<!--${node.textContent}-->`
        case node.DOCUMENT_TYPE_NODE:
            return doctypeToString(node)
        default:
            throw new TypeError(`Unexpected node type: ${node.nodeType}`)
    }
}

我将这段代码发布在 npm 上,链接为 document-outerhtml
编辑说明:上面的代码依赖于一个名为doctypeToString的函数;其实现可以如下(下面的代码已经在npm上发布为doctype-to-string):
function doctypeToString(doctype) {
    if (doctype === null) {
        return ''
    }
    // Checking with instanceof DocumentType might be neater, but how to get a
    // reference to DocumentType without assuming it to be available globally?
    // To play nice with custom DOM implementations, we resort to duck-typing.
    if (!doctype
        || doctype.nodeType !== doctype.DOCUMENT_TYPE_NODE
        || typeof doctype.name !== 'string'
        || typeof doctype.publicId !== 'string'
        || typeof doctype.systemId !== 'string'
    ) {
        throw new TypeError('Expected a DocumentType')
    }
    const doctypeString = `<!DOCTYPE ${doctype.name}`
        + (doctype.publicId ? ` PUBLIC "${doctype.publicId}"` : '')
        + (doctype.systemId
            ? (doctype.publicId ? `` : ` SYSTEM`) + ` "${doctype.systemId}"`
            : ``)
        + `>`
    return doctypeString
}


1

我总是使用

document.getElementsByTagName('html')[0].innerHTML

可能不是正确的方式,但当我看到它时我能理解它。


这是不正确的,因为它不会返回<html...>标签。 - Dan Dascalescu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接