目录引言逆向过程步骤一找到参数对应js代码位置步骤二分析参数值的生成逻辑步骤三确定函数u的具体内容步骤四使用python实现请求参数的生成投诉信息爬取引言下面是一张主流网页加密方法的思维导图本文将介绍的黑猫投诉平台网站使用的即是请求头加密。从开发者工具中抓包的结果来看该网页的json数据包的请求参数中rs和signature两个参数在下拉后得到的新数据包中是动态变化的而ts参数过一段时间会发生变化推测应该是和时间戳相关的参数。接下来就通过js逆向获取这几个参数的生成方法并实现爬取投诉信息。逆向过程步骤一找到参数对应js代码位置由于用rs搜索容易重复这里搜索signature参数其中只有一个js文件中包含该变量名。在js代码中再次搜索该变量名发现共找到14个为了找到真正的signature参数位置对可能是该参数的位置打上断点挨个尝试后确定获得signature参数值的位置在下图所示位置实际是变量g的值。同时也可以清楚的看到ts和rs的值分别等于l和p两个变量的值。步骤二分析参数值的生成逻辑从代码中很清楚的看到g的值通过这段代码赋予var g u([l, p, b, h, c, d[type e]].sort().join())也就是将这几个变量l, p, b, h, c, d[type e]排序后组成一个新的字符串并将该字符串传入函数u得到返回值即为g的值。再往上找寻找上面几个变量的值的生成方式可以发现在下图所示代码中这些变量被创建和赋值。首先l变量确实是当前时间戳得到的值l的值也是ts参数的值印证了一开始的猜想b是一个常数值为$d6eb7ff91ee257475%h的值是PAGE_CONFIG对象的keywords属性的值实际上从右边作用域可以看到就是我们的搜索关键字值为外卖 食品安全c的值为10它其实就是请求参数中的page_size的值e的值从右边作用域也可以看到值为1刷新网页该值不变因此d[type e]的值可以确定为1最后是p的值也是请求参数rs的值它是一个函数的返回值不需要管这个函数是干什么的用chatgpt把这段代码转为python代码即可转换之前还需找到e和t的值是什么也从右边发现两者值不变分别是1和4但e在代码中用于判断因此转为python值其实是True如下得到p值得生成方法实质就是生成16位得随机字符串def generate_random_string(eTrue, t4, r16): chars 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ length t if not e else random.randint(t, r) return .join(random.choice(chars) for _ in range(length))步骤三确定函数u的具体内容将断点打到u函数的位置跳到函数定义的位置通过反复地打断点跟进最终确定其执行的实际上是如下两个函数其实质是执行了一次SHA-256 哈希算法。知道他执行的是SHA-256 哈希算法后直接使用python对应的hashlib库中的方法即可。步骤四使用python实现请求参数的生成直接放出代码def generate_random_string(eTrue, t4, r16): chars 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ length t if not e else random.randint(t, r) return .join(random.choice(chars) for _ in range(length)) def get_sha256(value): sha256加密 :param value: 加密字符串 :return: 加密结果转换为16进制字符串并大写 hsobj hashlib.sha256() hsobj.update(value.encode(utf-8)) return hsobj.hexdigest() tsstr(int(time.time() * 1000))#ts,时间戳 lts rsgenerate_random_string(True, 4, 16) prs#rs b $d6eb7ff91ee257475% h外卖 食品安全#keywords c10#page_size dstr(i)#d[type e]page signature.join(sorted([l, p, b, h, c, d])) signatureget_sha256(signature) params { ts: ts, rs: rs, signature: signature, keywords: h, page_size: c, page: d, }到这里请求参数就构造完成了。投诉信息爬取下面是投诉信息的爬取把cookies和headers复制下来使用get方法获得每条投诉对应的具体信息页面的url然后从该url中爬取需要的信息我这里只需要投诉时间、结束时间和投诉编号完整代码如下import requests import random import hashlib import time import json from bs4 import BeautifulSoup cookies { #自己复制 } headers { #自己复制 } #[l, p, b, h, c, d[type e]].sort().join() def generate_random_string(eTrue, t4, r16): chars 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ length t if not e else random.randint(t, r) return .join(random.choice(chars) for _ in range(length)) def get_sha256(value): sha256加密 :param value: 加密字符串 :return: 加密结果转换为16进制字符串并大写 hsobj hashlib.sha256() hsobj.update(value.encode(utf-8)) return hsobj.hexdigest() requests.packages.urllib3.disable_warnings() sessionsrequests.session() data[] number0 for i in range(1,101):#1524 print(i) url_list[] if len(data)%500 and len(data)!0: time.sleep(60) while True: tsstr(int(time.time() * 1000))#ts,时间戳 lts rsgenerate_random_string(True, 4, 16) prs#rs b $d6eb7ff91ee257475% h外卖 食品安全#keywords c10#page_size dstr(i)#d[type e]page signature.join(sorted([l, p, b, h, c, d])) signatureget_sha256(signature) params { ts: ts, rs: rs, signature: signature, keywords: h, page_size: c, page: d, } try: response sessions.get(https://tousu.sina.com.cn/api/index/s,cookiescookies, headersheaders,paramsparams,verifyFalse,allow_redirectsFalse) responsejson.loads(response.text)[result][data][lists] #print(response) for n in range(len(response)): if response[n][main][evaluate_u]None: number1 continue else: urlresponse[n][main][url] url_list.append(url) number1 break except Exception as e: print(e,response.text,i) time.sleep(300) continue for url in url_list: while True: try: response sessions.get(https:url,cookiescookies,headersheaders,verifyFalse,allow_redirectsFalse) soup BeautifulSoup(response.text, html.parser) u_date_elements soup.find_all(class_u-date) u_listsoup.find(ul, class_ts-q-list) c_numu_list.find_all(li)[0].text endtimeu_date_elements[2].text starttimeu_date_elements[6].text data.append([starttime,endtime,c_num]) break except Exception as e: print(e,response.text,i) time.sleep(60) continue datapd.DataFrame(data,columns[starttime,endtime,c_num])
爬虫实战3-js逆向入门:以黑猫投诉平台为例
目录引言逆向过程步骤一找到参数对应js代码位置步骤二分析参数值的生成逻辑步骤三确定函数u的具体内容步骤四使用python实现请求参数的生成投诉信息爬取引言下面是一张主流网页加密方法的思维导图本文将介绍的黑猫投诉平台网站使用的即是请求头加密。从开发者工具中抓包的结果来看该网页的json数据包的请求参数中rs和signature两个参数在下拉后得到的新数据包中是动态变化的而ts参数过一段时间会发生变化推测应该是和时间戳相关的参数。接下来就通过js逆向获取这几个参数的生成方法并实现爬取投诉信息。逆向过程步骤一找到参数对应js代码位置由于用rs搜索容易重复这里搜索signature参数其中只有一个js文件中包含该变量名。在js代码中再次搜索该变量名发现共找到14个为了找到真正的signature参数位置对可能是该参数的位置打上断点挨个尝试后确定获得signature参数值的位置在下图所示位置实际是变量g的值。同时也可以清楚的看到ts和rs的值分别等于l和p两个变量的值。步骤二分析参数值的生成逻辑从代码中很清楚的看到g的值通过这段代码赋予var g u([l, p, b, h, c, d[type e]].sort().join())也就是将这几个变量l, p, b, h, c, d[type e]排序后组成一个新的字符串并将该字符串传入函数u得到返回值即为g的值。再往上找寻找上面几个变量的值的生成方式可以发现在下图所示代码中这些变量被创建和赋值。首先l变量确实是当前时间戳得到的值l的值也是ts参数的值印证了一开始的猜想b是一个常数值为$d6eb7ff91ee257475%h的值是PAGE_CONFIG对象的keywords属性的值实际上从右边作用域可以看到就是我们的搜索关键字值为外卖 食品安全c的值为10它其实就是请求参数中的page_size的值e的值从右边作用域也可以看到值为1刷新网页该值不变因此d[type e]的值可以确定为1最后是p的值也是请求参数rs的值它是一个函数的返回值不需要管这个函数是干什么的用chatgpt把这段代码转为python代码即可转换之前还需找到e和t的值是什么也从右边发现两者值不变分别是1和4但e在代码中用于判断因此转为python值其实是True如下得到p值得生成方法实质就是生成16位得随机字符串def generate_random_string(eTrue, t4, r16): chars 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ length t if not e else random.randint(t, r) return .join(random.choice(chars) for _ in range(length))步骤三确定函数u的具体内容将断点打到u函数的位置跳到函数定义的位置通过反复地打断点跟进最终确定其执行的实际上是如下两个函数其实质是执行了一次SHA-256 哈希算法。知道他执行的是SHA-256 哈希算法后直接使用python对应的hashlib库中的方法即可。步骤四使用python实现请求参数的生成直接放出代码def generate_random_string(eTrue, t4, r16): chars 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ length t if not e else random.randint(t, r) return .join(random.choice(chars) for _ in range(length)) def get_sha256(value): sha256加密 :param value: 加密字符串 :return: 加密结果转换为16进制字符串并大写 hsobj hashlib.sha256() hsobj.update(value.encode(utf-8)) return hsobj.hexdigest() tsstr(int(time.time() * 1000))#ts,时间戳 lts rsgenerate_random_string(True, 4, 16) prs#rs b $d6eb7ff91ee257475% h外卖 食品安全#keywords c10#page_size dstr(i)#d[type e]page signature.join(sorted([l, p, b, h, c, d])) signatureget_sha256(signature) params { ts: ts, rs: rs, signature: signature, keywords: h, page_size: c, page: d, }到这里请求参数就构造完成了。投诉信息爬取下面是投诉信息的爬取把cookies和headers复制下来使用get方法获得每条投诉对应的具体信息页面的url然后从该url中爬取需要的信息我这里只需要投诉时间、结束时间和投诉编号完整代码如下import requests import random import hashlib import time import json from bs4 import BeautifulSoup cookies { #自己复制 } headers { #自己复制 } #[l, p, b, h, c, d[type e]].sort().join() def generate_random_string(eTrue, t4, r16): chars 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ length t if not e else random.randint(t, r) return .join(random.choice(chars) for _ in range(length)) def get_sha256(value): sha256加密 :param value: 加密字符串 :return: 加密结果转换为16进制字符串并大写 hsobj hashlib.sha256() hsobj.update(value.encode(utf-8)) return hsobj.hexdigest() requests.packages.urllib3.disable_warnings() sessionsrequests.session() data[] number0 for i in range(1,101):#1524 print(i) url_list[] if len(data)%500 and len(data)!0: time.sleep(60) while True: tsstr(int(time.time() * 1000))#ts,时间戳 lts rsgenerate_random_string(True, 4, 16) prs#rs b $d6eb7ff91ee257475% h外卖 食品安全#keywords c10#page_size dstr(i)#d[type e]page signature.join(sorted([l, p, b, h, c, d])) signatureget_sha256(signature) params { ts: ts, rs: rs, signature: signature, keywords: h, page_size: c, page: d, } try: response sessions.get(https://tousu.sina.com.cn/api/index/s,cookiescookies, headersheaders,paramsparams,verifyFalse,allow_redirectsFalse) responsejson.loads(response.text)[result][data][lists] #print(response) for n in range(len(response)): if response[n][main][evaluate_u]None: number1 continue else: urlresponse[n][main][url] url_list.append(url) number1 break except Exception as e: print(e,response.text,i) time.sleep(300) continue for url in url_list: while True: try: response sessions.get(https:url,cookiescookies,headersheaders,verifyFalse,allow_redirectsFalse) soup BeautifulSoup(response.text, html.parser) u_date_elements soup.find_all(class_u-date) u_listsoup.find(ul, class_ts-q-list) c_numu_list.find_all(li)[0].text endtimeu_date_elements[2].text starttimeu_date_elements[6].text data.append([starttime,endtime,c_num]) break except Exception as e: print(e,response.text,i) time.sleep(60) continue datapd.DataFrame(data,columns[starttime,endtime,c_num])