浅析浏览器书签的导入和导出

简介: 浅析浏览器书签的导入和导出

浏览器有个实用的功能,但是可能用的频率不高,就是书签/收藏的导入和导出,因为现在一般浏览器都有云同步功能,所以这个功能存在感不强。


浏览器书签是可以跨不同的浏览器导入的,所以意味着导出的文件肯定是有一个规范的,我简单搜了一下没有搜到,可能是各家约定俗成的规范,并没有一个正式的标准。


通用的数据交换格式有很多,比如xml、json、yaml,json应该是使用最广泛的,因为易于解析和存储,尺寸也不大,所以很适合浏览器书签的导出,但是,实际上现代浏览器导出的书签文件是html文件。原因不详,也没有搜到相关信息,我猜测原因可能是html文件相对于json来说,普通用户更为熟悉,其次,html文件可以直接使用浏览器打开,当然,json文件也可以使用浏览器打开,但是可能直接点击的时候默认是用文本编辑器打开的,另外它们在浏览器的呈现方式也不一样,html显示的是一个普通的带有一堆超链接的页面,就是一个有点丑的网页,而json打开有点类似源码,不太友好,因为一般用户导出书签就是为了在另一个浏览器导入,所以屏蔽细节并没有什么问题。


html和xml是类似的,所以解析和传输也很简单,接下来看一下实例:


网络异常,图片无法展示
|


基本结构如上,每个文件夹下都有个书签,导出的书签源码如下:


网络异常,图片无法展示
|

网络异常,图片无法展示
|
网络异常,图片无法展示
|


简单分析一下:


1.标签字母都是大写


2.DOCTYPE声明和普通HTML页面不同


3.使用DL和DT来组织书签,DL代表一个文件夹的内容列表,DT代表一个内容,可能是书签也可能是文件夹,文件夹的话会有一个H3标签来表示书签的名字,书签的话就是直接跟一个A标签,DL标签后都跟了一个小写的p标签,有部分标签没有闭合


4.H1标签之前的都和书签内容没有什么关系


5.文件夹名称H3标签和超链接A标签都有ADD_DATELAST_MODIFIED来保存时间信息,该属性不存在也不影响


6.文件夹名称H3标签的属性PERSONAL_TOOLBAR_FOLDER来表示该文件夹下的内容是否显示到浏览器的工具栏,否则会默认放到浏览器的其他文件夹里,但也不一定,有的浏览器会有自己的行为


7.网页的标题icon会转换为base64格式放到ICON属性上,这个属性不存在也不影响

html其实就是普通字符串,所以可以手动生成,常见于一些导航网站和网址收藏工具的导出功能,如五花八门导航(lxqnsys.com/d),有一个需要注意的地方,就是html字符串必须格式化带换行和缩进,下图这种压缩过的是不行的:


网络异常,图片无法展示
|


生成方式也很简单,书签是树结构,所以递归循环拼接即可。


先看一下书签数据的格式,忽略时间和icon:


let bookmarks = [
  {
    name: '',// 文件夹或书签名字
    toolbar: true,// 是否显示到工具栏
    folder: true,// 是否是文件夹
    children: [
      {
        name: '',
        folder: true,
        children: []
      },
      {
        name: '',// 书签名称
        url: ''// 书签url
      }
    ]
  }
]


使用ES6的话可以直接使用模板字符串``来带换行的拼接,很方便:


function createBookmarksStr (bookmarks) {
  let str = `
    <!DOCTYPE NETSCAPE-Bookmark-file-1>
    <!-- This is an automatically generated file.It will be read and overwritten.DO NOT EDIT! -->
    <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
    <TITLE>Bookmarks</TITLE>
    <H1>Bookmarks</H1>
    <DL>
      <p>
  `
  let loop = (root) => {
    let str = ''
    root.forEach((item) => {
      if (item.folder) {
        str += `
          <DT>
            <H3 ${item.toolbar ? `PERSONAL_TOOLBAR_FOLDER="true"` : ''}>${item.name}</H3>
            <DL>
              <p>
        `
        str += loop(item.children)
        str += `
          </DL>
          <p>
        `
      } else {
        str += `
          <DT><A HREF="${item.url}">${item.name}</A>
        `
      }
    })
    return str
  }
  str += loop(bookmarks)
  str += `
    </DL>
    <p>
  `
  return str
}


ES6之前的就需要显式的拼接上换行符:


function createBookmarksStr (bookmarks) {
  var str = '<!DOCTYPE NETSCAPE-Bookmark-file-1>\n<!-- This is an automatically generated file.It will be read and overwritten.DO NOT EDIT! -->\n<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">\n<TITLE>Bookmarks</TITLE>\n<H1>Bookmarks</H1>\n<DL>\n\t<p>\n\t\t<DT>\n\t\t\t<H3 ADD_DATE=\"1568796074\" LAST_MODIFIED=\"1601707819\" PERSONAL_TOOLBAR_FOLDER=\"true\">\u4E66\u7B7E\u680F</H3>\n\t\t\t<DL>\n\t\t\t\t<p>\n\t\t\t\t\t'
  var loop = function (root) {
    var str = ''
    root.forEach(function (item) {
      if (item.folder) {
        str += '<DT>\n\t\t\t\t\t\t<H3 '+ (item.toolbar ? 'PERSONAL_TOOLBAR_FOLDER="true"' : '') +'>'+item.name+'</H3>\n\t\t\t\t\t\t<DL>\n\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t'
        str += loop(item.children)
        str += '</DL>\n\t\t\t\t\t\t<p>\n\t\t\t'
      } else {
        str += '<DT><A HREF=\"'+item.url+'\">'+item.name+'</A>\n\t\t\t\t\t\t\t\t'
      }
    })
    return str
  }
  str += loop(bookmarks)
  str += '</DL>\n\t\t\t<p>\n</DL>\n<p>'
  return str
}


