前言

我从以前就有搭过好几次博客,有一次发现博客的随机图片网页可以直接打开,遂发现了api,也尝试过存下来,不过是取base64的最后5个字母。现在我重新看到这个接口,翻两下甚至还有不少熟悉的,感到十分怀念,然后就想写一个脚本保存一下。
接口: https://www.dmoe.cc/random.php
请爱惜使用,不要暴力爬取呦。
一些废话:以前还觉得是害羞的见不得光的什么"二次元",现在再看居然有不少我已经看过了,都是前朝遗老了,不由感叹。我也变成老登了。

脚本

import requests
import time
import random
import hashlib

while True:
    res=requests.get("https://www.dmoe.cc/random.php")
    content=res.content
    img_md5 = hashlib.md5(content).hexdigest()
    with open(f"wallpaper/{str(img_md5)}.jpg", "wb") as f:
        f.write(content)
    print(img_md5)
    time.sleep(random.random()*1.5)

爬虫逻辑

很简单,直接使用requests.get(),连headerContent-Type都不用设置。

文件保存逻辑

我们可以使用python自带的hashlib来实现hash算法
注意,md5是hash的一种,不止md5可以实现hash功能

  • type(res.content)<class 'bytes'>
  • hashlib.md5()的传入类型要求是<class 'bytes'>
  • hashlib.md5().digest()的返回值是<class 'bytes'>返回hash后的二进制结果
  • hashlib.md5().digest()的返回值是<class 'str'>返回hash后的十六进制字符串结果

当然也可以把二进制图片base64编码一下,再encode然后hashlib。比如

import base64,hashlib
b64_str = base64.b64encode(img_bytes).decode("utf-8")   # bytes -> base64字符串
hash_value = hashlib.sha256(b64_str.encode("utf-8")).hexdigest()

hash算法简介

主要用于:数据校验,文件指纹,签名
特点:
结果稳定

  • 同样输入永远得到同样输出
  • 通常输出为十六进制字符串

MD5

  • 输出 128 位
  • 很快
  • 已不安全
  • 已经可以构造碰撞

适合:

  • 普通去重
  • 非安全场景的内容标识

不适合:

  • 数字签名
  • 安全校验
  • 密码存储

SHA1

  • 输出 160 位
  • 比 MD5 强一些
  • 也已不安全
  • 也存在实际碰撞攻击
  • 一般也不建议用于安全场景。

SHA256

  • 输出 256 位
  • 安全性高很多
  • 目前广泛使用
  • 速度比 MD5/SHA1 稍慢,但通常完全够用

适合:

  • 文件完整性校验
  • 签名
  • 安全摘要

SHA512

  • 输出 512 位
  • 更长、更强
  • 摘要更大
  • 在某些 64 位平台上不一定比 SHA256 慢很多

适合:

  • 需要更长摘要的场景
  • 高安全需求场景

python实现

import hashlib

s = "hello"

print("md5   =", hashlib.md5(s.encode()).hexdigest())
print("sha1  =", hashlib.sha1(s.encode()).hexdigest())
print("sha256=", hashlib.sha256(s.encode()).hexdigest())
print("sha512=", hashlib.sha512(s.encode()).hexdigest())

但这些仍然不安全,密码存储应该用:

bcrypt
scrypt
argon2
或 hashlib.pbkdf2_hmac

python内置hash函数

print(hash("hello"))
适合:

  • 放到 set
  • 作为 dict 的键
  • 程序内部快速比较/索引

注意:
Python 的字符串哈希 默认每次运行可能不同。你今天运行和下次运行,结果可能不一样。这是 Python 的安全机制(hash 随机化)。

所以:

  • 适合程序内部使用
  • 不适合做持久化、签名、跨进程一致的值(不能存数据库)

有点类似C++的std::mt19937,适合用在算法里。

拓展:一个数学问题

我们假设图片样本空间有限;每次调用api等概率地返回一张图片。
那么:

  • 假设一共有5000张图片,爬取k次,有几张重复?
  • 假设我们爬取k次,重复了n张,我们可以估计样本集有多大?
  • 假设我们要k张图片,样本集有N张图片,我们要抽X次,X的期望是多少?

不过,概率终归是概率,脸黑起来也没办法。

后记:一些唠叨

本来就想写个小脚本的,没想到东看看西瞧瞧写了那么多有意思的东西。写代码也许就是为了打发时间,没什么理由或者意义。有什么有趣的,看到就去琢磨一下。也不用定什么目标,先写个小脚本。最近想看看汪曾祺的《人间草木》,单琢磨一些草草树树,他一个文人也能看得那么起劲,也许就是打发时间吧。不过我一个工科生也不太懂啦。主要最近实在没什么好看的,也许是录取通知书还没下来,心焦吧。