请求分析
参数构造流程
这种提交数据得到响应的的请求,往往参数比较麻烦,所以参数的构造是得到完整请求的关键.
首先我们要明确目标,爬取这个网站的目的是什么,那我们的目的就是模拟浏览器发送请求,完成翻译的功能,明确了目标之后我们再定位到相关的URL就比较容易了。
现在先打开chrome的调试工具,然后输入需要翻译的内容,比如我们输入一个需要翻译的词,中国,如果觉得无关的请求太多了可以把当前的页面请求清空,重新点击翻译发送翻译相关的请求,然后再请求过滤器中选择XHR,这样请求就非常清晰了。通过请求的名字可以猜到,图中标注的请求就是我们需要的URL
以定位到URL为前提
- 先作对比,找出不同的参数
- 从之前的请求响应中找数据
(1)网页源代码中查找
(2)全局请求搜索 - JS加载调试,查找生成规律
参数来源(重要)
不变的参数写固定值,变动的参数的来源在JS中寻找,即JS生成一个动态请求的参数来源只可能有两个:
一是来自之前的请求响应,二是JS生成
参数对比来源
现在我们找到了相关的URL,也就是说给这个URL发送请求,那它返回的结果中就应该有翻译的结果。但是肯定需要通过请求告诉服务器需要翻译的词是什么,那么接下来就一起看一看发送请求需要携带什么参数。(翻译两个词,如你好和世界,将表单数据复制下来查看区别)
现在我们来看一下这两次的请求表单的数据有什么区别,主要的区别有两个字段,分别是query,sign,还有一个token是看起来就比较重要的参数,query很显然是我们自己输入的数据,那么这个sign就是需要找到的参数(后面token是固定的,也是可以从访问https://fanyi.baidu.com得到的静态页面中获取),所以我们的重点任务就是找到这个sign的生成方式
query
是自己输入的数据
sign是动态加载的
token 可以从访问https://fanyi.baidu.com得到的静态页面中获取
获取token值
首先获取token值,这个值的获取比较容易,是静态页面中写好的,复制之前请求中的token值然后直接在界面中搜索可以看到这边token的定义位置,然后通过正则匹配出来就可以了,很简单,应该都能看得懂吧,这里就不多讲了。
获取sign值
token找到了,接下来就需要找到sign值了,这个值因为是JS动态生成的,在页面上无法直接找到,所以要进行分析然后找到相关的Js代码。接下来我们一起看一下这个值是怎么生成的。
调试细节
- 搜索定位生成sign的js文件
- 依此判断sign生成的文件(第二个)
- 调整显示格式
- 搜索定位
- 通过断点调试,确定生成函数
底层函数
找到生成sign的函数
进入生成sign的函数
PyExecJs执行js代码
找到对应的JS代码后把完整的函数作为一个新的文件粘贴出来,JS代码如果比较长可能不太好找到完整的函数,这里可以把光标放在在定义函数的位置后面的大括号,代码提示会告诉我们函数结束的大括号在什么位置,这样就找到了完整的函数定义。之后用PyExecJs直接执行JS代码,如果想了解sign的具体实现方式可以自己分析一下JS代码,在chrome调试工具中的Console可以执行具体的JS代码帮助理解,这里就不展开了。
通过扣代码,生成sign的js完整代码
缺啥补啥
function n(t, e) {
for (var n = 0; n >> r : t 30 && (t = "".concat(t.substr(0, 10)).concat(t.substr(Math.floor(a / 2) - 5, 10)).concat(t.substr(-10, 10)))
} else {
for (var s = t.split(/[uD800-uDBFF][uDC00-uDFFF]/), c = 0, u = s.length, l = []; c 30 && (t = l.slice(0, 10).join("") + l.slice(Math.floor(p / 2) - 5, Math.floor(p / 2) + 5).join("") + l.slice(-10).join(""))
}
for (var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107)), h = (null !== r ? r : (r = window[d] || "") || "").split("."), f = Number(h[0]) || 0, m = Number(h[1]) || 0, g = [], y = 0, v = 0; v > 6 | 192 : (55296 == (64512 & _) && v + 1 > 18 | 240,
g[y++] = _ >> 12 & 63 | 128) : g[y++] = _ >> 12 | 224,
g[y++] = _ >> 6 & 63 | 128),
g[y++] = 63 & _ | 128)
}
for (var b = f, w = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(97)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(54)), k = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(51)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(98)) + "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(102)), x = 0; x
现在用Python执行JS代码,因为我们知道这个函数传入的参数是用户输入的需要翻译的数据,所以就可以开始进行调试,当然会预见到会有很多的报错,不过没关系,这个是很正常的,只需要一个个把每个报错解决了可以了,因为这个sign值是和传入的参数相关的,也就是说传入相同的值也就会得到相同的结果,最后得到一个sign值就算是可以成功执行了,然后验证一下是不是相等的。下面我们就来实际执行一下JS代码,看看可能会遇到哪些问题。
可能遇到的错误
- 遇到的错误1
- 报错
- 解决方法 js代码中添加以下代码
- 遇到的错误2
- 报错
- 检查
- 解决方法 找到window 的值,替换成固定的值,或从之前的请求中得到的值
- 遇到的错误3
- 错误
- 解决方法 js代码中添加以下代码
js代码中添加
代码实现
注意:
- token需要获取多次,才能保持稳定不变
- PyexecJs执行 生成sign的js代码 是重点
import requests
import execjs
headers = {
"Acs-Token": "1691117035328_1691117298117_Qj699LVqZC95JeEX00HjPduCJL9ievc30rAXXAIB/7U/sio35d2hrtaU/U7Xca+Gee/HAB3Fi/XnJaL4iv2UkhmsQOg/6zsq/y6S/xNVyPjaiqhBcC12DzPl78mGD2P+rx51KdCIIUYPcR3NmLwUQswg3Yuy74H5w4W3CKmvlbHaq1yoVl2+XLuVlve4SkwOv6v2FIoRHKqJoJkNTaioJ68VCYM4Spk/jLyM2N16EQPJqZjJwB8KZe445KjSZPyW+xsWtRTYosF2Yl2YFQrCzRin5CL40/CZ2S2sKSey9MTMeMrOoslGS9rvReCBBM1LXmC8ydKi/IRnngc9bxNA9Cdo4Qfz5L8WQRsbiTHxJSTccbjrRFLGJWGu1JxtDFeYaZisr5DaADfKd5/yJOYlrhNbWkD4sXudn18KmvhCV0+P/OfKHK8puymqtFLjentixUUU8HnUD0Mxxzw6craJHbMousKgB+eQXH16AT1Dx38CGEGZs5WLpsXu3fQuXbgs",
"Origin": "https://fanyi.baidu.com",
"Referer": "https://fanyi.baidu.com/translate?aldtype=16047&query=&keyfrom=baidu&smartresult=dict&lang=auto2zh",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
"X-Requested-With": "XMLHttpRequest",
}
cookies = {
"BIDUPSID": "B89F81B5FCFF061501540DD7DA73CB7B",
"PSTM": "1687681080",
"BAIDUID": "B89F81B5FCFF0615D1361CAB2C48046B:FG=1",
"REALTIME_TRANS_SWITCH": "1",
"FANYI_WORD_SWITCH": "1",
"HISTORY_SWITCH": "1",
"SOUND_SPD_SWITCH": "1",
"SOUND_PREFER_SWITCH": "1",
"BDUSS": "NsMkc2TmdIdXBJLXhhd1FZaWI5fml6ZlR6ZFFoSWdwSldHTllTQ0lPRXVQOEZrRVFBQUFBJCQAAAAAAAAAAAEAAAC~KxxlaUdlZWvKqNfTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC6ymWQusplkWF",
"BDUSS_BFESS": "NsMkc2TmdIdXBJLXhhd1FZaWI5fml6ZlR6ZFFoSWdwSldHTllTQ0lPRXVQOEZrRVFBQUFBJCQAAAAAAAAAAAEAAAC~KxxlaUdlZWvKqNfTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC6ymWQusplkWF",
"H_WISE_SIDS": "234020_216843_213355_214800_110085_243888_244713_254835_256739_257289_257586_253022_262381_236312_261869_259306_263190_256419_264205_256998_256222_261934_265008_262665_265029_265035_265055_265133_261036_265467_265647_259734_265851_264642_261929_265881_265312_265996_266091_266099_257015_265289_265276_259732_234296_234207_265801_266367_266690_266828_264768_266758_266743_267067_265886_257442_265367_267256_266159_266457_266566_261646_253528_267344_267302_267372_267373_267427_265615_267413_267538_267559_265906_266873_256153_266188_267789_267712_267899_267910_267926_267072_267459_197096_267977_265776_266420_265999_266113_266714_267703_107311_268416_260335_268319_268487_268506_267031_266453_266服务器托管网804_268638_268593_263618",
"BDORZ": "B490B5EBF6F3CD402E515D22BCDA1598",
"BA_HECTOR": "a5252g040l2000al00a5a00d1icol3s1o",
"BAIDUID_BFESS": "B89F81B5FCFF0615D1361CAB2C48046B:FG=1",
"ZFY": "aky7vfoVJKqEHtJdWkOiK90KKkWF:AM7ZaXaqdyssWPA:C",
"BDRCVFR[feWj1Vr5u3D]": "I67x6TjHwwYf0",
"delPer": "0",
"PSINO": "1",
"H_PS_PSSID": "36554_39107_38831_39147_39114_39121_39038_38917_26350_39101_39043",
"BCLID": "11089121968086782353",
"BCLID_BFESS": "11089121968086782353",
"BDSFRCVID": "rrFOJexroG0ZmSbfzMz9e7MNxFweG7bTDYrEOwXPsp3LGJLVFakFEG0Pts1-dEu-S2OOogKKBeOTHn0F_2uxOjjg8UtVJeC6EG0Ptf8g0M5",
"BDSFRCVID_BFESS": "rrFOJexroG0ZmSbfzMz9e7MNxFweG7bTDYrEOwXPsp3LGJLVFakFEG0Pts1-dEu-S2OOogKKBeOTHn0F_2uxOjjg8UtVJeC6EG0Ptf8g0M5",
"H_BDCLCKID_SF": "tRAOoC_-tDvDqTrP-trf5DCShUFsbJjlB2Q-XPoO3KJADfOPbR6Y26F8jPcwhU5f5mkf3fbgy4op8P3y0bb2DUA1y4vp0toW3eTxoUJ2-KDVeh5Gqq-KXU4ebPRi3tQ9QgbXopQ7tt5W8ncFbT7l5hKpbt-q0x-jLTnhVn0MBCK0HPonHjtBD5JP",
"H_BDCLCKID_SF_BFESS": "tRAOoC_-tDvDqTrP-trf5DCShUFsbJjlB2Q-XPoO3KJADfOPbR6Y26F8jPcwhU5f5mkf3fbgy4op8P3y0bb2DUA1y4vp0toW3eTxoUJ2-KDVeh5Gqq-KXU4ebPRi3tQ9QgbXopQ7tt5W8ncFbT7l5hKpbt-q0x-jLTnhVn0MBCK0HPonHjtBD5JP",
"Hm_lvt_64ecd82404c51e03dc91cb9e8c025574": "1688981097,1691117035",
"Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574": "1691117035",
"ab_sr": "1.0.1_ZWQ0MDkxOWMxYThkY2JiODU0NTQ4YjM1MWMwYmRkNjllZTVlMTI3ZTNkMTg3YTU1NzM0N2E5NDlmOGMyNjQzYzA0ZjI5NjczMDkwODdmNmJiOWY4MzA4MmYyNTBiZmQxOTM3NTIwZTI2ZmMzMzI0ZDM3ZjAwNGZkZjNlZTkyMmQxYTVhYzIxMWNmMTdhOGFlMTBjZmNjZmZhNGE3OGEzMTU0MTUxMGQ3NzNkNmVjZTdlMzhkNGU2ZGY5NGFjMDA3"
}
url = "https://fanyi.baidu.com/v2transapi"
params = {
"from": "zh",
"to": "en"
}
with open('../js_code/baidu.js','r',encoding='utf-8') as f:
js_code = f.read()
word = input('请输入翻译的内容:')
# 编译
js_compile = execjs.compile(js_code)
# 执行
sign = js_compile.call('baidu',word)
print(sign)
data = {
"from": "zh",
"to": "en",
"query": word,
"transtype": "translang",
"simple_means_flag": "3",
"sign": sign,
"token": "bbff56519eb02b010184234a47ded1ed",
"domain": "common",
"ts": "1691117298106"
}
resp服务器托管网onse = requests.post(url, headers=headers, cookies=cookies, params=params, data=data)
print(response.content.decode())
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net