python3 爬虫遇到了反爬
当你兴冲冲的打开一个网页, 发现里面的资源好棒, 能批量下载就好了, 然后感谢写个爬虫 down 一下, 结果, 一顿操作之后, 发现网站竟然有反爬措施, 尴尬了.
接下来的几篇文章, 我们研究一下各种反爬虫套路, 当然互联网没有 100% 的反爬措施, 只要你能使用浏览器访问的网页, 都是可以爬取到了, 所有的人不能杜绝爬虫, 只能在一定程度上增加你爬取的成本, 说白了, 就是让你的技术爬不到~
爬虫和反爬虫一直都是这个领域程序员对抗的基础, 从最简单的 UA 限制, 到略微复杂一些的 IP 限制, 用户限制, 技术都是不断发展的, 但是, 不怕贼偷, 就怕贼惦记, 只要你的网站内容有价值, 放心, 一堆爬虫 coder 盯着呢?
emmmm....
搞定 JavaScript 加密
JS 加密最简单的是采用 md5 进行的, 我们通过 http://fanyi.youdao.com / 来演示本篇博客内容
接下来你要注意的是这个请求是由哪个 JS 文件发起的
文件获取到为 fanyi.min.JS, 继续追踪, 鼠标在这个文件名上面停留一下就可以获取到基本信息, 我们点击跟请求相关的那个方法对应的文件链接, 跳转到方法内部
这个地方有个操作细节, 你需要学会, 点击文件之后, 跳转到的 JS 文件是压缩之后的, 进行一下格式化操作
拿到源码
- t.translate = function(e, t) {
- _ = f("#language").val();
- var n = x.val()
- , r = g.generateSaltSign(n)
- , i = n.length;
- if (F(),
- T.text(i),
- i> 5e3) {
- var a = n;
- n = a.substr(0, 5e3),
- r = g.generateSaltSign(n);
- var s = a.substr(5e3);
- s = (s = s.trim()).substr(0, 3),
- f("#inputTargetError").text("有道翻译字数限制为 5000 字,"" + s + ""及其后面没有被翻译!").show(),
- T.addClass("fonts__overed")
- } else
- T.removeClass("fonts__overed"),
- f("#inputTargetError").hide();
- d.isweb(n) ? o() : l({
- i: n,
- from: C,
- to: S,
- smartresult: "dict",
- client: k,
- salt: r.salt,
- sign: r.sign,
- ts: r.ts,
- bv: r.bv,
- doctype: "json",
- version: "2.1",
- keyfrom: "fanyi.web",
- action: e || "FY_BY_DEFAULT",
- typoResult: !1
- }, t)
- }
参数分析
i 表示 带翻译的词语
from 设置为 AUTO
to 设置为 AUTO
smartresult 默认值 dict
client 翻译的客户端: 默认应该为 fanyideskweb
salt 第一个变量 需要查阅生成规则
sign 第二个变量 需要查阅生成规则
ts
bv
其余的参数保持默认即可
重点参数
salt
sign
ts
bv
代码的复查当中找到参数来源
- var r = function(e) {
- var t = n.md5(navigator.appVersion)
- , r = "" + (new Date).getTime()
- , i = r + parseInt(10 * Math.random(), 10);
- return {
- ts: r,
- bv: t,
- salt: i,
- sign: n.md5("fanyideskweb" + e + i + "1L5ja}w$puC.v_Kz3@yYn")
- }
OK, 我们已经获取到参数的内容了
ts = r 表示当前的时间戳
salt 用 r 去加上一个随机数
sign 为 一个特殊的 md5, 中间重点注意 e 其实就是你要翻译的词语
navigator.appVersion 这个比较容易, 在开发者工具中运行一下就可以得到了
5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/68.0.3440.106 Safari/537.36
代码尝试
准备好这么多材料之后, 剩下的就是编码了, 我们开始吧, 这个地方依据的是 JS 的源码, 然后转换成 Python 即可, 没有特别难的地方
参数的生成
- def generate_salt_sign(translate):
- # var t = n.md5(navigator.appVersion)
- app_version = "5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"
- bv = hashlib.md5(app_version.encode(encoding='UTF-8')).hexdigest()
- # r = "" + (new Date).getTime()
- ts = str(int(round(time.time(),3)*1000))
- # i = r + parseInt(10 * Math.random(), 10);
- salt = ts + str(random.randint(1,10))
- # sign: n.md5("fanyideskweb" + e + i + "1L5ja}w$puC.v_Kz3@yYn")
- sign = hashlib.md5(("fanyideskweb"+translate+salt+"1L5ja}w$puC.v_Kz3@yYn").encode(encoding='utf-8')).hexdigest()
- return salt,sign,ts,bv
参数的拼接与 header 的准备
- def params():
- data = {}
- translate = 'morning'
- client = 'fanyideskweb'
- data['i'] = translate
- data['from'] = 'AUTO'
- data['to'] = 'AUTO'
- data['smartresult'] = 'dict'
- data['client'] = client
- data['salt'],data['sign'],data['ts'],data['bv'] = generate_salt_sign(translate)
- data['doctype'] = 'json'
- data['version'] = '2.1'
- data['keyfrom'] = 'fanyi.web'
- data['action'] = 'FY_BY_REALTIME'
- data['typoResult'] = 'false'
- return data
发起请求
- def tran():
- data = params()
- headers = {}
- headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"
- headers["Referer"] = "http://fanyi.youdao.com/"
- headers["Cookie"] = "OUTFOX_SEARCH_USER_ID=-1868577286@222.222.147.75;"
- with requests.post("http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule",headers=headers,data=data) as res:
- print(res.text)
- if __name__ == '__main__':
- tran()
结果展示
{"translateResult":[[{"tgt":"早....","src":"morning"}]],"errorCode":0,"type":"en2zh-CHS","smartResult":{"entries":["","n. 早晨; 黎明; 初期 \ r\n"],"type":1}}
得到数据之后就表示我们的目标完成了~
本篇博客的反爬内容搞定~
关注微信公众账号, 回复 0401 获取源码
来源: https://www.cnblogs.com/happymeng/p/10749850.html