学会爬取静态页面的数据后,下面当然是学习爬取动态页面的数据。
什么是动态页面呢?
有时候我们再用requests抓取页面的时候,得到的结果可能和在浏览器中看到的不一样:在浏览器中可以看到正常显示的页面数据,但在使用requests得到的结果中却没有。这是因为requests获取的都是原始的HTML文档,而浏览器中的页面则是经过JavaScript处理数据后生成的结果,这些数据的来源有多种,可能是通过Ajax加载的,可能是包含在HTML文档中的,也可能是经过JavaScript和特定算法计算后生成的。
本篇整理记录爬取其中通过JavaScript混淆加密来渲染的页面
案例网站 有道翻译:http://fanyi.youdao.com/
输入‘萌新’点击翻译后,右边的XHR栏中,出现一条类型为xhr的数据请求,点击查看后。
POST请求地址为:http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
再看一下请求带过去的参数是哪些?
OK!!!其中 i 这个参数就是我们需要翻译的内容。那么直接复制请求头以及所需参数来构建requests请求。
构建requests请求
headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9",
"Cookie": "[email protected]; JSESSIONID="
"aaaBxpJhsD9bZgfYbsJax; OUTFOX_SEARCH_USER_ID_NCOO=2138649720.2208343;"
" ___rl__test__cookies=1581141334922",
"Referer": "http://fanyi.youdao.com/",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}
url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
form_data = {
"i": '萌新',
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"salt": '15811630953552',
"sign": '95f6b7ff43ba04c257097dabd115645e',
"ts": '1581163095355',
"bv": 'd6c3cd962e29b66abe48fcb8f4dd7f7d',
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_CLICKBUTTION"
}
response = requests.post(url=url, headers=headers, data=form_data)
print(response.text)
运行后结果:
程序返回了一个错误码!
当我们尝试翻译不同的内容后,我们发现参数 salt 、sign、ts、bv是会变化的。那么就该思考变化的参数是怎么来的呢?
发现js文件
此时发现这个数据请求它指向 fanyi.min.js:1 这个js文件,我们点击这个js文件
出现这个界面,一堆的JavaScript代码,看也看不懂,我们点击左下角的{}让它展开。
使用chrome的打断点功能
在方框处添加之前数据请求的POST地址:http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
然后,重新点击翻译按钮,断点成功屏幕会变为一半为灰色。 发现,行号重新定位在了7570行,展开右边 Call Stack,点击其中的
t.translate发现有我们需要的参数。
继续深入
将鼠标放入generateSaltSign上面,出现了如图所示的链接,点击跳转至8363行。
此时我们就找到了需要的参数salt、sign、ts、bv的源头。
将鼠标点击8363行,出现蓝色的标记即为打上一个断点。然后点击上方图中所示按钮。再点击一下翻译按钮。
通过上面的操作,我们找出了4个参数的源头,正是通过上图中的JavaScript代码来计算出来的。下面就用python来构造这4个参数
def get_ts():
ts = str(time.time() * 1000)
return ts
def get_bv():
appVersion = "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
m = hashlib.md5()
m.update(appVersion.encode("utf-8"))
bv = m.hexdigest()
return bv
def get_salt():
salt = str(time.time() * 1000) + str(random.random() * 10)
return salt
def get_sign(myinput):
a = "fanyideskweb"
b = myinput
c = get_salt()
d = "n%A-rKaT5fb[Gy?;N5@Tj"
str_data = a + b + c + d
m = hashlib.md5()
m.update(str_data.encode("utf-8"))
sign = m.hexdigest()
return sign
import requests
import time
import json
import hashlib
import random
def get_ts():
ts = str(time.time() * 1000)
return ts
def get_bv():
appVersion = "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
m = hashlib.md5()
m.update(appVersion.encode("utf-8"))
bv = m.hexdigest()
return bv
def get_salt():
salt = str(time.time() * 1000) + str(random.random() * 10)
return salt
def get_sign():
a = "fanyideskweb"
b = "萌新"
c = get_salt()
d = "n%A-rKaT5fb[Gy?;N5@Tj"
str_data = a + b + c + d
m = hashlib.md5()
m.update(str_data.encode("utf-8"))
sign = m.hexdigest()
return sign
def get_request():
headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9",
"Cookie": "[email protected]; JSESSIONID="
"aaaBxpJhsD9bZgfYbsJax; OUTFOX_SEARCH_USER_ID_NCOO=2138649720.2208343;"
" ___rl__test__cookies=1581141334922",
"Referer": "http://fanyi.youdao.com/",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}
url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule"
form_data = {
"i": '萌新',
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"salt": get_salt(),
"sign": get_sign(),
"ts": get_ts(),
"bv": get_bv(),
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_CLICKBUTTION"
}
response = requests.post(url=url, headers=headers, data=form_data)
print("翻译结果是:" + str(json.loads(response.text)['translateResult'][0][0]['tgt']))
if __name__ == '__main__':
get_request()
既然,我们能找到这些参数的规律,我们可以打包成 .exe 可执行文件做成翻译软件,分享给身边的小伙伴学习交流使用!!!
参考:Python中将.py文件打包成.exe可执行文件的简单方法