关于有道词典数据爬取的进一步说明

之前Info函数的封装中使用了一个POST的爬取过程得到了英文翻译的结果,这里针对POST的过程做进一步的分析和讲解,供大家进一步了解POST在企业实战中的使用和爬虫破解的细节。

        大家对于一个那个诡异的URL链接 "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=null" 可能不知从何而来,而如果直接使用POST数据包中的链接"http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule", 发现并不能得到正确的结果,原因不具体分析了。

从POST的数据包中,我们可以看到:

    # 把form数据转规范化,然后post给服务端
    formdata = {
    "i":key,
    "from":"AUTO",
    "to":"AUTO",
    "smartresult":"dict",
    "client":"fanyideskweb",
    "salt":"1523933959290",
    "sign":"248f5d216c45a64c38a3dccac0f4600d",
    "doctype":"json",
    "version":"2.1",
    "keyfrom":"fanyi.web",
    "action":"FY_BY_REALTIME",
    "typoResult":"false"
    }

这里的salt和sign明显是数字加密技术的点(salt是加密中的加盐操作,sign是一个身份验证),所以这个网站之后没法正常抓取,关键就是这里的salt和sign被加密了。

我原来就讲过,其实爬虫本质上是一种黑客技术,这里毫无疑问,有道采用了一些加密的处理。而根据我们之前的原理分析可知,这个加密的逻辑事实上肯定隐藏在客户端的浏览器中了。

         那我们这里就模拟JS的过程来分析一下(这个过程比较自然,大部分人都能掌握),当然这需要一些前端的HTML和JavaScript的知识作为准备。

我们来看一下有道翻译的主页:http://fanyi.youdao.com/

打开主页,查看源码,通过搜索,我们可以看到:

这里有3个js的脚本,我们稍加分析,可以知道核心的代码隐藏在fanyi.min.js这个js文件中。

具体代码如下:

        var r = function(e) {
            var t = "" + ((new Date).getTime() + parseInt(10 * Math.random(), 10));
            return {
                salt: t,
                sign: n.md5("fanyideskweb" + e + t + "6x(ZHw]mwzX#u0V7@yfwK")

            }
        };

当然,我们需要一定的JS知识来阅读这个代码,很容易读懂这段代码,这个salt,有当前时间戳,一个random随机值的和产生;

而这个sign则是一段信息的md5值。

这里忽略细节,我们给出Python对此的模拟过程:

def getSalt(): # 得到加盐信息
    return str(int(time.time()*1000)+random.randint(0,11))

def getSign(key,salt):# 得到sign信息
    sign = ("fanyideskweb" + key + salt + "6x(ZHw]mwzX#u0V7@yfwK")
    hashObj = hashlib.md5()
    hashObj.update(sign.encode("utf-8"))
    return hashObj.hexdigest()

有了这两个破解的关键点,我们就可以使用正常的抓包模拟POST的过程来完成有道翻译的过程(这个翻译对中英文都支持)

,从而来完成一个在线词典的功能:

# -*- coding: utf-8 -*-
"""
Created on Tue Apr 17 11:01:28 2018

@author: Administrator
"""
import urllib
import json

import time
import random
import hashlib

def getSalt():
    return str(int(time.time()*1000)+random.randint(0,11))

def getSign(key,salt):
    #print(key)
    #print(salt)
    sign = ("fanyideskweb" + key + salt + "6x(ZHw]mwzX#u0V7@yfwK")
    hashObj = hashlib.md5()
    hashObj.update(sign.encode("utf-8"))
    return hashObj.hexdigest()
# 设置一个退出程序的出口
isOut = False

# 不断调用爬取翻译页面的功能
#直到isOut被设置为True,退出程序
while True:
    if isOut == True:
        break
    
    #假定用户输入“CloseMe”,则退出
    key = input("请输入需要翻译的文字,\
                输入CloseMe表示退出:\n")
    if key == "CloseMe":
        isOut = True
        continue #回到循环开始处,然后结果条件满足退出
    
    # 做真正的查询操作
    url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
       
    # http://tool.chinaz.com/js.aspx
    # 把form数据转规范化,然后post给服务端
    saltInfo = getSalt()
    formdata = {
    "i":key,
    "from":"AUTO",
    "to":"AUTO",
    "smartresult":"dict",
    "client":"fanyideskweb",
    "salt":saltInfo,
    "sign":getSign(key,saltInfo),
    "doctype":"json",
    "version":"2.1",
    "keyfrom":"fanyi.web",
    "action":"FY_BY_REALTIME",
    "typoResult":"false"
    }

    data = urllib.parse.urlencode(formdata).encode()
    # 给服务器发送post请求
    
        # 构造headers
    headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
               "X-Requested-With": "XMLHttpRequest",
               "Accept-Language":"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
               "Content-Length":len(data),
               "Cookie":"YOUDAO_MOBILE_ACCESS_TYPE=1; OUTFOX_SEARCH_USER_ID=1547024714@106.38.155.125; OUTFOX_SEARCH_USER_ID_NCOO=305129980.33",
               "Connection":"keep-alive",
               "Accept":"application/json, text/javascript, */*; q=0.01",
               "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
               "Host":"fanyi.youdao.com",
               "Referer":"http://fanyi.youdao.com/"
            }
    req = urllib.request.Request(url,
                                 data,
                                 headers,
                                 method="POST")

    response = urllib.request.urlopen(req)
    info = response.read().decode("utf-8")


    # json decode: json str --> dict
    jsonLoads = json.loads(info)
    print(jsonLoads['translateResult'][0][0]["src"])
    print(jsonLoads['translateResult'][0][0]["tgt"])

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值