猿人学爬虫题目第三题: 《访问逻辑-推心置腹》,该案例也非常简单。

第三题和第四题跟Js逆向没有什么关系,本来是不想发的,为了排版好看也发这个专栏里吧。


Js逆向-猿人学(3-4)访问逻辑-样式干扰_Js逆向
第三题浪费了我十几分钟,因为试了很多次没有返回set-cookie,最后发现是服务端对headers的认证问题。 已知参数中除了 Host 和 Content-Length 别的缺一不可。

  • Accept-Encoding 、 Accept-Language 、Accept、Connection 存在即可
  • Origin 和 Referer 必须有字符串 yuanrenxue.com/match/3
  • User-Agent 访问后几页需要是 yuanrenxue.project
import requests
headers = {
    'Connection': '1',
    'User-Agent': 'yuanrenxue.project',
    'Accept': '1',
    'Origin': 'lxyuanrenxue.com/match/3123',
    'Referer': 'yuanrenxue.com/match/3222',
    'Accept-Encoding': 'lx',
    'Accept-Language': 'lx'
}
url = "http://match.yuanrenxue.com/logo"
s = requests.session()
s.headers = headers
s.post(url, headers=headers)
d = s.get('http://match.yuanrenxue.com/api/match/3?page=4')
print(d.text)

第四题:《雪碧图、样式干扰》
Js逆向-猿人学(3-4)访问逻辑-样式干扰_js_02

这个数字是无法选中的,因为以图片的形式加载出来,这种css做映射的方式在市面上还是很常见的。

Js逆向-猿人学(3-4)访问逻辑-样式干扰_Js逆向_03

原理就是通过css标签的参数来赋予数字图片不同的位置,left > 0 ,水平向右偏移。

上图第一个img标签向右偏移了23px,因为一个数字的间隔是11.5px,所以他看起来就是在页面的第三个数字。


解决方法:

因为经过观察, 这里的数字图的链接都是固定的,如果是动态的话我们可能需要找一下生成规律了。
而静态的直接把0-9的数字图链接复制出来就可以。

原本的链接太长了不方便看,我把前面的data:image… 都删了。

item = {
    'AOyW6SvqnweCAAAAAElFTkSuQmCC':0,
    '7HMAAAAAElFTkSuQmCC':1,
    'psESerq6nvOPMylrLDEa7q3C7L7hrVt0z1Fu9Dor0g3AH8BJlTqZkAngxQAAAAASUVORK5CYII=':2,
    'AbAv8WdRHzjKAAAAAElFTkSuQmCC': 3,
    'AgqvQAAAABJRU5ErkJggg==':4,
    '3J2gmVZucHAAAAAASUVORK5CYII=':5,
    'nz0HAvgL80YzEyuMQpQAAAAASUVORK5CYII=':6,
    'wZllPKOqgIPfi2yzeBSPAVFRT1UBF2I5GzflzwEWWU9TD5zxLwC1sVsHrJiVs0AAAAAElFTkSuQmCC': 7,
    'BwUbVTGaHQS9Thu0rF9kUrELEJmKDGSW2J7DTzPbNwzIyiOyPX2lVJYPh3wL8BvLZG6cpuRANAAAAAElFTkSuQmCC':8,
    'dVIiAf4ApbEnkB6qHqsAAAAASUVORK5CYII=':9
}

接下来把页面中的图片链接和left偏移值获取出来。已知返回的json数据,info中是html节点。
Js逆向-猿人学(3-4)访问逻辑-样式干扰_js_04
需要注意的是,页面中也加入了假标签,既 display: none; 的,需要去除。
Js逆向-猿人学(3-4)访问逻辑-样式干扰_js_05
而json中返回了很多假数据,后来观察了下,只有一种class是真图片。
Js逆向-猿人学(3-4)访问逻辑-样式干扰_Js逆向_06

另外每次请求返回的标签数量也是不同的,但是唯一可以确定的是 页面上正确数字是不变的,所以判断class标签的数量。

测试方法:(打印出所有不同class的数量)(尽管在js中也能找到解决方法)

