blog/source/_posts/tampermonkey-save-51cto-to-...

6.9 KiB
Raw Blame History

title tags categories abbrlink date
油猴脚本保存51CTO为HTML文件
4d33d521 2023-11-12 14:11:46

背景

因中文互联网内容经常404所以养成了内容自己保存的习惯看到好的内容想保存到自己本地。这次市制作51CTO的保存脚本

调研

51CTO分为两种内容一种是专栏一种是用户写的博客文章。因为博主也买一些专栏所以也需要将其保存起来。所以本次就两种都需要使用。依旧使用油猴脚本来保存正文的HTML。

本次依旧需要再chrome或者edge中安装好油猴插件

开始

本次编写分为三种类型

  1. 抓取专栏章节
  2. 保存每个章节的内容
  3. 保存用户的博客

专栏章节

打开一个专栏详情可以看到详情里有章节目录所以先把章节目录抓取过来。查看元素发现每个章节有a标签可以解析到章节的具体URLspan内有章节标题。所以就需要这两项内容。

先把匹配的URL规则准备好专栏详情的页面是这种形式的 https://blog.51cto.com/cloumn/detail/123 所以匹配规则为

// @match        https://blog.51cto.com/cloumn/detail/*

开始准备抓取URL及标题我们用一个对象元素存储这些数据

let value = {};

var itemList = document.getElementsByClassName("heading");
for (var i = 0; i < itemList.length; i++) {
    var item = itemList[i].getElementsByTagName("a")[0];
    console.log(item)
    value[item.href] = item.getElementsByTagName("span")[0].innerText
}
console.log(JSON.stringify(value))

可以看到抓取到了url及标题。

image

怎么解决存储的问题呢因为每次刷新页面都会丢失这些数据。最简单的方案直接用localStorage所以需要提供一个获取和存储的方法

    // 获取内容,如果没有就初始化一个空对象
    function getStorage() {
        var value = localStorage.getItem('title-list');
        if (!value) {
            value = {};
        } else {
            value = JSON.parse(value);
        }
        return value;
    }
    // 保存内容
    function saveStorage(context) {
        localStorage.setItem('title-list', JSON.stringify(value));
    }
    
    

抓取完成后,跳转到任意章节的详情。

for (let key in value) {
    window.location.href = key;
        return;
}

最后尝试一下内容,是否能正确运行

专栏内容

专栏相对简单因为已经有了URL和标题我们只需要抓取正文内容即可。

专栏章节的url为https://blog.51cto.com/cloumn/blog/1223 所以match也需要加上同样的规则。

专栏内容都在class artical-content-bak main-content下,我们只需要抓取第一个元素即可。


  var context = document.getElementsByClassName("artical-content-bak main-content")[0].innerHTML;

我们依旧在开发者控制台运行一下这个脚本,能正常抓到数据。

标题可以从localStorage中获取并且获取后记得移除后保存毕竟数据已经用完了。

 let obj = getStorage();
 var title = obj[url];
 delete obj[url];
 saveStorage(obj);

最后我们保存html我们使用一个a标签保存

    function download(context, title) {
        const link = document.createElement('a');
        var textBlob = new Blob([context], { type: 'text/plain' });

        link.setAttribute('href', URL.createObjectURL(textBlob));
        link.setAttribute('download', title + ".html");
        link.click();
    }

文章

文章的URL模式为https://blog.51cto.com/u_1234/1234,所以先把mach规则调整好https://blog.51cto.com/u_*/*

其标题在H1元素下正文就是class=container。所以整个抓取内容如下

let title = document.getElementsByTagName("h1")[0].innerText;

let context = document.getElementById("container").innerHTML;

同样在开发者控制台运行一次,发现没问题再整理。

收尾

因为涉及三个页面我们需要判断使用哪个流程这里就精简了直接用if else if作为分支判断

最后脚本聚合到一起

// ==UserScript==
// @name         51CTO保存
// @namespace    http://tampermonkey.net/
// @version      0.1
// @match        https://blog.51cto.com/cloumn/*
// @match   https://blog.51cto.com/u_*/*
// @description  try to take over the world!
// @author       You
// @require      https://unpkg.com/turndown/dist/turndown.js
// @require https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    let btn = document.createElement("button");
    btn.innerHTML = "下载";
    btn.style = "position: fixed;z-index: 999; left: 90%; top: 20px;";

    btn.onclick = function () {
        //code
        copyToMarkdown()
    }

    document.body.append(btn);
    function copyToMarkdown() {
        var url = window.location.href
        if (url.startsWith("https://blog.51cto.com/cloumn/detail")) {
            var value = getStorage();
            var itemList = document.getElementsByClassName("heading");
            for (var i = 0; i < itemList.length; i++) {
                var item = itemList[i].getElementsByTagName("a")[0];
                console.log(item)
                value[item.href] = item.getElementsByTagName("span")[0].innerText
            }
            saveStorage(value);
            for (let key in value) {
                window.location.href = key;
                return;
            }
        } else if (url.startsWith("https://blog.51cto.com/cloumn/blog")) {
            let obj = getStorage();
            var title = obj[url];
            var context = document.getElementsByClassName("artical-content-bak main-content")[0]

            delete obj[url];
            saveStorage(obj);

            download(context.innerHTML, title);
            for (let key in obj) {
                window.location.href = key;
                return;
            }

        } else if (url.startsWith("https://blog.51cto.com/u_")) {
            let title = document.getElementsByTagName("h1")[0].innerText;
           
            let context = document.getElementById("container").innerHTML;
            download(context, title);
        }
    };


    function getStorage() {
        var value = localStorage.getItem('title-list');
        if (!value) {
            value = {};
        } else {
            value = JSON.parse(value);
        }
        return value;
    }

    function saveStorage(context) {
        localStorage.setItem('title-list', JSON.stringify(context));
    }
    function download(context, title) {
        const link = document.createElement('a');
        var textBlob = new Blob([context], { type: 'text/plain' });

        link.setAttribute('href', URL.createObjectURL(textBlob));
        link.setAttribute('download', title + ".html");
        link.click();
    }
})();