爬虫解决加密问题

1,158 阅读8分钟

一、hash算法

note.youdao.com/noteshare?i…

二、解决js加密问题

js加密目标:参数加密

通过分析js或者ajax接口,分析目标就是接口的参数 参数一般从哪里取找:

  • 有可能出现之前分类类别信息中。---在页面信息中

    比如:豆瓣电影案例

  • 有可能之前发送一些ajax请求,在这些请求的结果中找到参数,进行下次的ajax请求发送

    比如:参照高德地图案例

  • 通过js加密,进行参数伪装。--js加密不一定能解决

    加密的时候一般hash算法。---16摘要

    16进制数:

    ​ 0-9 和a-f

    js加密想要解决是很难的,如果解决不了就使用selenium获取

分析js加密的步骤:

​ 1、定位哪些参数是加密的

​ 定位的而过程也就是对比找不一样的参数的过程。哪些参数不一样就是分析对象。

salt: 15947184706411
sign: eb23b60951c66d5ded8a0bd83c6c24cb
ts: 1594718470641

如果出现eb23b60951c66d5ded8a0bd83c6c24cb---(16进制数的特征)

​ 2、通过上述分析的标准过滤排除,发现只有可能在js文件中,此时可以定位js加密

3、进行js加密的分析:

​ 步骤1:在哪些js文件中是否有出现这个写参数的名字

​ 搜索,提前:加载出js来。(要重新加载一些页面,将js加载到发开这工具内存中)

步骤2:进入文件在进行查找

格式化代码的功能

案例:(1)、案例:js解密
import hashlib
import random
import time

import requests


def translate(word):
    base_url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
    headers = {
        'Origin': 'http://fanyi.youdao.com',
        'Referer': 'http://fanyi.youdao.com/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
        'X-Requested-With': 'XMLHttpRequest',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Cookie': 'OUTFOX_SEARCH_USER_ID=1900023740@10.108.160.18; OUTFOX_SEARCH_USER_ID_NCOO=1880372795.73266; JSESSIONID=aaan4xJWxbJPbgdOOiqnx; ___rl__test__cookies=1594777517602',
    }
    ts = str(int(time.time() * 1000))
    salt = ts + str(random.randint(0, 10))
    sign = hashlib.md5(bytes("fanyideskweb" + word + salt + "mmbP%A-r6U3Nw(n]BjuEU", encoding='utf-8')).hexdigest()
    data = {
        'i': word,
        'from': 'AUTO',
        'to': 'AUTO',
        'smartresult': 'dict',
        'client': 'fanyideskweb',
        'salt': salt,
        'sign': sign,
        'ts': ts,
        'bv': 'd6ea15a844a294021d16ba0a44b1d2a1',
        'doctype': 'json',
        'version': '2.1',
        'keyfrom': 'fanyi.web',
        'action': 'FY_BY_REALTlME',
    }
    response = requests.post(base_url, headers=headers, data=data)
    # print(response.json())
    result = ''
    for data in response.json()['smartResult']['entries']:
        result += data
    return result


if __name__ == '__main__':
    word = input('请输入单词:')
    result = translate(word)
    print(result)

三、css解密

css加密---页面的样式相关的

1、定位问题:什么情况是css加密?

​ 只要和显示相关的问题都是css加密范畴

2、解决办法

​ 首先获取数据里面就是

但是显示到页面中,就是正确内容:

结论:对照的信息应该在css文件中,而且和@font-face相关

字体加密文件就是woff字体文件 解决css加密的方法:

1、找到css中woff文件。

2、通过这些woff文件,获取里面f516:1

3、生成字典:

​ data = {

​ 'f516':1,

​ }

4、for k,v in data.items():

​ 替换response.text中&#xf4f8

(1)、案例:css解密
import requests, os, re
from lxml import etree
from fontTools.ttLib import TTFont