看完了如何生成,接下来看一下如何解析,解析和拼接类似,也是通过深度优先进行遍历,只是会有一些特征判断。字符串如何转化成一棵树,最简单的肯定是先转换为DOM元素,然后再通过操作DOM的api来进行遍历,有一些库可以用来做这件事,不过这里直接用的是iframe


function getBookmarksStrRootNode (str) {
    // 创建iframe
  let iframe = document.createElement('iframe')
  document.body.appendChild(iframe)
  iframe.style.display = 'none'
  // 添加书签dom字符串
  iframe.contentWindow.document.documentElement.innerHTML = str
  // 获取书签树根节点
  return iframe.contentWindow.document.querySelector('dl')
}
function analysisBookmarksStr(str) {
    let root = getBookmarksStrRootNode(str)
}


看一下转换的结果:


书签DOM字符串:


网络异常,图片无法展示
|


转换后的DOM节点:


网络异常,图片无法展示
|


获取到书签树的根节点,接下来递归遍历即可:


function walkBookmarksTree (root) {
    let result = []
  // 深度优先遍历
  let walk = (node, list) => {
      let els = node.children
    if (els && els.length > 0) {
      for (let i = 0; i < els.length; i++) {
        let item = els[i]
        // p标签或h3标签直接跳过
        if (item.tagName === 'P' || item.tagName === 'H3') {
          continue
        }
        // 文件夹不用创建元素
        if (item.tagName === 'DL') {
          walk(els[i], list)
        } else {// DT节点
          let child = null
          // 判断是否是文件夹
          let children = item.children
          let isDir = false
          for(let j = 0; j < children.length; j++) {
            if (children[j].tagName === 'H3' || children[j].tagName === 'DL') {
              isDir = true
            }
          }
          // 文件夹
          if (isDir) {
            child = {
              name: item.tagName === 'DT' ? item.querySelector('h3') ? item.querySelector('h3').innerText : '' : '',
              folder: true,
              children: []
            }
            walk(els[i], child.children)
          } else {// 书签
            let _item = item.querySelector('a')
            child = {
              name: _item.innerText,
              url: _item.href
            }
          }
          list.push(child)
        }
      }
    }
  }
  walk(root, result)
  return result
}
function analysisBookmarksStr(str) {
    let root = getBookmarksStrRootNode(str)
    let result = walkBookmarksTree(root)
}


最后解析的结果:


网络异常,图片无法展示
|


搞定收工,赶紧去试试吧。


相关文章
|
Web App开发 数据安全/隐私保护
Chrome谷歌浏览器密码数据导出与导入管理(实现数据无缝同步)
Chrome谷歌浏览器密码数据导出与导入管理(实现数据无缝同步)
1345 0
|
Web App开发 Linux iOS开发
Chrome浏览器如何导出所有书签并导入书签
【11月更文挑战第4天】本文介绍了如何在 Chrome 浏览器中导出和导入书签。导出时,打开书签管理器,点击“整理”按钮选择“导出书签”,保存为 HTML 文件。导入时,同样打开书签管理器,点击“整理”按钮选择“导入书签”,选择之前导出的 HTML 文件即可。其他主流浏览器也支持导入这种格式的书签文件。
10621 2
|
Web App开发 搜索推荐 NoSQL
如何搭建一个集成导航与在线工具的个性化浏览器私有书签(附详细搭建教程)
在这个信息爆炸的时代,我们都希望拥有一个能够轻松解决多端、多浏览器的收藏和笔记同步问题的神奇工具。Mtab书签正是为此而设计的顶级应用。它将基础导航、记事本、在线小工具和多端同步集于一身,为用户提供了更便利的网络浏览体验,并解决了多端同步的烦恼。
512 0
如何搭建一个集成导航与在线工具的个性化浏览器私有书签(附详细搭建教程)
|
Web App开发
Chrome浏览器导出HTTPS证书
Chrome浏览器导出HTTPS证书
881 0
Chrome浏览器导出HTTPS证书
|
Web App开发 测试技术 API
Postman软件基本用法:浏览器复制请求信息并导入到软件从而测试、发送请求
Postman软件基本用法:浏览器复制请求信息并导入到软件从而测试、发送请求
575 1
|
Web App开发 安全 定位技术
Chrome浏览器书签同步插件floccus与坚果云的协同使用方法
Chrome浏览器书签同步插件floccus与坚果云的协同使用方法
507 1
|
Web App开发 JSON JavaScript
浏览器书签bookmark转json格式
一直使用谷歌浏览器,因为某些原因登录谷歌账号不方便,所以公司和家里的浏览器上收藏的好多书签也不能同步,以前都是直接导出来,然后自己手动导入同步
|
Web App开发
浏览器导入和导出cookie
浏览器导入和导出cookie
|
Web App开发
chrome浏览器 导入burp证书 失败 无法抓包
chrome浏览器 导入burp证书 失败 无法抓包
957 0