前言

当你想去破解一个网站的JS加密时,你还是需要考虑,你的JS功底足够好吗?其次是这件事情的价值值不值得去花费大量的时间去破解JS加密?思考好这些问题再决定是否要使用破解JS加密的方式去爬虫,毕竟是破解,这是既花费时间,还看一定运气的事情。三思而后行


JS破解有道词典小案例

查找网站中的JS加密文件是哪一个,查看页面源代码就可以找到了。主要还是破解过程,下面直接上代码:

  1. import requests
  2. import time
  3. import random
  4. import hashlib # 使用md5加密
  5. # 请求头
  6. headers = {
  7. 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0',
  8. 'Referer': 'https://fanyi.youdao.com/?keyfrom=dict2.index',
  9. 'Cookie': 'YOUDAO_MOBILE_ACCESS_TYPE=1; DICT_UGC=be3af0da19b5c5e6aa4e17bd8d90b28a|; OUTFOX_SEARCH_USER_ID=1523284257@60.12.58.56; JSESSIONID=abcDb6kMwIOwfgCZDgJOx; OUTFOX_SEARCH_USER_ID_NCOO=2124804081.0772424; ___rl__test__cookies=1624086557348'
  10. }
  11. # 请求的翻译服务器网址
  12. url = "https://fanyi.youdao.com/translate_o?smartresult=dict,rule"
  13. """
  14. --------------------------------------------------JS加密分析----------------------------------------------------
  15. 目标参数
  16. i: n, 翻译的单词
  17. from: C,
  18. to: S,
  19. smartresult: "dict",
  20. client: E,
  21. salt: r.salt, str(时间戳) + 0~10的一个随机数
  22. sign: r.sign, md5加密("fanyideskweb" + 翻译的单词 + salt + "Tbh5E8=q6U3EXe+&L[4c@")
  23. lts: r.ts, str(时间戳)
  24. bv: r.bv, md5加密(浏览器的版本号)
  25. doctype: "json",
  26. version: "2.1",
  27. keyfrom: "fanyi.web",
  28. action: e || "FY_BY_DEFAULT"
  29. 其中的加密函数
  30. var r = function(e) {
  31. var t = n.md5(navigator.appVersion), navigator.appVersion:浏览器的版本号,是固定的,可以在浏览器的控制台查看
  32. r = "" + (new Date).getTime(), 这就是一个字符串类型的毫秒级时间戳
  33. i = r + parseInt(10 * Math.random(), 10);
  34. return {
  35. ts: r,
  36. bv: t,
  37. salt: i,
  38. sign: n.md5("fanyideskweb" + e + i + "Tbh5E8=q6U3EXe+&L[4c@")
  39. }
  40. };
  41. """
  42. if __name__ == "__main__":
  43. # 输入需要翻译的字符串
  44. text = input("输入需要翻译的字符串: ")
  45. # ---------------进行参数加密----------------
  46. # 浏览器的版本号
  47. browser_id = "5.0 (X11)"
  48. # 时间戳
  49. lts = str(int(time.time() * 1000))
  50. salt = lts + str(random.randint(0, 10))
  51. sign_str = "fanyideskweb" + text + salt + "Tbh5E8=q6U3EXe+&L[4c@"
  52. # 进行md5加密,得到加密的值
  53. sign = hashlib.md5(sign_str.encode('utf-8')).hexdigest()
  54. bv = hashlib.md5(browser_id.encode('utf-8')).hexdigest()
  55. # 翻译的一个表单数据
  56. form = {
  57. "i": text,
  58. "from": "AUTO",
  59. "to": "AUTO",
  60. "smartresult": "dict",
  61. "client": "fanyideskweb",
  62. "salt": salt,
  63. "sign": sign,
  64. "lts": lts,
  65. "bv": bv,
  66. "doctype": "json",
  67. "version": "2.1",
  68. "keyfrom": "fanyi.web",
  69. "action": "FY_BY_REALTlME"
  70. }
  71. response = requests.post(url, headers=headers, data=form).json()
  72. print(response['translateResult'][0][0]["tgt"])

如上代码,应该比较简单,注释都有写清楚,下面是运行结果:

  1. 运行一:
  2. 输入需要翻译的字符串: hello world
  3. 你好世界
  4. 运行二:
  5. 输入需要翻译的字符串: Practice makes perfect
  6. 熟能生巧

图形验证码登录V2EX网站案例

登录许多网站的时候,我们都需要填写一个验证码,这其实也是反爬虫手段中的一环。如何解决这一个问题,第一个思路,训练一个机器学习的模型,模型训练的足够好之后,我们就可以用这个模型来识别我们的验证码,从而完成登录。但是,很显然,这样的开销太大了,毕竟我们只是想完成一个登录,另一种办法就是使用第三方的“打码平台”进行识别。这里列举一个第三方的打码平台:斐斐打码
这里由于V2EX这个网站需要魔法上网才可以进入,这里就不给具体的代码了,只简单记录一下思路。

  1. 请求头:这里需要两个参数,一个user-agent,一个referer
  2. 请求表单:在浏览器中找到登录的POST请求中的表单数据,可以发现我们的输入,但是它的关键字是一串没有规律的字符。但查看网页源代码后,可以在源代码中对应的标签内看到这一串key值。
  3. 步骤:第一步要爬取网页源代码,获取key值;第二步:使用第三方打码平台识别验证码(下载验证码图片时需要带请求头cookie);第三步:发送登录的POST请求。

字体反爬

字体反爬:网页开发者自己创造一种字体,因为在字体中每个文字都有其代号,那么以后的网页不会直接显示这个文字的最终效果,而是显示它的代号。因此即使获取到了网页中的文本内容,也只是获取到了代号,而不是文字本身。
因为创建字体费时费力,如果创建的字体过多,也会影响网页的一个加载速度。一般为了反爬虫,仅会针对0~9以及少数汉字进行单独创建,其它的还是使用用户系统中自带的字体。

  • 字体反爬虫的解决办法:
    • 一般为了考虑网页的渲染性能,通常开发者会把字体编码成base64的方式,因此我们可以在网页中找到@font-face属性,然后获取里面的base64代码,再用Python解码后保存到本地
    • 如果没有使用base64,那么另一种方式是直接把字体文件放到服务器上,然后前端通过@font-face中的url函数进行加载。
    • 处理字体反爬中,要分析字体形状和真实字符之间的映射关系,很多时候,网站中对字体的编码方式是不断变化的,因此每次我们需要找到当时请求时编码与字体形状的对应关系,再通过对应关系来映射到真正的字符。更难的字体反爬中,可能每次的字体形状也会是不一样的,可能在坐标上会有轻微的调整,爬取这样的网站时就需要我们对字体中的一些坐标进行判断,如果变化在一定的范围内,那么就可以判定为同一个字符。

这一部分我暂时不知道我是否会有这样的需求,暂时不放例子,具体可以看一下实习僧这个网站。