def dowload_woff(text):
    '''
    下载woff文件
    之所以写到这个方法中:没必要每条请求都进行下载。
    :param text:
    :return:
    '''
    # 1、先取找到页面中css连接
    css_url = re.search(r'href="(//s3plus.*?\.css)">', text).group(1)
    # print(css_url)
    # 2、请求连接,从响应中获取字体文件的url
    css_content = requests.get('http:' + css_url).text
    # print(css_content)
    # 3、下载字体文件
    woff_urls = re.findall(r',url\("(//s3plus.*?\.woff)"\);\}', css_content, re.S)
    # print(woff_urls)
    filenames = []
    for url in woff_urls:
        filename = re.split('/', url)[-1]
        print(filename)
        content = requests.get('http:' + url).content
        with open(f'./css_woff/{filename}', 'wb') as fp:
            fp.write(content)
        if filename not in filenames:
            filenames.append(filename)
    return filenames


def css_decode(text):
    '''
    对页面内容进行css解密
    :param text:
    :return: 正确的页面内容
    '''
    # 字体文件的存放目录、
    css_dir = './css_woff/'
    # 判断css_woff有没有字体文件。
    # listdir:获取一个文件夹中的所有文件名
    filenames = os.listdir(css_dir)
    # print(result)
    if not filenames:
        # 1、下载woof文件
        filenames = dowload_woff(text)
    # 4、读取字体文件,生成data字典。
    data = {}
    for filename in filenames:
        font = TTFont(css_dir + filename)
        keys = font.getGlyphOrder()[2:]
        # print(filename,keys)
        character = list(
            '1234567890店中美家馆小车大市公酒行国品发电金心业商司超生装园场食有新限天面工'
            '服海华水房饰城乐汽香部利子老艺花专东肉菜学福饭人百餐茶务通味所山区门药银农龙停尚安'
            '广鑫一容动南具源兴鲜记时机烤文康信果阳理锅宝达地儿衣特产西批坊州牛佳化五米修爱北养'
            '卖建材三会鸡室红站德王光名丽油院堂烧江社合星货型村自科快便日民营和活童明器烟育宾精'
            '屋经居庄石顺林尔县手厅销用好客火雅盛体旅之鞋辣作粉包楼校鱼平彩上吧保永万物教吃设医'
            '正造丰健点汤网庆技斯洗料配汇木缘加麻联卫川泰色世方寓风幼羊烫来高厂兰阿贝皮全女拉成'
            '云维贸道术运都口博河瑞宏京际路祥青镇厨培力惠连马鸿钢训影甲助窗布富牌头四多妆吉苑沙'
            '恒隆春干饼氏里二管诚制售嘉长轩杂副清计黄讯太鸭号街交与叉附近层旁对巷栋环省桥湖段乡'
            '厦府铺内侧元购前幢滨处向座下県凤港开关景泉塘放昌线湾政步宁解白田町溪十八古双胜本'
            '单同九迎第台玉锦底后七斜期武岭松角纪朝峰六振珠局岗洲横边济井办汉代临弄团外塔杨铁浦'
            '字年岛陵原梅进荣友虹央桂沿事津凯莲丁秀柳集紫旗张谷的是不了很还个也这我就在以可到错'
            '没去过感次要比觉看得说常真们但最喜哈么别位能较境非为欢然他挺着价那意种想出员两推做'
            '排实分间甜度起满给热完格荐喝等其再几只现朋候样直而买于般豆量选奶打每评少算又因情找'
            '些份置适什蛋师气你姐棒试总定啊足级整带虾如态且尝主话强当更板知己无酸让入啦式笑赞'
            '片酱差像提队走嫩才刚午接重串回晚微周值费性桌拍跟块调糕')
        # print(len(keys),len(character))
        keys = [x[3:] for x in keys]
        # print(keys)
        for i, k in enumerate(keys):
            if k not in data:
                data[k] = character[i]

    # 5、利用data字典,进行内容替换
    for k, v in data.items():
        text = text.replace(f'&#x{k};', v)
    return text


def get_xpath(url):
    '''
    请求url,返回响应element对象
    :param url:
    :return:
    '''
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
        'Cookie': 's_ViewType=10; _lxsdk_cuid=173504e2df3c8-054b7b278012f3-3e3e5e0e-100200-173504e2df349; _lxsdk=173504e2df3c8-054b7b278012f3-3e3e5e0e-100200-173504e2df349; _hc.v=55973ab1-034c-99d9-05a8-cf2b71be7302.1594780168; _lxsdk_s=173504e2df6-e74-e34-e3a%7C%7C19; Hm_lvt_602b80cf8079ae6591966cc70a3940e7=1594780169; Hm_lpvt_602b80cf8079ae6591966cc70a3940e7=1594780169',

    }
    response = requests.get(url, headers=headers)
    page_content = css_decode(response.text)
    print(page_content)
    # 测试
    # print(response.text)
    # return etree.HTML(page_content)


