职贝云数AI新零售门户

标题: 微博图床挂了! [打印本页]

作者: 只要你感受就    时间: 2023-2-1 13:02
标题: 微博图床挂了!
(, 下载次数: 0)
不断担心的事情还是发生了。
作为hexo多年的运用者,微博图床不断是我的默许选项,hexo+typora+iPic更是我这几年写文章的黄金组合。而图床中,新浪图床不断都是我的默许选项,速度快、波动同时支持大图片批量上传更是让其成为了众多图床工具的默许选项。虽然往年早些的时分,部分如「ws1、ws2……」的域名就曾经无法运用了,但经过某些手腕还是可以让其存活的,而最近,一切调用的微博图床图片都无法加载并提示“403 Forbidden”了。

(, 下载次数: 0)
Tips:图片中出现的Tengine是淘宝在Nginx的基础上修正后开源的一款[[实战教学/AI画家第三弹——毕业设计大杀器Flask#^fc8b19|Web服务器]],基本上,Tengine可以被看作一个更好的Nginx,或者是Nginx的超集,概况可参考 淘宝Web服务器Tengine正式开源 - The Tengine Web Server
刚得知这个音讯的时分,我的第一想法其实是非常生气的,毕竟本人这几年上千张图片都是用的微博图床,如今还没备份就被403了,可细心一想,说到底还是把东西交在别人手里的下场,微博又不是慈善企业,也要控制成本,不断睁一只眼闭一只眼让大家收费用就算了,出了成绩还是不太好怪到微博下去的。
那么有什么比较好的办法处理这个成绩呢?
查遍了网上一堆复制/粘贴出来的文章,不是开启反向代理就是更改央求头,真正情愿从根本上处理成绩的没几个。
假如不想将本人沉淀的博客、文章托管在印象笔记、notion、语雀这些在线平台的话,想要彻底处理这个成绩最好的方式是:自建图床!
为了更好的处理成绩,我们先弄明白,403是什么,以及我们存在微博上的图片终究是如何被403的。
403

百度百科,对于403错误的解释很简单
403错误是一种在网站访问过程中,常见的错误提示,表示资源不可用。服务器了解客户的央求,但回绝处理它,通常由于服务器上文件或目录的权限设置导致的WEB访问错误。
所以说到底是由于访问者无权访问服务器端所提供的资源。而微博图床出现403的缘由次要在于微博开启了防盗链。
防盗链的原理很简单,站点在得知有央求时,会先判别央求头中的信息,假如央求头中有Referer信息,然后根据本人的规则来判别Referer头信息能否符合要求,Referer 信息是央求该图片的来源地址。
假如盗用网站是 https 的 协议,而图片链接是 http 的话,则从 https 向 http 发起的央求会由于安全性的规定,而不带 referer,从而完成防盗链的绕过。官方输入图片的时分,判别了来源(Referer),就是从哪个网站访问这个图片,假如是你的网站去加载这个图片,那么 Referer 就是你的网站地址;你的网址一定没在官方的白名单内,(当然作为可操作性极强的阅读器来说 referer 是完全可以伪造一个官方的 URL 这样也也就也可以饶过限制 )所以就看不到图片了。

(, 下载次数: 0)
处理成绩

解释完原理之后我们发现,其实只需想办法在本人的个人站点中设置好referer就可以处理这个成绩,但说到底也只是治标不治标,真正处理这个成绩就是想办法将图片迁移到本人的个人图床上。
如今的图床工具很多,iPic、uPic、PicGo等一堆工具既收费又开源,成绩在于选择什么云存储服务作为本人的图床以及如何交换本人这上千张图片。
什么是OSS以及如何选择

「OSS」的英文全称是Object Storage Service,翻译成中文就是「对象存储服务」,官方一点解释就是对象存储是一种运用HTTP API存储和检索非结构化数据和元数据对象的工具。
白话文解释就是将系统所要用的文件上传到云硬盘上,该云硬盘提供了文件下载、上传等一列服务,这样的服务以及技术可以统称为OSS,业内提供OSS服务的厂商很多,知名常用且成规模的有阿里云、腾讯云、百度云、七牛云、又拍云等。
对于我们这些个人用户来说,这些云厂商提供的服务都是足够运用的,我们所要关怀的便是成本 。
笔者运用的是七牛云,它提供了10G的收费存储,基本曾经够用了。
有人会思索将GitHub/Gitee作为图床,并且这样的文章在中文互联网里广泛传播,由于很多人的个人站点都是托管在GitHub Pages上的,但是个人建议是不要这么做。
首先GitHub在国内的访问就很受限,很多场景都需求迷信上网才能获得残缺的阅读体验。再加上GitHub官方也不引荐将Git仓库存储大文件,GitHub建议仓库保持较小,理想状况下小于 1 GB,激烈建议小于 5 GB。
如何交换上千张图片

交换文章中的图片链接和“把大象放进冰箱里”步骤是差不多的
思索到我们需求迁移的文件数量较多,手动操作一定是不太可行的,因此我们可以采用代码的方式写一个脚本完成上述操作。思索到本人曾经是一个成熟的Java工程师了,这个功能就干脆用Java写了。
为了减少代码量,精简代码结构,我这里引入了几个第三方库,当然不引入也行,假如不引入有一些繁琐而又简单的业务逻辑需求本人完成,有点糜费工夫了。
整个脚本逻辑非常简单,流程如下:

(, 下载次数: 0)
获取博客文件夹下的Markdown文件

这里我们直接运用hutool这个三方库,它内置了很多非常适用的工具类,获取一切markdown文件也变得非常容易
  1. /**
  2. * 挑选出一切的markdown文件
  3. */
  4. public static List<File> listAllMDFile() {
  5.     List<File> files = FileUtil.loopFiles(VAULT_PATH);
  6.     return files.stream()
  7.        .filter(Objects::nonNull)
  8.         .filter(File::isFile)
  9.         .filter(file -> StringUtils.endsWith(file.getName(), ".md"))
  10.         .collect(Collectors.toList());
  11. }
复制代码
获取文件中的一切包含微博图床的域名

经过Hutools内置的FileReader我们可以直接读取markdown文件的内容,因此我们只需求解析出文章里包含微博图床的链接即可。我们可以借助正则表达式疾速获取一段文本内容里的一切url,然后做一下filter即可。
  1. /**
  2. * 获取一段文本内容里的一切url
  3. *
  4. * @param content 文本内容
  5. * @return 一切的url
  6. */
  7. public static List<String> getAllUrlsFromContent(String content) {
  8.     List<String> urls = new ArrayList<>();
  9.     Pattern pattern = Pattern.compile(
  10.         "\\b(((ht|f)tp(s?)\\:\\/\\/|~\\/|\\/)|www.)" + "(\\w+:\\w+@)?(([-\\w]+\\.)+(com|org|net|gov"
  11.             + "|mil|biz|info|mobi|name|aero|jobs|museum" + "|travel|[a-z]{2}))(:[\\d]{1,5})?"
  12.             + "(((\\/([-\\w~!$+|.,=]|%[a-f\\d]{2})+)+|\\/)+|\\?|#)?" + "((\\?([-\\w~!$+|.,*:]|%[a-f\\d{2}])+=?"
  13.             + "([-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)" + "(&(?:[-\\w~!$+|.,*:]|%[a-f\\d{2}])+=?"
  14.             + "([-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)*)*" + "(#([-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)?\\b");
  15.     Matcher matcher = pattern.matcher(content);
  16.     while (matcher.find()) {
  17.         urls.add(matcher.group());
  18.     }
  19.     return urls;
  20. }
复制代码
下载图片

用Java下载文件的代码在互联网上失实是反复率最高的一批检索内容了,这里就直接贴出代码了。
  1. public static void download(String urlString, String fileName) throws IOException {
  2.     File file = new File(fileName);
  3.     if (file.exists()) {
  4.         return;
  5.     }
  6.     URL url = null;
  7.     OutputStream os = null;
  8.     InputStream is = null;
  9.     try {
  10.         url = new URL(urlString);
  11.         URLConnection con = url.openConnection();
  12.         // 输入流
  13.         is = con.getInputStream();
  14.         // 1K的数据缓冲
  15.         byte[] bs = new byte[1024];
  16.         // 读取到的数据长度
  17.         int len;
  18.         // 输入的文件流
  19.         os = Files.newOutputStream(Paths.get(fileName));
  20.         // 末尾读取
  21.         while ((len = is.read(bs)) != -1) {
  22.             os.write(bs, 0, len);
  23.         }
  24.     } finally {
  25.         if (os != null) {
  26.             os.close();
  27.         }
  28.         if (is != null) {
  29.             is.close();
  30.         }
  31.     }
  32. }
复制代码
上传图片

下载完图片后我们便要着手将下载上去的图片上传至我们本人的云存储服务了,这里直接给出七牛云上传图片的文档链接了,文档里写的非常详细,我就不赘述了
Java SDK_SDK 下载_对象存储 - 七牛开发者中心
全局处理

经过阅读代码的细节,我们可以发现,我们的方法粒度是单文件的,但理想上,我们可以先将一切的文件遍历一遍,一致停止图片的下载、上传与交换,这样可以节约点工夫。
一致交换的逻辑也很简单,我们声明一个全局Map,
  1. private static final Map<String, String> URL_MAP = Maps.newHashMap();
复制代码
其中,key是旧的新浪图床的链接,value是新的自定义图床的链接。
我们将listAllMDFile这一步中所获取到的一切文件里的一切链接保存于此,下载时只需遍历这个Map的key即可获取到需求下载的图片链接。然后将上传后得到的新链接作为value存在到该Map中即可。
全文交换链接并更新文件

有了上述这些处理步骤,接上去一步就变的异常简单,只需求遍历每个文件,将婚配到全局Map中key的链接交换成Map中的value即可。
  1. /**
  2. * 交换一切的图片链接
  3. */
  4. private static String replaceUrl(String content, Map<String, String> urlMap) {
  5.     for (Map.Entry<String, String> entry : urlMap.entrySet()) {
  6.         String oldUrl = entry.getKey();
  7.         String newUrl = entry.getValue();
  8.         if (StringUtils.isBlank(newUrl)) {
  9.             continue;
  10.         }
  11.     content = RegExUtils.replaceAll(content, oldUrl, newUrl);
  12.     }
  13.     return content;
  14. }
复制代码
我们借助commons-lang完成字符串婚配交换,借助Hutools完成文件的读取和写入。
  1. files.forEach(file -> {
  2.     try {
  3.         FileReader fileReader = new FileReader(file.getPath());
  4.         String content = fileReader.readString();
  5.         String replaceContent = replaceUrl(content, URL_MAP);
  6.         FileWriter writer = new FileWriter(file.getPath());
  7.         writer.write(replaceContent);
  8.     } catch (Throwable e) {
  9.         log.error("write file error, errorMsg:{}", e.getMessage());
  10.     }
  11. });
复制代码
为了安全起见,最好把文件放在新的目录中,不要直接交换掉原来的文件,否则程序出现不测就费事了。
接上去我们只需求运转程序,静待备份结果跑完即可。
以上就是本文的全部内容了,希望对你有所协助




欢迎光临 职贝云数AI新零售门户 (https://www.taojin168.com/cloud/) Powered by Discuz! X3.5