import requests
from lxml import etree
url = "http://match.yuanrenxue.com/api/match/4?page=2"
d =requests.get(url,headers=headers).json()
s = etree.HTML(d['info'])
result = []
for li in s.xpath('//td'):
    result+=li.xpath('./img/@class')

for la in list(set(result)):
    print(result.count(la))

经过测试之后,

  • 第一页的正确数量为 39
  • 第二页的正确数量为 40
  • 第三页的正确数量为 39
  • 第四页的正确数量为 37
  • 第五页的正确数量为 40

然后用xpath通过class名把正确的图片地址和偏移值取出来。
根据图片地址再匹配对应的数字,根据偏移值来计算正确的顺序。

写了一堆for循环 = = 处理比较麻烦就不啰嗦了,有问题就留言吧


最后输出结果:
Js逆向-猿人学(3-4)访问逻辑-样式干扰_Js逆向_07

完整代码:

# -*- coding: utf-8 -*-
# @Time    : 2021/1/20 15:34
# @Author  : lx
# @IDE :PyCharm


headers = {
    'Accept': 'application/json, text/javascript, */*; q=0.01',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Connection': 'keep-alive',
    'Cookie': 'sessionid=4oq3k87ymymlwwkxubguaro78xi5ygdm',
    'Host': 'match.yuanrenxue.com',
    'Referer': 'http://match.yuanrenxue.com/match/4',
    'X-Requested-With': 'XMLHttpRequest',
    'User-Agent': 'yuanrenxue.project'

}
def sort(zu:list):
    item = {}
    # [[23.0, 8], [-11.5, 6], [11.5, 1], [-23.0, 0]]
    # [23.0, 8]:第一组本来在第一位,23.0即使往右挪2位
    for index in range(len(zu)):
        item[index + zu[index][0] / 11.5]= zu[index][1]
    result = ''
    for num in sorted(item.items()):
        result+=str(num[1])
    return int(result)



img_item = {
    'AOyW6SvqnweCAAAAAElFTkSuQmCC':0,
    '7HMAAAAAElFTkSuQmCC':1,
    'psESerq6nvOPMylrLDEa7q3C7L7hrVt0z1Fu9Dor0g3AH8BJlTqZkAngxQAAAAASUVORK5CYII=':2,
    'AbAv8WdRHzjKAAAAAElFTkSuQmCC': 3,
    'AgqvQAAAABJRU5ErkJggg==':4,
    '3J2gmVZucHAAAAAASUVORK5CYII=':5,
    'nz0HAvgL80YzEyuMQpQAAAAASUVORK5CYII=':6,
    'wZllPKOqgIPfi2yzeBSPAVFRT1UBF2I5GzflzwEWWU9TD5zxLwC1sVsHrJiVs0AAAAAElFTkSuQmCC': 7,
    'BwUbVTGaHQS9Thu0rF9kUrELEJmKDGSW2J7DTzPbNwzIyiOyPX2lVJYPh3wL8BvLZG6cpuRANAAAAAElFTkSuQmCC':8,
    'dVIiAf4ApbEnkB6qHqsAAAAASUVORK5CYII=':9
}

lab_list = [39,40,39,37,40]

import requests
from lxml import etree
for page in range(1,6):
    url = f"http://match.yuanrenxue.com/api/match/4?page={page}"
    d =requests.get(url,headers=headers).json()
    s = etree.HTML(d['info'])
    result = []
    for li in s.xpath('//td'):
        result+=li.xpath('./img/@class')

    for la in list(set(result)):
        if result.count(la) == lab_list[page-1]:
            endl = []
            for li in s.xpath('//td'):
                zu = []     # 一组是3个图片或者4个图片组成的数字
                for pic in li.xpath('./img[@class="{}"]'.format(la)): # la=正确class标签名
                    for k,v in img_item.items():
                        if k in pic.xpath('./@src')[0]:
                            px = pic.xpath('./@style')[0].split(':')[1].replace('px','')
                            zu.append([float(px),v])
                            continue
                endl.append(sort(zu))
            print(endl)