网页中用 URL 加载豆瓣图片被拒绝(403)

在豆瓣上爬取电影海报图片的 URL,通过链接直接访问可以正常加载
但是使用 butterfly 主题的友链卡片功能(js+html)时无法加载图片
原因是网站设置了防盗链的策略,会在后台判断请求的 Referrer 属性是不是来自于一个非本域名的网站,如果来源不是本域名就返回 403 forbidden。

解决:

修改 butterfly 主题下 friendship link 的 js 脚本
node_modules\hexo-theme-butterfly\scripts\tag\flink.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
i.link_list.forEach((j) => {
listResult += `
<div class="flink-list-item">
<a href="${j.link}" title="${j.name}" target="_blank">
<div class="flink-item-icon">
<img class="no-lightbox" src="${
j.avatar
}" referrerPolicy="no-referrer" onerror='this.onerror=null;this.src="${urlFor(
hexo.theme.config.error_img.flink
)}"' alt="${j.name}" />
</div>
<div class="flink-item-name">${j.name}</div>
<div class="flink-item-desc" title="${j.descr}">${j.descr}</div>
</a>
</div>`;
});

在其中 img 标签添加referrerPolicy="no-referrer"防止像豆瓣服务器发送 referrer 信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
no-referrer 任何情况下都不发送referer

no-referrer-when-downgrade 在同等安全等级下(例如https页面请求https地址),发送referer,但当请求方低于发送方(例如https页面请求http地址),不发送referer

origin 仅仅发送origin,即protocal+host

origin-when-cross-origin 跨域时发送origin

same-origin 当双方origin相同时发送

strict-origin 当双方origin相同且安全等级相同时发送

unfafe-url 任何情况下都显示完整的referer

或者可以通过使用https://images.weserv.nl/代理来引用图片

1
2
3
4
5
6
7
8
9
<img
src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p1833029967.jpg"
alt="1"
referrerpolicy="no-referrer"
/>
<img
src="https://images.weserv.nl/?url=img3.doubanio.com/view/photo/s_ratio_poster/public/p1833029967.jpg"
alt="2"
/>

参考文章

obsidian 图片引用格式无法被 hexo 正常识别

问题

当迁移 obsidian 中的课程笔记到博客的时候,我发现图片无法被正常渲染。
obsidian 中原生的图片引用方式为

1
![[Pasted image 20240521093347.png]]

这种引用方式可以插入与文章处于同一根目录的图片。但是由于 hexo 是通过将 markdown 文件转换成 html 进行页面显示的,实际在页面中会被直接转换为文本

index.html
1
<p>![[Pasted image 20240521093347.png]]</p>

但是在更改为如下格式以后发现图片仍然不能被正常渲染

1
![](Pasted image 20240521093347.png)

根据 hexo 文档,在启用了资源文件夹以后,应该能正常渲染图片

使用 Markdown 嵌入图片
hexo-renderer-marked 3.1.0 引入了一个新的选项,其允许你无需使用 asset_img 标签插件就可以在 markdown 中嵌入图片
启用后,资源图片将会被自动解析为其对应文章的路径。
例如: image.jpg 位置为 /2020/01/02/foo/image.jpg ,这表示它是 /2020/01/02/foo/ 文章的一张资源图片, ![](image.jpg) 将会被解析为 <img src="/2020/01/02/foo/image.jpg">

但是实际上 hexo 的资源文件夹位于source\_posts\笔记名 而不是原来的 source\年\月\日\笔记名 导致这种方法依然不能正常工作

似乎是因为Pasted image 20240521093347.png这种文件名中含有空格导致的无法被正常转换。(lll ¬ ω ¬)。有时能够正常渲染 markdown 格式的图片。

不过,既然自动转换如此不靠谱,修改大量的图片名称并且同样修改它们在笔记中的名称如此麻烦。不如修改一下插入的方式。

解决

最终发现在实际文章被渲染成 html 以后会被存放在\public\年\月\日\文章名文件夹中(并且复制资源文件夹source\_posts\笔记名中的图片一并存放)
alt text

所以,理论上我们可以直接在笔记中使用 html 源代码<img src="img name.png"/>即可直接引用 public 下被复制的图片了。而不需要经过 hexo 从 markdown 到 html 的复杂转换

convert.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import re

# 读取md文件内容
def read_md_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()

# 替换图片链接并写入新文件
def replace_and_write(content, new_file_path):
new_content = re.sub(r'!\[\[([^]]+)\]\]', r'<img src="\1"/>', content)
with open(new_file_path, 'w', encoding='utf-8') as file:
file.write(new_content)


def main():
md_file_path = r'filename.md' #obsidian格式的文件
new_file_path = 'convertedFile.md' # 新文件路径
content = read_md_file(md_file_path)
replace_and_write(content, new_file_path)
print("替换完成,并已写入新文件")

if __name__ == "__main__":
main()

可以通过以上的转换程序,自动转换所有的图片格式,最终达到了正常显示的效果

ps

为了能够更快地加载图片资源,最好使用在线的图床
但是由于笔记中的图片数量多并且位置关系复杂,使用本地的图片上传并加载更为简便