app:2.66.0

接口:https://app.api.ke.com/api/secondhand/resblock/framegroup/list?resblockId=2413600823455693

需求:获取贝壳小区里面的户型图数据

image-20230606165229656

接口分析:

通过抓包可以发现,里面有很多的字段都看不太懂,我们可以通过撰写请求来确定哪些字段是需要携带,哪些是不需要携带的,其中 CookieDevice-id-sAuthorization 字段是一定需要携带的

cookie可以固定,只需要一个 lianjia_udid 字段就可以了

Device-id-s 跟设备有关,这里也可以写死

wll-kgsa 这个字段在高版本的app中,需要携带,使用低版本就不需要携带,请求头中还需要携带 Lianjia-Version 等跟版本有关的 字段才行

Authorization 这个字段必须携带,基本贝壳app所有的接口都必须携带,这个接口应该是跟请求体有关,相同的请求参数该字段相同

image-20230606165626380

请求代码:

image-20230606170451661

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
list_headers = {
'x-req-id': '3726645a-df8c-464b-9341-3ca5d345a820',
'Page-Schema': 'community%2Fhuxing%2Flist',
'Referer': 'communitydetail',
'Cookie': 'lianjia_udid=0fc0690f43831ba1;',
'Dynamic-SDK-VERSION': '1.1.0',
'Lianjia-City-Id': '440300',
'parentSceneId': '6530638482656836097',
'source-global': '{}',
'User-Agent': 'Beike2.89.0;samsung SM-G973N; Android 9',
'Lianjia-Device-Id': '0fc0690f43831ba1',
'Lianjia-Version': '2.66.0',
'Lianjia-Im-Version': '2.34.0',
'Lianjia-Recommend-Allowable': '1',
'Authorization': 'MjAxODAxMTFfYW5kcm9pZDpiY2YzYTI4ZDE2MWU3Yzc3NTBiYzQ5OGFmZjQyZjNhNGRlYWVlOGQ1',
'Device-id-s': '0fc0690f43831ba1;;020102Sl74XvwW/Nx/ybVLmW6etX19zcPY6VWmllYXVAk+iYbWtHbEJNSVm9jF72ngVm1xRYM2JLG7wRzFcludQvy5RA==',
'Channel-s': 'Android_ke_tencentt',
'AppInfo-s': 'Beike;2.66.0;2660100',
'Hardware-s': 'samsung;SM-G973N',
'SystemInfo-s': 'android;9',
'Host': 'app.api.ke.com',
'Connection': 'Keep-Alive',
'Accept-Encoding': 'gzip',
}
list_url = 'https://app.api.ke.com/api/secondhand/resblock/framegroup/list?resblockId={}'.format(house_id)
print(list_url)
res = requests.get(url=list_url, headers=list_headers, timeout=8)
res.encoding = 'utf-8'
res_json = json.loads(res.text)
print(res_json)
frame_list = res_json['data']['list']
if len(frame_list):
for img_list in frame_list:
for data in img_list['list']:
item = {}
item['unit'] = data['title'].split('/')[0]
item['area'] = data['title'].split('/')[1]
item['orientation'] = data['title'].split('/')[2]
item['title'] = data['title']
item['img_url'] = data['picUrl']
print(item)

字段获取:

使用jadx进行反编译,搜索关键字 Authorization 或者 "Authorization"

搜出来的结果不算多,可以挨个点进去看一下。我们这里直接看这个拦截器,猜测一下,既然每个接口都会携带,那应该都需要经过某个拦截器才对,我们进来看一下

image-20230606172137600

进来之后,我们可以看到这里应该是添加了一个okhttp的的拦截器,我们在业内搜索 signRequest 关键字,最终在下面我们可以看到对应的拦截器方法

image-20230606172441461

image-20230606173019938

我们采用firda hook的形式去看一下这个方法返回什么,结果竟然报错了,猜测是反编译导致方法名的问题,我们换个版本的jadx重新编译一下

image-20230606181218482

换了个 1.2.0版本的jadx,这次反编译没有问题, 也是成功的验证了这个方法返回的就是我们要的 "Authorization" 字段

image-20230606181553850

image-20230606181712564

我们来看一下这个方法,第一个判断条件是判断请求url是否是布尔类型,第二个判断条件是请求方式是否为get, 我们可以直接看 com.bk.base.netimpl.a.ji().getSignString(uri, hashMap); 下面为判断是否是post请求,已经还对请求体做了处理,猜测如果是post请求,那么请求体应该也会被参与计算中去

image-20230606182637305

我们直接右键 跳到声明

image-20230606183022468