def main():
    base_url = 'http://www.dianping.com/search/keyword/155/0_%E5%92%8C%E8%B0%90%E5%B9%BF%E5%9C%BA'
    tree = get_xpath(base_url)
    # li_list = tree.xpath('//*[@id="shop-all-list"]/ul/li')
    # # print(li_list)
    # for li in li_list:
    #     title = li.xpath('.//div[@class="tit"]/a/h4/text()')[0]
    #     print(title)


if __name__ == '__main__':
    main()

四、base64编码

原理: base64 编码的原理是先将源文件以标准字节(byte)为单位转化成二进制,一个字节占8 个位(bit),如“ABC”的二进制是01000001、01000010、01000011,这样源文件就形成了 每 8 个 bit一组的一串二进制,然后将这些二进制串以base64特有的规则(每个字节占 6 个位)再转化成base64格式的字符(如下图),编码完成,解码就是这个过程反过来

bas64编码类型(特点),可以通过这些特点取识别出是否是base64编码

特点1:A-Z a-z 0-9 +/

​ ascii码对于base64编码转化的时候,结尾字符无法对应的时候会用=进行不起

特点2:结尾有很多= Base32:5位为一个字节进行拆分

而Base32中只有大写字母(A-Z)和数字234567

Base16:4为一个字节

而Base16就是16进制,他的范围是数字(0-9),字母(ABCDEF)

(1)、案例:base64加密
import requests, re
from lxml import etree
from io import BytesIO
from fontTools.ttLib import TTFont
import base64


def base64_deocde(content):
    '''
    对页面内容进行css解密
    :param content:
    :return:
    '''
    # 1获取字体文件内容
    font_base64_str = re.search(r'base64,(.*?)\) format', content).group(1)
    # print(font_base64_str)
    font_bytes = base64.b64decode(font_base64_str)
    with open('font.woff', 'wb') as fp:
        fp.write(font_bytes)
    # print(font)
    # TTFont()
    font = TTFont(BytesIO(font_bytes))
    font.saveXML('font.xml')
    keys = font.getBestCmap()
    keys = {hex(k): v for k, v in keys.items()}
    # print(keys)

    # 目标是找到uni
    # 2、生成字典
    data = {k[2:]: str(int(v[-2:]) - 1) for k, v in keys.items()}
    # print(data)
    # 3、替换
    for k, v in data.items():
        content = content.replace(f'&#x{k};', v)
    return content


def get_xpath(url):
    '''
    请求url,返回响应element对象
    :param url:
    :return:
    '''
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
        'cookie': 'ctid=14; lps=https%3A%2F%2Fbj.zu.anjuke.com%2F%7C; aQQ_ajkguid=3274DC80-7587-5817-0284-655827C2314F; id58=e87rkF8Oq2qquqUgCZbsAg==; id58=e87rkF8Oq2yquqUgCZcrAg==; wmda_uuid=0f7ececca97eb5c3895e05b0ea16ce01; wmda_new_uuid=1; wmda_session_id_6289197098934=1594796907895-f601e16b-23d6-2347; wmda_visited_projects=%3B6289197098934; xzfzqtoken=fzHvD9NRAZqWu4ckT6yqlgqbprZU2Hc05spuCJ2Xn4Xm6g9J5GrGOyBH8w%2FjGhH9in35brBb%2F%2FeSODvMgkQULA%3D%3D',
    }
    response = requests.get(url, headers=headers)
    # 测试
    # print(response.text)
    page_content = base64_deocde(response.text)
    return etree.HTML(page_content)


def main():
    base_url = 'https://bj.zu.anjuke.com/'
    tree = get_xpath(base_url)
    div_list = tree.xpath('//div[@class="zu-itemmod"]')
    # print(div_list)
    for div in div_list:
        title = div.xpath('.//div[@class="zu-info"]/h3/a/b/text()')[0]
        price = div.xpath('.//div[@class="zu-side"]/p/strong/b/text()')[0]
        print(title, price)


if __name__ == '__main__':
    main()