前言
首先我們需要了解一下 Python基本語法默垄、爬蟲庫,html的查詢惜犀,數(shù)據(jù)的處理與保存
Python:
- 基礎(chǔ)知識 語法與特性
requests:
- 使用Apache2 licensed 許可證的HTTP庫不从,代替了urllib
支持HTTP連接保持和連接池,支持使用cookie保持會話把曼,支持文件上傳,支持自動響應(yīng)內(nèi)容的編碼漓穿,支持國際化的URL和POST數(shù)據(jù)自動編碼祝迂。
Beautiful Soup:
- 提供一些簡單的、python式的函數(shù)用來處理導(dǎo)航器净、搜索、修改分析樹等功能当凡。
爬蟲與js逆向
百度翻譯
百度翻譯爬蟲山害,通過百度翻譯接口查詢
分析
- 打開百度翻譯
分析流程
- 將瀏覽器切換至手機端,這樣查看請求的參數(shù)可能會較少沿量,點擊下圖中的按鈕:
- 查看請求接口
- 查看請求參數(shù)是否有變化
- 圖一:
- 圖二:
經(jīng)過分析浪慌,我們發(fā)現(xiàn)這里有兩個參數(shù)發(fā)生變化,經(jīng)過推斷朴则,這里的參數(shù)可能是使用js生成的权纤,所以我們這里要對接口進行分析,破解,得到這里的值
分析結(jié)果
--分析目標--- | ----分析結(jié)果------------------- |
---|---|
請求URL分析 | https://fanyi.baidu.com/v2transapi |
請求方式分析 | POST |
請求參數(shù)分析 | 參看請求參數(shù)分析 |
請求頭分析 | 參看請求頭分析 |
請求參數(shù)分析
參數(shù)KEY | 分析結(jié)果 |
---|---|
query | 翻譯單詞(變化) |
from | en(固定值不變) |
to | zh(固定值不變) |
token | 900aa0a84929561d52bbee8c9222c0aa(經(jīng)過請求測試汹想,我們發(fā)現(xiàn)可以為固定值) |
sign | 54706.276099 |
JS 逆向流程
注意: 在js逆向中外邓,不是你要精通js才可以js逆向,你要懂一點js就可以做逆向古掏,重要的逆向思維损话,對問題的思考方式
chrome 調(diào)試技巧
- search 打開查詢面板
- 查詢面板可以通過關(guān)鍵字查找所有出現(xiàn)關(guān)鍵字地方的代碼
- 點擊跟蹤代碼并且可以把代碼格式化
- 對格式化的代碼進行設(shè)置斷點
- 鼠標光標移動到上面可以查看當前運行代碼變量值,函數(shù)原始代碼地方等等
JS 逆向流程
- 通過關(guān)鍵詞切入到代碼中槽唾,切入到發(fā)送請求的代碼行丧枪,通過請求的url中提取關(guān)鍵字
- 在發(fā)送請求的代碼添加斷點,并且觸發(fā)發(fā)送請求庞萍,確認尋找的代碼是否正確
- 往上逆向拧烦,尋找目標參數(shù)以及生成邏輯
- 利用js2py模擬執(zhí)行生成邏輯獲取想要的內(nèi)容
根據(jù)逆向流程查找我們所需的js代碼
- 搜索關(guān)鍵字
- 跟進代碼,分析AJAX請求
- 查找我們需要的值
- 準確的找到我們需要的值
- 復(fù)制我們需要的js代碼
- 代碼如下:
function e(r) {
var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
if (null === o) {
var t = r.length;
t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10))
} else {
for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)
"" !== e[C] && f.push.apply(f, a(e[C].split(""))),
C !== h - 1 && f.push(o[C]);
var g = f.length;
g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""))
}
var u = void 0
, l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);
u = null !== i ? i : (i = window[l] || "") || "";
for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {
var A = r.charCodeAt(v);
128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),
S[c++] = A >> 18 | 240,
S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,
S[c++] = A >> 6 & 63 | 128),
S[c++] = 63 & A | 128)
}
for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)
p += S[b],
p = n(p, F);
return p = n(p, D),
p ^= s,
0 > p && (p = (2147483647 & p) + 2147483648),
p %= 1e6,
p.toString() + "." + (p ^ m)
}
編寫爬蟲代碼
- 寫代碼之前钝计,我們需要先了解一下
js2py
這個模塊 - https://pypi.org/project/Js2Py/
# !/usr/bin/python3
# -*- coding: utf-8 -*-
import js2py
import requests
js_ctx = js2py.EvalJs()
# 0:英譯中 1:中譯英
t_mode = 0
class Translation(object):
def __init__(self, query):
# 初始化
self.url = "https://fanyi.baidu.com/v2transapi?from={0}&to={1}"
self.query = query
self.headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
"Referer": "https://fanyi.baidu.com/",
"Cookie": "BAIDUID=714BFAAF02DA927F583935C7A354949A:FG=1; BIDUPSID=714BFAAF02DA927F583935C7A354949A; PSTM=1553390486; delPer=0; PSINO=5; H_PS_PSSID=28742_1463_21125_18559_28723_28557_28697_28585_28640_28604_28626_22160; locale=zh; from_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; to_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; Hm_lvt_afd111fa62852d1f37001d1f980b6800=1553658863,1553766321,1553769980,1553770442; Hm_lpvt_afd111fa62852d1f37001d1f980b6800=1553770442; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1553766258,1553766321,1553769980,1553770442; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1553770442"
}
# js逆向獲取sign的值
def make_sign(self):
with open("translation.js", "r", encoding="utf-8") as f:
js_ctx.execute(f.read())
# 調(diào)用js中的函數(shù)生成sign
sign = js_ctx.e(self.query)
# 將sign加入到data中
return sign
def make_data(self, sign):
data = {
"query": self.query,
"token": "6f5c83b84d69ad3633abdf18abcb030d",
"sign": sign
}
return data
def get_content(self, data):
if t_mode == 0:
from_str = "en"
to_str = "zh"
else:
from_str = "zh"
to_str = "en"
response = requests.post(
url=self.url.format(from_str, to_str),
headers=self.headers,
data=data
)
return response.json()['trans_result']['data'][0]['dst']
def run(self):
# 獲取sign的值
sign = self.make_sign()
# 構(gòu)建參數(shù)
data = self.make_data(sign)
# 獲取翻譯內(nèi)容
content = self.get_content(data)
print(content)
if __name__ == '__main__':
t_mode = int(input("請輸入翻譯模式(0:英譯中 1:中譯英):"))
query = input("請輸入您要翻譯的內(nèi)容:")
translation = Translation(query)
translation.run()
注意
- 此時我們運行代碼會報錯誤恋博,會講我們?nèi)鄙?
r
的值
解決辦法:回到瀏覽器仁热,我們查找
r
的值,并將生成r
的值的函數(shù)榜聂,加入到我們之前創(chuàng)建的js
文件中啼器,放在G
函數(shù)的上面
- 生成r的代碼,如下所示
function n(r, o) {
for (var t = 0; t < o.length - 2; t += 3) {
var a = o.charAt(t + 2);
a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),
a = "+" === o.charAt(t + 1) ? r >>> a : r << a,
r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a
}
return r
}
- 我們重新運行代碼糙臼,發(fā)現(xiàn)又會遇到一個錯誤玷或,說是缺少
i
的值悄蕾,所以我們的解決辦法還是马昙,繼續(xù)進行js
逆向栓辜,查找i的值
- 逆向分析
- 我們回到
function a()
中永高,找到需要使用i
值的地方隧土,打上斷點
- 打上斷點之后刷新一下頁面,我們再次將鼠標放在
i
上,我們會看到一個浮點字符串命爬,此時我們不確定i
的值是否是變化的曹傀,所以我們換一個翻譯的單詞,刷新頁面饲宛,再次查看i
的值皆愉,我們發(fā)現(xiàn)i
的值是固定的,所以我們可以在代碼中艇抠,直接定義一個固定的i
值.
我們在自定義的 js 代碼最上面一行寫入:
var i = "320305.131321201"
最后
運行代碼幕庐,成功,完成了一次簡單的百度翻譯的 js 逆向嘗試家淤。
QQ音樂下載
qq音樂下載是怎樣的流程
分析流程
- 打開QQ音樂
url : https://y.qq.com/
- 將瀏覽器切換至手機端异剥,這樣查看請求的參數(shù)可能會較少,點擊下圖中的按鈕:
- 查看請求接口
- 通過單一歌曲的鏈接查看必須的傳遞參數(shù) song_mid 繼續(xù)搜尋可用鏈接:
根據(jù)逆向流程查找我們所需的js代碼
- 可查看必要參數(shù)sign值與data絮重,拼接data冤寿,查看參數(shù)sign的得出
- debug 調(diào)試 獲取到j(luò)s的方法與sign值的獲取js代碼
- getSecuritySign內(nèi)部主要處理數(shù)據(jù)的js 方法如上 復(fù)制至sign.js中保存使用
- 該鏈接獲取到的鏈接拼接為音樂的源