我们可以继续hook一下这个方法,看一下传入的两个值是什么

image-20230606183111227

接收的就是请求的url链接,第二个参数如果是post请求,则传入的是请求体,我们再看一下这个方法做了什么

image-20230606183327959

我们从下往上看 我们最终要 encodeToString encodeToString 是 str2 和 SHA1ToString 组合后加工而成

str2 是跟前后两个参数有关,一个是 httpAppId 一个是httpAppSecret

SHA1ToString 是对sb参数做了处理

sb视乎是跟请求参数有关

最为重要的是它的数据是经过base64处理后得到的,那我们看一下base64处理之前是什么样子的

image-20230606185108575

这下我们可以确定str2就是 20180111_android 这个值固定, 接下来 我们只要知道 DeviceUtil.SHA1ToString(sb.toString()) 做了哪些事情 我们就完成了

image-20230606185928699

image-20230606200003780

同样的,hook一下这个方法,可以看到传入的值当中,后面的是请求体,前面一部分看上去也像是md5加密后的结果,他们拼接之后做了sha1加密

1
https://app.api.ke.com/api/secondhand/resblock/framegroup/list?resblockId=2411048421652

image-20230606195954146

image-20230606201036249

我们多翻几个页面,看一下这个值会不会发生变化,经过测试之后,我们可以看到,这就是个固定值,即便重启app,这个值也不会发生变化

image-20230606200648963

现在 我们可以总结一下, 有两个固定值,一个是 d5e343d453aecca8b14b2dc687c381ca 拼接请求体后进行sha1加密,另一个固定值是

20180111_android: 加上上面sha1加密后在进行base64编码,就得到了 Authorization字段

改写一下代码,也是完全没有问题,可以成功获取到我们想要的数据

image-20230606201228886

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# coding:utf-8
import hmac
import multiprocessing
import string
import urllib

import requests, re, random, json, time
from lxml import etree
import pymysql
import hashlib
from base64 import b64encode, b64decode



def get_img_list():
time_stamp = int(time.time())
house_id = '2413600823455693'
secret_str = 'd5e343d453aecca8b14b2dc687c381caresblockId={}'.format(house_id)
hash_secret = hashlib.sha1(secret_str.encode("utf-8")).hexdigest()
base_secret = '20180111_android:' + hash_secret
base64_secret = b64encode(base_secret.encode()).decode('utf-8')
print(base64_secret)
list_headers = {
'x-req-id': '3726645a-df8c-464b-9341-3ca5d345a820',
'Page-Schema': 'community%2Fhuxing%2Flist',
'Referer': 'communitydetail',
'Cookie': 'lianjia_udid=0fc0690f43831ba1;',
'Dynamic-SDK-VERSION': '1.1.0',
'Lianjia-City-Id': '440300',
'parentSceneId': '6530638482656836097',
'source-global': '{}',
'User-Agent': 'Beike2.89.0;samsung SM-G973N; Android 9',
'Lianjia-Device-Id': '0fc0690f43831ba1',
'Lianjia-Version': '2.66.0',
'Lianjia-Im-Version': '2.34.0',
'Lianjia-Recommend-Allowable': '1',
'Authorization': base64_secret,
'Device-id-s': '0fc0690f43831ba1;;020102Sl74XvwW/Nx/ybVLmW6etX19zcPY6VWmllYXVAk+iYbWtHbEJNSVm9jF72ngVm1xRYM2JLG7wRzFcludQvy5RA==',
'Channel-s': 'Android_ke_tencentt',
'AppInfo-s': 'Beike;2.66.0;2660100',
'Hardware-s': 'samsung;SM-G973N',
'SystemInfo-s': 'android;9',
'Host': 'app.api.ke.com',
'Connection': 'Keep-Alive',
'Accept-Encoding': 'gzip',
}
list_url = 'https://app.api.ke.com/api/secondhand/resblock/framegroup/list?resblockId={}'.format(house_id)
print(list_url)
res = requests.get(url=list_url, headers=list_headers, timeout=8)
res.encoding = 'utf-8'
res_json = json.loads(res.text)
print(res_json)
frame_list = res_json['data']['list']
if len(frame_list):
for img_list in frame_list:
for data in img_list['list']:
item = {}
item['unit'] = data['title'].split('/')[0]
item['area'] = data['title'].split('/')[1]
item['orientation'] = data['title'].split('/')[2]
item['title'] = data['title']
item['img_url'] = data['picUrl']
print(item)


get_img_list()

'''
lianjiabeike://ershou/community/frameList?resblockId=2411049483671&roomKey=l2
https://apps.api.ke.com/house/resblock/detailpart1v2?id={}
'''