├── .gitignore ├── .idea ├── .gitignore ├── dbnavigator.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── reverse_practice.iml └── vcs.xml ├── 8btc ├── __init__.py ├── demo.js ├── demo.py └── docs │ ├── 1.png │ ├── 2.png │ ├── 4.png │ └── readme.md ├── aliwx ├── __init__.py └── demo.py ├── appmiu ├── __init__.py └── demo.js ├── bbs_csdn ├── __init__.py ├── demo.js └── demo.py ├── bmfw ├── __init__.py ├── demo.js └── demo.py ├── cas_gench ├── __init__.py ├── demo.js └── demo.py ├── chacewang ├── __init__.py ├── demo.js └── demo.py ├── changelog.md ├── chrome.md ├── chromedriver.md ├── cnpub ├── __init__.py ├── demo.js └── demo.py ├── cpws ├── __init__.py ├── demo.js ├── login.js └── login.py ├── ctbpsp ├── __init__.py ├── demo.js └── demo.py ├── ctyun ├── __init__.py └── demo.js ├── dewu ├── __init__.py ├── demo.js └── demo.py ├── didiwaimai ├── __init__.py ├── demo.js └── demo.py ├── dmfw_mca ├── __init__.py ├── demo.js └── demo.py ├── driver_path └── chromedriver ├── ehsy ├── __init__.py ├── demo.js └── demo.py ├── endata ├── __init__.py ├── demo.js └── demo.py ├── fenbi ├── __init__.py ├── demo.js └── demo.py ├── ggzyfw_fujian ├── __init__.py ├── demo.js └── demo.py ├── hh1024 ├── __init__.py ├── demo.js └── demo.py ├── hjs ├── __init__.py └── demo.py ├── hsddcx ├── __init__.py ├── demo.js └── demo.py ├── images ├── chrome_version.png ├── chromedriver_version.png ├── fix_origin_chrome.png ├── origin_chrome.png ├── response_type.png ├── setting.png └── setting_button.png ├── iyunzhi ├── __init__.py ├── demo.js └── demo.py ├── jzsc ├── __init__.py ├── demo.js └── demo.py ├── kanzhun ├── __init__.py ├── demo.js └── demo.py ├── landchina ├── __init__.py ├── demo.js └── demo.py ├── liepin ├── __init__.py └── demo.js ├── liuyan ├── __init__.py └── demo.py ├── maomaozu ├── __init__.py ├── demo.js └── demo.py ├── music163 ├── __init__.py └── demo.js ├── music_kuwo ├── __init__.py └── demo.js ├── my_37 ├── __init__.py └── demo.js ├── mytokencap ├── __init__.py ├── demo.js └── demo.py ├── newrank ├── __init__.py ├── demo.js └── demo.py ├── oauth ├── __init__.py └── demo.js ├── oklink ├── __init__.py ├── demo.js └── demo.py ├── package.json ├── passport_fang ├── __init__.py ├── demo.js └── demo.py ├── pycharm激活方案汇总 ├── README.MD ├── 激活方案一 │ └── 无限30天试用(靠谱) │ │ ├── ide-eval-resetter-2.1.13.zip │ │ └── 操作步骤.docx ├── 激活方案三 │ └── 正版激活(支持所有版本)(永久更新) │ │ └── 支持所有版本-正版激活.txt ├── 激活方案二 │ └── 永久破解(亲测2020 3.3以下版本通用) │ │ ├── BetterIntelliJ.zip │ │ ├── reset_script │ │ ├── reset_jetbrains_eval_mac_linux.sh │ │ └── reset_jetbrains_eval_windows.vbs │ │ ├── 操作说明.txt │ │ └── 激活补丁key-.txt └── 激活方案四 │ └── README.MD ├── python2encrypt ├── __init__.py ├── base64_encrypt.py ├── md5_encrypt.py ├── rsa_encrypt.py └── sha_encrypt.py ├── qimingpian ├── __init__.py ├── demo.js └── demo.py ├── readme.MD ├── remark.md ├── requirements.txt ├── souhu ├── __init__.py └── demo.js ├── stream_capital ├── __init__.py ├── demo.js └── demo.py ├── tonghuashun ├── __init__.py ├── demo.js └── demo.py ├── tousu_sign ├── __init__.py ├── demo.js └── demo.py ├── utils.py ├── waitpay ├── __init__.py ├── demo.js └── demo.py ├── webapi ├── __init__.py ├── demo.js └── demo.py ├── weibotop ├── __init__.py ├── demo.js └── demo.py ├── xhpfmapi ├── __init__.py ├── demo.js └── demo.py ├── xiniu ├── __init__.py ├── demo.js └── demo.py ├── xmly_login ├── __init__.py ├── demo.py ├── get_pwd.js └── get_signature.js ├── ybdzpz ├── __init__.py ├── demo.js └── demo.py ├── yiche ├── __init__.py └── demo.py ├── ypwk ├── __init__.py └── demo.js ├── yuanrenxue ├── __init__.py ├── readme.md ├── scrape_login1 │ ├── __init__.py │ └── demo.py ├── scrape_spa2 │ ├── __init__.py │ ├── demo.js │ └── demo.py ├── scrape_spa6 │ ├── __init__.py │ ├── demo.js │ └── demo.py ├── topic13 │ ├── __init__.py │ └── demo.py ├── topic14 │ ├── __init__.py │ ├── demo.js │ └── demo.py ├── topic25 │ ├── __init__.py │ └── demo.py ├── topic55 │ ├── __init__.py │ ├── demo.js │ └── demo.py ├── topic56 │ ├── __init__.py │ ├── demo.js │ └── demo.py ├── topic57 │ ├── __init__.py │ ├── demo.js │ └── demo.py ├── topic58 │ ├── __init__.py │ └── demo.py ├── topic60 │ ├── __init__.py │ ├── demo.js │ └── demo.py ├── wangluozhe2 │ ├── __init__.py │ ├── demo.js │ └── demo.py ├── wangluozhe3 │ ├── __init__.py │ ├── demo.js │ └── demo.py └── wangluozhe4 │ ├── __init__.py │ ├── demo.js │ └── demo.py ├── zbcg_sznsyy ├── __init__.py ├── demo.js └── demo.py └── zyfuw ├── __init__.py ├── demo.js └── demo.py /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | .idea 4 | __pycache__ 5 | .xml 6 | .iml -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/reverse_practice.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /8btc/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:45 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /8btc/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js'); 2 | 3 | function get_device_id(e, t) { 4 | for (var n = "", a = t ? Math.round(Math.random() * (t - e)) + e : e, i = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"], r = 0; r < a; r++) { 5 | n += i[Math.round(Math.random() * (i.length - 1))] 6 | } 7 | return n 8 | } 9 | 10 | function get_sign(c) { 11 | var e = JSON.stringify(c), 12 | t = 'WTAHAPPYACTIVITY'; 13 | var n = { 14 | mode: CryptoJS.mode.ECB, 15 | padding: CryptoJS.pad.Pkcs7 16 | } 17 | , a = CryptoJS.enc.Utf8.parse(t); 18 | return CryptoJS.AES.encrypt(e, a, n).toString().replace(/\//g, "_").replace(/\+/g, "-") 19 | } 20 | 21 | 22 | var device_id = get_device_id(20, 20); 23 | console.log(device_id) 24 | 25 | var sign_params = {"appId": "1", "timestamp": 1695189097, "serverCode": "0"}, 26 | sign = get_sign(sign_params); 27 | console.log(sign) 28 | -------------------------------------------------------------------------------- /8btc/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:45 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import time 7 | import requests 8 | 9 | from utils import * 10 | 11 | 12 | def conversion_time_str(postDate): 13 | """ 14 | 时间戳转标准时间格式 15 | :param postDate: 时间戳 16 | :return: 标准时间格式 17 | """ 18 | timeArray = time.localtime(postDate) 19 | res_time = time.strftime("%Y-%m-%d %H:%M:%S", timeArray) 20 | return res_time 21 | 22 | 23 | def get_device_id_and_sign(sign_params): 24 | ctx = Utils(js_file_name='demo.js').read_js_file() 25 | device_id = ctx.call('get_device_id', 20, 20) 26 | sign = ctx.call('get_sign', sign_params) 27 | return device_id, sign 28 | 29 | 30 | def get_results(json_data): 31 | sign_params = {"appId": "1", "timestamp": str(int(time.time())), "serverCode": "0"} 32 | device_id, sign = get_device_id_and_sign(sign_params) 33 | logger.info({'device_id': device_id, 'sign': sign}) 34 | headers = { 35 | 'authority': 'gate.8btc.cn:8443', 36 | 'accept': '*/*', 37 | 'accept-language': 'zh-CN,zh;q=0.9', 38 | 'app-code': '8btc', 39 | 'authorization': '{"secretKeyVersion":1,"sign":"%s"}' % sign, 40 | 'device_id': device_id, 41 | 'origin': 'https://www.8btc.com', 42 | 'referer': 'https://www.8btc.com/', 43 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36', 44 | } 45 | response = requests.post('https://gate.8btc.cn:8443/one-graph-auth/graphql', headers=headers, json=json_data) 46 | return response.json() 47 | 48 | 49 | def parse(json_data): 50 | results = get_results(json_data) 51 | data_list = results['data']['articleGraph']['list']['edges'] 52 | for data in data_list: 53 | node = data['node'] 54 | title = node['post']['title'] 55 | post_date = node['post']['postDate'] 56 | release_time = conversion_time_str(post_date) 57 | source = node['extra']['source']['name'] 58 | link = node['extra']['source']['link'] 59 | links = '无' if not link else link 60 | source = '无' if not source else source 61 | up = node['sense']['up'] 62 | down = node['sense']['down'] 63 | desc = node['post']['desc'] 64 | print( 65 | f'标题: {title}\n发布时间: {release_time}\n来源: {source}\n利好: {up}\n利空: {down}\n原文链接: {links}\n内容: {desc.strip()}') 66 | print('===' * 30) 67 | 68 | page_info = results['data']['articleGraph']['list']['pageInfo'] 69 | has_next_page = page_info['hasNextPage'] 70 | if not has_next_page: 71 | logger.info('已经是最后一页了~~~') 72 | return 73 | next_page_params = page_info['endCursor'] 74 | json_data['variables']['after'] = next_page_params 75 | parse(json_data) 76 | 77 | 78 | if __name__ == '__main__': 79 | json_data = { 80 | 'operationName': 'listFlash', 81 | 'variables': { 82 | 'flashCategory': 'GENERAL', 83 | 'first': 20, 84 | }, 85 | 'query': 'query listFlash($first: Int, $after: String, $showOn7x24h: Boolean, $flashCategory: FlashCategory = GENERAL, $tag: Int, $startTime: Date, $endTime: Date) { articleGraph { list: listFlash(page: {first: $first, after: $after, pattern: CURSOR}, param: {flashCategory: $flashCategory, showOn7x24h: $showOn7x24h, tagId: $tag, startTime: $startTime, endTime: $endTime}) { edges { node { id post { title desc content postDate thumbnail __typename } extra { authorInfo { base { displayName __typename } __typename } source { link name __typename } __typename } ... on Flash { highlight push sense { down up select __typename } __typename } __typename } __typename } pageInfo { hasNextPage totalCount startCursor endCursor __typename } __typename } __typename }}', 86 | } 87 | parse(json_data) 88 | -------------------------------------------------------------------------------- /8btc/docs/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/8btc/docs/1.png -------------------------------------------------------------------------------- /8btc/docs/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/8btc/docs/2.png -------------------------------------------------------------------------------- /8btc/docs/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/8btc/docs/4.png -------------------------------------------------------------------------------- /8btc/docs/readme.md: -------------------------------------------------------------------------------- 1 | ## 巴比特站点爬虫文档 2 | - 网站 [https://www.8btc.com/flash](https://www.8btc.com/flash) 3 | - 爬取的是 `快讯` 模块 4 | 5 | ## 反扒 6 | - 下拉刷新更多,抓包,如下![抓包](1.png) 7 | - 经过多次测试,请求头中的 `authorization` 参数,每次请求都会变化,为必要参数。 8 | 9 | ## `authorization` 的破解 10 | 11 | - 全局搜索该关键字即可定位到关键代码![定位参数生成位置](2.png) 12 | - 下拉,点击 `查看更多`,发现断点生效![参数分析](4.png) 13 | ### device_id 14 | - `device_id` 由 `Object(i.u)(20, 20)` 生成 15 | - 控制台输入 `i.u`,并点击进去,发现如下代码: 16 | ```javascript 17 | function w(e, t) { 18 | for (var n = "", a = t ? Math.round(Math.random() * (t - e)) + e : e, i = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"], r = 0; r < a; r++) { 19 | n += i[Math.round(Math.random() * (i.length - 1))] 20 | } 21 | return n 22 | } 23 | ``` 24 | - 该代码就可以直接生成 `device_id` 参数,且不需要额外的补环境 25 | - 其中参数 e 和 t 都是定值 20 26 | 27 | ### sign 28 | - `sign` 由 `Object(i.d)(c, "WTAHAPPYACTIVITY")` 生成。其中 `i.d` 是函数 `E`,且接收两个参数:`c` 和 `WTAHAPPYACTIVITY` 29 | - 其中 c 为 `'{"appId":"1","timestamp":"1662101940","serverCode":"0"}'` 30 | - i.d 函数,点击进去之后,发现如下代码 31 | ```javascript 32 | function E(e, t) { 33 | var n = { 34 | mode: o.a.mode.ECB, 35 | padding: o.a.pad.Pkcs7 36 | } 37 | , a = o.a.enc.Utf8.parse(t); 38 | return o.a.AES.encrypt(e, a, n).toString().replace(/\//g, "_").replace(/\+/g, "-") 39 | } 40 | ``` 41 | - AES-ECB 模式,Pkcs7 填充方式 -------------------------------------------------------------------------------- /aliwx/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:34 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /aliwx/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:33 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import re 7 | import execjs 8 | import requests 9 | 10 | from loguru import logger 11 | 12 | headers = { 13 | 'authority': 'www.aliwx.com.cn', 14 | 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 15 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36', 16 | } 17 | 18 | 19 | def get_html(): 20 | params = { 21 | 'bid': '6813923', 22 | 'cid': '674259', 23 | } 24 | response = requests.get('https://www.aliwx.com.cn/reader', params=params, headers=headers) 25 | return response.text 26 | 27 | 28 | def get_decrypt_data(encrypt_data): 29 | js_str = ''' 30 | function _decodeCont(t) { 31 | return t = function (t) { 32 | return t.split("").map(function (t) { 33 | var e, i; 34 | return t.match(/[A-Za-z]/) ? (e = Math.floor(t.charCodeAt(0) / 97), 35 | i = (t.toLowerCase().charCodeAt(0) - 83) % 26 || 26, 36 | String.fromCharCode(i + (0 == e ? 64 : 96))) : t 37 | }).join("") 38 | }(t), 39 | function (t) { 40 | var e, i, a, n, r, c, o, s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", d = "", 41 | l = 0; 42 | for (t = t.replace(/[^A-Za-z0-9\+\/\=]/g, ""); l < t.length;) 43 | n = s.indexOf(t.charAt(l++)), 44 | r = s.indexOf(t.charAt(l++)), 45 | c = s.indexOf(t.charAt(l++)), 46 | o = s.indexOf(t.charAt(l++)), 47 | e = n << 2 | r >> 4, 48 | i = (15 & r) << 4 | c >> 2, 49 | a = (3 & c) << 6 | o, 50 | d += String.fromCharCode(e), 51 | 64 != c && (d += String.fromCharCode(i)), 52 | 64 != o && (d += String.fromCharCode(a)); 53 | return function (t) { 54 | for (var e, i = "", a = 0, n = 0, r = 0; a < t.length;) 55 | n = t.charCodeAt(a), 56 | n < 128 ? (i += String.fromCharCode(n), 57 | a++) : n > 191 && n < 224 ? (r = t.charCodeAt(a + 1), 58 | i += String.fromCharCode((31 & n) << 6 | 63 & r), 59 | a += 2) : (r = t.charCodeAt(a + 1), 60 | e = t.charCodeAt(a + 2), 61 | i += String.fromCharCode((15 & n) << 12 | (63 & r) << 6 | 63 & e), 62 | a += 3); 63 | return i 64 | }(d) 65 | }(t) 66 | } 67 | ''' 68 | ctx = execjs.compile(''.join(js_str)) 69 | decrypt_data = ctx.call('_decodeCont', encrypt_data) 70 | return decrypt_data 71 | 72 | 73 | def get_info(): 74 | html = get_html() 75 | a_str = re.findall(re.compile(r'dataChapters">(.*?)', re.S), html)[0] 76 | data_info = str(a_str).replace('"', '"').replace('true', 'True').replace('false', 'False').replace('amp;', '') 77 | item = eval(data_info) # 字符串转字典 78 | data_list = item['chapterList'] 79 | info = { 80 | volumedata['volumeName']: { 81 | # 判断是否为收费章节的条件为 isFreeRead 字段 82 | chapterdata['chapterName']: chapterdata['contUrlSuffix'] if chapterdata['isFreeRead'] else None 83 | for chapterdata in volumedata['volumeList'] 84 | } 85 | for volumedata in data_list 86 | } 87 | return info 88 | 89 | 90 | def get_encrypt_data(): 91 | info = get_info() 92 | for volumeName, item in info.items(): 93 | for chapterName, url_suffix in item.items(): 94 | if url_suffix: 95 | logger.info(f'当前进度: {volumeName}, {chapterName}') 96 | url = f'https://c13.shuqireader.com/pcapi/chapter/contentfree/{url_suffix}' 97 | results = requests.get(url, headers=headers).json() 98 | encrypt_data = results['ChapterContent'] 99 | logger.warning('\n'.join(get_decrypt_data(encrypt_data).split('
'))) 100 | else: 101 | logger.error(f'收费章节: {volumeName}, {chapterName}') 102 | break 103 | 104 | 105 | if __name__ == '__main__': 106 | get_encrypt_data() 107 | -------------------------------------------------------------------------------- /appmiu/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:59 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /appmiu/demo.js: -------------------------------------------------------------------------------- 1 | var h = '富强民主文明和谐自由平等公正法治爱国敬业诚信友善'; 2 | 3 | function e() { 4 | for (var t = arguments.length, n = Array(t), r = 0; r < t; r++) 5 | n[r] = arguments[r]; 6 | var e = n.length 7 | , i = "string" == typeof n[e - 1] ? n[e - 1] : "Assert Error" 8 | , o = !0 9 | , u = !1 10 | , c = void 0; 11 | try { 12 | for (var f, a = n[Symbol.iterator](); !(o = (f = a.next()).done); o = !0) { 13 | if (!f.value) 14 | throw new Error(i) 15 | } 16 | } catch (t) { 17 | u = !0, 18 | c = t 19 | } finally { 20 | try { 21 | !o && a.return && a.return() 22 | } finally { 23 | if (u) 24 | throw c 25 | } 26 | } 27 | } 28 | 29 | function i() { 30 | return Math.random() >= .5 31 | } 32 | 33 | function c(t) { 34 | e("string" == typeof t); 35 | var n = [] 36 | , r = !0 37 | , o = !1 38 | , u = void 0; 39 | try { 40 | for (var c, f = t[Symbol.iterator](); !(r = (c = f.next()).done); r = !0) { 41 | var a = c.value 42 | , s = Number.parseInt(a, 16); 43 | s < 10 ? n.push(s) : i() ? (n.push(10), 44 | n.push(s - 10)) : (n.push(11), 45 | n.push(s - 6)) 46 | } 47 | } catch (t) { 48 | o = !0, 49 | u = t 50 | } finally { 51 | try { 52 | !r && f.return && f.return() 53 | } finally { 54 | if (o) 55 | throw u 56 | } 57 | } 58 | return n 59 | } 60 | 61 | function o(t) { 62 | var n = /[A-Za-z0-9\-\_\.\!\~\*\'\(\)]/g 63 | , r = t.replace(n, function (t) { 64 | return t.codePointAt(0).toString(16) 65 | }); 66 | return encodeURIComponent(r).replace(/%/g, "").toUpperCase() 67 | } 68 | 69 | function a(t) { 70 | return t.map(function (t) { 71 | return h[2 * t] + h[2 * t + 1] 72 | }).join("") 73 | } 74 | 75 | function l(t) { 76 | return a(c(o(t))) 77 | } 78 | 79 | // https://www.appmiu.com/key/ 80 | var key = '1234567', 81 | res = l(key); 82 | console.log(res) -------------------------------------------------------------------------------- /bbs_csdn/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:54 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /bbs_csdn/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:22 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 逆向参数 8 | - 请求头中 X-Ca-Signature 和 X-Ca-Nonce 为必要参数,且缺一不可 9 | 10 | 思路 11 | 全局搜索关键字 X-Ca-Signature 即可定位到关键函数,如下 12 | e.headers["X-Ca-Nonce"] = f(), 13 | "[object FormData]" === Object.prototype.toString.call(e.data) && (e.headers["X-Ca-Signed-Content-Type"] = "multipart/form-data", 14 | e.headers["X-Ca-Signature"] = h({ 15 | method: a, 16 | url: c, 17 | accept: t, 18 | params: d, 19 | date: n, 20 | contentType: i, 21 | headers: e.headers, 22 | appSecret: r 23 | }) 24 | 25 | 在该处下断点,点击下一页,断点即可生效 26 | 其中,生成 X-Ca-Nonce 参数的为 f 函数,且点进去 f 函数,发现 f 函数为一个获取随机uuid的函数。 27 | 28 | 生成 X-Ca-Signature 参数的为 h 函数,接收的参数为一个对象,在该对象中,只有两个参数是变化的,剩下的参数均可为固定 29 | - page参数可变,表示页码 30 | - nonce参数可变,随机生成的uuid 31 | 32 | ''' 33 | 34 | import execjs 35 | import requests 36 | 37 | from loguru import logger 38 | 39 | f = open('demo.js', 'r') 40 | js_str = f.read() 41 | ctx = execjs.compile(''.join(js_str)) 42 | 43 | headers = { 44 | "authority": "bizapi.csdn.net", 45 | "accept": "application/json, text/plain, */*", 46 | "accept-language": "zh-CN,zh;q=0.9", 47 | "origin": "https://bbs.csdn.net", 48 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", 49 | "x-ca-key": "203899271", 50 | "x-ca-signature-headers": "x-ca-key,x-ca-nonce" 51 | } 52 | url = "https://bizapi.csdn.net/community-cloud/v1/colleges/main_page/list" 53 | 54 | global next_page # 计算下一页的页码 55 | 56 | 57 | def get_results(page): 58 | params = { 59 | "deviceType": "pc", 60 | "page": str(page), 61 | "pageSize": "20", 62 | "category": "37", 63 | "sort": "desc", 64 | "type": "2" 65 | } 66 | para_info = ctx.call('get_nonce_signature', page) 67 | logger.info(f'获取到第 {page} 页请求头加密参数: \n{para_info}') 68 | headers['x-ca-nonce'] = para_info['nonce'] 69 | headers['x-ca-signature'] = para_info['signature'] 70 | response = requests.get(url, headers=headers, params=params) 71 | return response.json() 72 | 73 | 74 | def get_data(page): 75 | results = get_results(page) 76 | next_page = page 77 | data_list = results['data']['list'] 78 | for data in data_list: 79 | communityName = data['communityName'] 80 | activeUserNum = data['activeUserNum'] 81 | continueLearningDays = data['continueLearningDays'] 82 | influence = data['influence'] 83 | communityNum = data['communityNum'] 84 | user_list = [user['nickName'] for user in data['userList']] 85 | users = '、'.join(user_list) 86 | print( 87 | f'学校名称: {communityName}\n7日活跃人数: {activeUserNum}\n持续学习天数: {continueLearningDays}\n影响力: {influence}\n成员数量: {communityNum}\n明星成员: {users}') 88 | print('===' * 20) 89 | print('***' * 25) 90 | # 自动获取下一页 91 | total_page = results['data']['totalPages'] 92 | if next_page < total_page: 93 | next_page += 1 94 | get_data(next_page) 95 | 96 | 97 | def main(): 98 | get_data(1) 99 | 100 | 101 | if __name__ == '__main__': 102 | main() 103 | -------------------------------------------------------------------------------- /bmfw/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:34 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /bmfw/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js'); 2 | 3 | var token = '23y0ufFl5YxIyGrI8hWRUZmKkvtSjLQA', 4 | nonce = '123456789abcdefg', 5 | passid = 'zdww'; 6 | 7 | 8 | function get_headers_params(timestamp) { 9 | var zdwwsignature = CryptoJS.SHA256(timestamp + 'fTN2pfuisxTavbTuYVSsNJHetwq5bJvC' + 'QkjjtiLM2dCratiA' + timestamp) 10 | .toString(CryptoJS.enc.Hex) 11 | .toUpperCase(); 12 | return { 13 | 'x-wif-nonce': 'QkjjtiLM2dCratiA', 14 | 'x-wif-paasid': 'smt-application', 15 | 'x-wif-signature': zdwwsignature, 16 | 'x-wif-timestamp': timestamp 17 | } 18 | } 19 | 20 | function generateAjaxParmas(params, timestamp) { 21 | return { 22 | paasHeader: passid, 23 | timestampHeader: timestamp, 24 | nonceHeader: nonce, 25 | signatureHeader: CryptoJS.SHA256(timestamp + token + nonce + timestamp) 26 | .toString(CryptoJS.enc.Hex) 27 | .toUpperCase() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bmfw/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:34 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 网站:http://bmfw.www.gov.cn/hsjcjgcx/index.html?ADTAG=feiyanh5&adcode=440000 8 | 接口:http://bmfw.www.gov.cn/bjww/interface/interfaceJson 9 | 请求方式:post 10 | 需要逆向的参数 11 | -请求头部分,缺一不可 12 | - x-wif-timestamp 长度为10位的时间戳 13 | - x-wif-signature SHA256加密 14 | - x-wif-paasid 定值: `smt-application` 15 | - x-wif-nonce 定值: `QkjjtiLM2dCratiA` 16 | - 请求参数部分,缺一不可 17 | - paasHeader 定值: `zdww` 18 | - timestampHeader 长度为10位的时间戳 19 | - signatureHeader SHA256加密 20 | - nonceHeader 定值: `123456789abcdefg` 21 | 22 | 全局搜索关键字 `signatureHeader`,只有一个js文件,即可定位到加密位置 23 | 24 | 而且,在该js文件中,请求头中的加密参数和发送post请求所携带的参数的加密,都能在该js文件中找到 25 | 26 | 把关键的js代码copy至本地,复现加密逻辑,生成加密参数即可 27 | ''' 28 | 29 | import time 30 | import requests 31 | 32 | from utils import * 33 | 34 | ctx = Utils(js_file_name='demo.js').read_js_file() 35 | 36 | 37 | def get_encrypt_data(params, timestamp): 38 | if params: 39 | return ctx.call('generateAjaxParmas', params, timestamp) 40 | else: 41 | return ctx.call('get_headers_params', timestamp) 42 | 43 | 44 | def get_results(page): 45 | headers = { 46 | 'Accept': 'application/json, text/javascript, */*; q=0.01', 47 | 'Accept-Language': 'zh-CN,zh;q=0.9', 48 | 'Content-Type': 'application/json; charset=UTF-8', 49 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36', 50 | } 51 | json_data = { 52 | "code": "", 53 | "serach_key": "", 54 | "page": page, 55 | "appId": "NcApplication", 56 | "key": "818461bc617bb175b8c2b87d6bf1bb07", 57 | "page_size": "4" 58 | } 59 | ts = str(int(time.time())) 60 | encrypt_header = get_encrypt_data(params=None, timestamp=ts) 61 | headers['x-wif-nonce'] = encrypt_header['x-wif-nonce'] 62 | headers['x-wif-paasid'] = encrypt_header['x-wif-paasid'] 63 | headers['x-wif-signature'] = encrypt_header['x-wif-signature'] 64 | headers['x-wif-timestamp'] = encrypt_header['x-wif-timestamp'] 65 | 66 | encrypt_params = get_encrypt_data(params=json_data, timestamp=ts) 67 | json_data['paasHeader'] = encrypt_params['paasHeader'] 68 | json_data['timestampHeader'] = encrypt_params['timestampHeader'] 69 | json_data['nonceHeader'] = encrypt_params['nonceHeader'] 70 | json_data['signatureHeader'] = encrypt_params['signatureHeader'] 71 | response = requests.post('http://bmfw.www.gov.cn/bjww/interface/interfaceJson', headers=headers, json=json_data, 72 | verify=False) 73 | return response.json() 74 | 75 | 76 | def parse(): 77 | for page in range(1, 10): 78 | res = get_results(page) 79 | data_list = res['data']['list'] 80 | for data in data_list: 81 | name = data['name'] 82 | phone = data['phone'] 83 | address = data['address'] 84 | area_address = data['area_address'] 85 | print(f'机构名称: {name}\n联系电话: {phone}\n所在区县: {area_address}\n机构地址: {address}') 86 | print('===' * 20) 87 | 88 | 89 | if __name__ == '__main__': 90 | parse() 91 | -------------------------------------------------------------------------------- /cas_gench/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:00 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /cas_gench/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:32 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 第一次请求 8 | - 主页 https://cas.gench.edu.cn/cas/login 9 | - get请求,从源码中获取 execution 字段 10 | 11 | 第二次请求 12 | - 登录接口 https://cas.gench.edu.cn/cas/login 13 | - post请求 14 | - params包括 execution、加密后的密码、账户 15 | - 如果不带 execution 的画,请求出来的源码为主页源码,不是接口返回的源码 16 | 17 | 全局搜索关键字 'password' 可在 'login.js' 文件中,找到如下代码: 18 | - result = RSAUtils.encryptedString(key, thisPwd) 19 | result 就是最终加密后的结果 20 | 在该处下断点,进入 RSAUtils.encryptedString 函数中 21 | - 把该文件中的所有js代码复制下来,放在本地运行即可 22 | - 无需进行额外修改 23 | ''' 24 | 25 | import re 26 | import execjs 27 | import requests 28 | 29 | from loguru import logger 30 | 31 | headers = { 32 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", 33 | "Accept-Language": "zh-CN,zh;q=0.9", 34 | "Content-Type": "application/x-www-form-urlencoded", 35 | "Origin": "https://cas.gench.edu.cn", 36 | "Pragma": "no-cache", 37 | "Referer": "https://cas.gench.edu.cn/cas/login", 38 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 39 | } 40 | 41 | f = open('demo.js', 'r') 42 | js_str = f.readlines() 43 | ctx = execjs.compile(''.join(js_str)) 44 | 45 | 46 | def get_results(url): 47 | response = requests.get(url, headers=headers) 48 | return response.text 49 | 50 | 51 | def get_api_status(username, pwd, execution): 52 | url = "https://cas.gench.edu.cn/cas/login" 53 | data = { 54 | "username": username, 55 | "password": pwd, 56 | "execution": execution, 57 | "encrypted": "true", 58 | "_eventId": "submit", 59 | "loginType": "1" 60 | } 61 | response = requests.post(url, headers=headers, data=data) 62 | return response.text 63 | 64 | 65 | def get_execution(): 66 | url = 'https://cas.gench.edu.cn/cas/login' 67 | html = get_results(url) 68 | execution = re.findall(re.compile(r'name="execution".*?value="(.*?)".*?/>', re.S), html)[0] 69 | return execution 70 | 71 | 72 | def main(): 73 | execution = get_execution() 74 | logger.info(f'execution: {execution}') 75 | user_name = 'test_test' 76 | pwd = '123456' 77 | encrypt_pwd = ctx.call('get_encrypt_pwd', pwd) 78 | logger.info(f'密码加密结果: {encrypt_pwd}') 79 | results = get_api_status(user_name, encrypt_pwd, execution) 80 | if '账户或密码不正确' in results: 81 | logger.info(f'登录完成,状态为【账户或密码不正确】') 82 | 83 | 84 | if __name__ == '__main__': 85 | main() 86 | -------------------------------------------------------------------------------- /chacewang/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:19 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /chacewang/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:36 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 对查策网(https://www.chacewang.com/chanye/index#)的响应数据进行解密 8 | 9 | 打xhr断点,一步一步调试 10 | 或者搜索关键字`decrypt(`或者`JSON.parse(`也可以定位到加密位置 11 | 12 | 13 | 已完成: 14 | - 响应数据解密已破解 15 | 16 | 未完成: 17 | - 响应数据中的申报时间字段(start_time、end_time)进行了字体加密,未破解 18 | ''' 19 | 20 | import requests 21 | 22 | from utils import * 23 | 24 | 25 | def get_encrypt_data(page: str): 26 | headers = { 27 | 'authority': 'web.chace-ai.com', 28 | 'accept': 'application/json, text/plain, */*', 29 | 'accept-language': 'zh-CN,zh;q=0.9', 30 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36', 31 | # "authorization": "Bearer xxxxxx" 32 | } 33 | params = { 34 | 'page': page, 35 | 'size': '20', 36 | 'industry': '', 37 | 'area': 'RegisterArea_ZXS_Shanghai', 38 | 'dept': '', 39 | 'partition': '', 40 | 'pe_name': '', 41 | 'currentArea': 'RegisterArea_ZXS_Shanghai', 42 | 'query_date': '0', 43 | 'full_search': '0', 44 | 'sort_type': '0', 45 | } 46 | response = requests.get('https://web.chace-ai.com/api/ccw/project/evaluation/getList/', params=params, 47 | headers=headers) 48 | return response.json() 49 | 50 | 51 | def get_decrypt_data(encrypt_data): 52 | ctx = Utils(js_file_name='demo.js').read_js_file() 53 | return ctx.call('get_decrypt_data', encrypt_data) 54 | 55 | 56 | def parse(): 57 | for page in range(1, 10): 58 | results = get_encrypt_data(str(page)) 59 | encrypt_data = results['data'] 60 | decrypt_data = get_decrypt_data(encrypt_data) 61 | print(decrypt_data) 62 | break 63 | 64 | 65 | if __name__ == '__main__': 66 | parse() 67 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ## changelog version 20230920 2 | 3 | #### 搜狐网(souhu) 4 | 5 | - 经观察,新闻详情页面: https://www.sohu.com/a/611710835_123753) 6 | - 包含的图片链接已经恢复正常,故该项目失效 7 | 8 | #### 福建省公共资源交易-交易信息(ggzyfu_fujian) 9 | 10 | - 获取请求头 `portal-sign` 时 11 | - md5盐值:`3637CB36B2E54A72A7002978D0506CDF` ==> `B3978D054A72A7002063637CCDF6B2E5` 12 | 13 | - 响应数据解密 14 | - AES 15 | - key值: `BE45D593014E4A4EB4449737660876CE` ==> `EB444973714E4A40876CE66BE45D5930` 16 | - iv值: `A8909931867B0425` ==> `B5A8904209931867` 17 | 18 | *** 19 | 20 | ## changelog version 20230630 21 | 22 | #### 查策网(chacewang) 23 | 24 | - 请求头发生变化,解密方式未发生变化 25 | - 添加了登录认证 26 | - 请求头需携带 `authorization` 字段 27 | 28 | #### 新榜资讯-废弃(newrank) 29 | 30 | - 必须登录才能请求到数据 31 | 32 | *** 33 | 34 | ## changelog version 20230328 35 | 36 | #### 易车网(yiche) 37 | 38 | - api接口发生变化 39 | - 原接口 `https://car.yiche.com/web_api/car_model_api/api/v1/car/config_new_param` 40 | - 新接口 `https://mapi.yiche.com/web_api/car_model_api/api/v1/car/config_new_param` 41 | 42 | #### 全国建筑市场监管公共服务平台 (jzsc) 43 | 44 | - api接口变更 45 | - 原接口 `https://jzsc.mohurd.gov.cn/Api/webApi/dataservice/query/comp/list` 46 | - 新接口 `https://jzsc.mohurd.gov.cn/APi/webApi/dataservice/query/comp/list` 47 | - 具体是 `/Api/` 变为 `/APi/`。字母`p`由小写变为大写 48 | 49 | *** 50 | 51 | ## changelog version 20230314 52 | 53 | #### 美食优惠聚合 (waitpay) 54 | 55 | - 网站停止维护 56 | - 主页: [https://static.waitwaitpay.com/web/sd_se/index.html#/](https://static.waitwaitpay.com/web/sd_se/index.html#/) 57 | 58 | #### 中国招投标公告服务中心 (ctbpsp) 59 | 60 | - 对响应数据进行解密的js进行变更 61 | - 原代码 `var keyHex = CryptoJS.enc.Utf8.parse("ctpstp@custominfo!@#qweASD");` 62 | - 新代码 `var keyHex = CryptoJS.enc.Utf8.parse("1qaz@wsx3e");` 63 | 64 | #### 中国·国家地名信息库 (dmfw_mca) 65 | 66 | - api接口变更 67 | - 原接口 `https://dmfw.mca.gov.cn/9095/stname/list` 68 | - 新接口 `https://dmfw.mca.gov.cn/stname/listPub` 69 | 70 | - 响应数据变更 71 | - 原接口 https://dmfw.mca.gov.cn/9095/stname/list 响应数据为密文,需要解密 72 | - 新接口 https://dmfw.mca.gov.cn/stname/listPub 响应数据为明文 73 | 74 | #### 全国建筑市场监管公共服务平台 (jzsc) 75 | 76 | - api接口变更 77 | - 原接口 `http://jzsc.mohurd.gov.cn/api/webApi/dataservice/query/comp/list` 78 | - 新接口 `https://jzsc.mohurd.gov.cn/Api/webApi/dataservice/query/comp/list` 79 | 80 | #### 黑猫投诉 (tousu_sign) 81 | 82 | - 部分字段的解析规则发生变化 83 | -------------------------------------------------------------------------------- /chrome.md: -------------------------------------------------------------------------------- 1 | ## 更改chrome设置,使source面板显示具体行号 2 | 3 | - 修改前 4 | - 左侧栏不显示行号 5 | - ![origin_google](images/origin_chrome.png) 6 | 7 | *** 8 | 9 | - 修改后 10 | - ![fix_origin_google](images/fix_origin_chrome.png) 11 | 12 | *** 13 | 14 | > 步骤 15 | 16 | - 点击控制台中的设置按钮 17 | - ![setting_button](images/setting_button.png) 18 | 19 | - 在显示出来的设置页面,取消勾选 `Experiments` 设置下的 `Automatically pretty print in the Sources Pabel` 即可 20 | - ![setting](images/setting.png) -------------------------------------------------------------------------------- /chromedriver.md: -------------------------------------------------------------------------------- 1 | ### 关于配置 `chromedriver` 环境 2 | 3 | 1. 在 `chrome` 浏览器上确认浏览器的环境 ![chrome版本](images/chrome_version.png) 4 | 2. 在 [http://chromedriver.storage.googleapis.com/index.html](http://chromedriver.storage.googleapis.com/index.html) 5 | 里,找到对应的 `chromedriver` 版本 ![chromedriver版本](images/chromedriver_version.png) 6 | 3. 下载该`chromedriver` 版本,并在使用selenium时,指定该驱动的路径即可,如下: 7 | ```@python 8 | driver = webdriver.Chrome(executable_path=f'{os.path.abspath(os.path.dirname(os.getcwd()))}/driver_path/chromedriver',options=option) 9 | ``` 10 | -------------------------------------------------------------------------------- /cnpub/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:35 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /cnpub/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js'); 2 | 3 | var e1 = '16weizifuchuan16', 4 | i1 = '1suibianshurude6'; 5 | 6 | function get_decrypt_data(t) { 7 | var s = CryptoJS["enc"].Utf8.parse(e1), 8 | n = CryptoJS["enc"].Utf8.parse(i1), 9 | o = CryptoJS["AES"].decrypt(CryptoJS["format"].Hex.parse(t), s, { 10 | iv: n, 11 | mode: CryptoJS["mode"].CBC, 12 | padding: CryptoJS["pad"].Pkcs7 13 | }); 14 | return JSON.parse(CryptoJS["enc"].Utf8.stringify(o).toString()) 15 | } 16 | 17 | function get_encrypt_params(para) { 18 | var s = CryptoJS["enc"].Utf8.parse(e1), 19 | n = CryptoJS["enc"].Utf8.parse(i1), 20 | o = CryptoJS["enc"].Utf8.parse(JSON.stringify(para)), 21 | c = CryptoJS["AES"].encrypt(o, s, { 22 | iv: n, 23 | mode: CryptoJS["mode"].CBC, 24 | padding: CryptoJS["pad"].Pkcs7 25 | }); 26 | return c.ciphertext.toString() 27 | } 28 | 29 | var encrypt_data = { 30 | "newsType": 1, 31 | "pageNum": 6, 32 | "pageSize": 10, 33 | "title": "" 34 | }, 35 | decrypt_data = get_encrypt_params(encrypt_data); 36 | console.log(decrypt_data) 37 | -------------------------------------------------------------------------------- /cnpub/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:46 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 标准aes加密解密 8 | ''' 9 | 10 | import execjs 11 | import requests 12 | 13 | from loguru import logger 14 | 15 | headers = { 16 | "Accept": "application/json, text/plain, */*", 17 | "Accept-Language": "zh-CN,zh;q=0.9", 18 | "Content-Type": "application/json;charset=UTF-8", 19 | "Origin": "https://cnpub.com.cn", 20 | "Referer": "https://cnpub.com.cn/information.html", 21 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", 22 | } 23 | url = "https://cnpub.com.cn/prod-api/api/index/newsList" 24 | 25 | f = open('demo.js', 'r', encoding='utf8') 26 | js_str = f.read() 27 | ctx = execjs.compile(''.join(js_str)) 28 | 29 | 30 | def get_para_data(para, encrypt_data): 31 | if para: 32 | return ctx.call('get_encrypt_params', para) 33 | return ctx.call('get_decrypt_data', encrypt_data) 34 | 35 | 36 | def get_results(page): 37 | para = { 38 | "newsType": 1, 39 | "pageNum": page, 40 | "pageSize": 10, 41 | "title": "" 42 | } 43 | data = get_para_data(para=para, encrypt_data=None) 44 | logger.info(f'第 {page} 页加密参数: {data}') 45 | response = requests.post(url, headers=headers, data=data) 46 | return str(response.text).strip('"') 47 | 48 | 49 | def parse_data(page): 50 | encrypt_data = get_results(page) 51 | decrypt_data = get_para_data(para=None, encrypt_data=encrypt_data) 52 | rows = decrypt_data['list']['rows'] 53 | for row in rows: 54 | title = row['title'] 55 | author = row['author'] 56 | origin = row['platformName'] 57 | update_time = row['publishTime'] 58 | print(f'标题: {title}\n作者: {author}\n出自: {origin}\n更新时间: {update_time}') 59 | print('***' * 25) 60 | 61 | 62 | def main(): 63 | for page in range(1, 10): 64 | parse_data(page) 65 | print('===' * 30) 66 | 67 | 68 | if __name__ == '__main__': 69 | main() 70 | -------------------------------------------------------------------------------- /cpws/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:56 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /cpws/login.js: -------------------------------------------------------------------------------- 1 | window = global; 2 | var JSEncrypt = require('jsencrypt') 3 | 4 | 5 | function encrypt_pwd(e) { 6 | var t = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5GVku07yXCndaMS1evPIPyWwhbdWMVRqL4qg4OsKbzyTGmV4YkG8H0hwwrFLuPhqC5tL136aaizuL/lN5DRRbePct6syILOLLCBJ5J5rQyGr00l1zQvdNKYp4tT5EFlqw8tlPkibcsd5Ecc8sTYa77HxNeIa6DRuObC5H9t85ALJyDVZC3Y4ES/u61Q7LDnB3kG9MnXJsJiQxm1pLkE7Zfxy29d5JaXbbfwhCDSjE4+dUQoq2MVIt2qVjZSo5Hd/bAFGU1Lmc7GkFeLiLjNTOfECF52ms/dks92Wx/glfRuK4h/fcxtGB4Q2VXu5k68e/2uojs6jnFsMKVe+FVUDkQIDAQAB"; 7 | var o = new JSEncrypt; 8 | o.setPublicKey(t); 9 | return encodeURIComponent(o.encrypt(e)) 10 | } 11 | 12 | var pwd = encrypt_pwd('123456') 13 | console.log(pwd) -------------------------------------------------------------------------------- /cpws/login.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:20 上午 3 | # @File: login.py 4 | # @Author: liyf 5 | 6 | import requests 7 | 8 | from utils import * 9 | 10 | ctx = Utils(js_file_name='login.js').read_js_file() 11 | 12 | 13 | def get_login_res(username, pwd): 14 | headers = { 15 | 'Accept': '*/*', 16 | 'Accept-Language': 'zh-CN,zh;q=0.9', 17 | 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 18 | 'Origin': 'https://account.court.gov.cn', 19 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36', 20 | 'X-Requested-With': 'XMLHttpRequest', 21 | } 22 | encrypt_pwd = ctx.call('encrypt_pwd', pwd) 23 | data = { 24 | 'username': username, 25 | 'password': encrypt_pwd, 26 | 'appDomain': 'wenshu.court.gov.cn', 27 | } 28 | response = requests.post('https://account.court.gov.cn/api/login', headers=headers, data=data) 29 | return response.json() 30 | 31 | 32 | def main(): 33 | user = '1234567890' 34 | pwd = '123456' 35 | login_res = get_login_res(user, pwd) 36 | logger.info(f'登录结果如下:\n{login_res}') # {'code': '999999', 'data': None, 'message': '账户格式不正确', 'success': False} 37 | msg = login_res['message'] 38 | logger.info(f'登录状态: {msg}') # 登录状态: 账户格式不正确 39 | 40 | 41 | if __name__ == '__main__': 42 | main() 43 | -------------------------------------------------------------------------------- /ctbpsp/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:53 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /ctbpsp/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js'); 2 | 3 | function decryptByDES(ciphertext) { 4 | // todo changelog20230314 5 | // 更改了key 6 | // ctpstp@custominfo!@#qweASD 变为了 1qaz@wsx3e 7 | 8 | // var keyHex = CryptoJS.enc.Utf8.parse("ctpstp@custominfo!@#qweASD"); 9 | var keyHex = CryptoJS.enc.Utf8.parse("1qaz@wsx3e"); 10 | // direct decrypt ciphertext 11 | var decrypted = CryptoJS.DES.decrypt( 12 | { 13 | ciphertext: CryptoJS.enc.Base64.parse(ciphertext), 14 | }, 15 | keyHex, 16 | { 17 | mode: CryptoJS.mode.ECB, 18 | padding: CryptoJS.pad.Pkcs7, 19 | } 20 | ); 21 | return decrypted.toString(CryptoJS.enc.Utf8); 22 | } -------------------------------------------------------------------------------- /ctbpsp/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:53 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import json 7 | import requests 8 | 9 | from utils import * 10 | 11 | 12 | def get_decrypt_data(encrypt_data): 13 | ctx = Utils(js_file_name='demo.js').read_js_file() 14 | return json.loads(ctx.call('decryptByDES', encrypt_data)) 15 | 16 | 17 | def get_results(page): 18 | headers = { 19 | 'Accept': 'application/json, text/plain, */*', 20 | 'Accept-Language': 'zh-CN,zh;q=0.9', 21 | 'Cache-Control': 'no-cache', 22 | 'Connection': 'keep-alive', 23 | 'Origin': 'http://ctbpsp.com', 24 | 'Referer': 'http://ctbpsp.com/', 25 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36', 26 | } 27 | 28 | response = requests.get( 29 | f'https://custominfo.cebpubservice.com/cutominfoapi/recommand/type/5/pagesize/10/currentpage/{page}', 30 | headers=headers) 31 | return response.text 32 | 33 | 34 | def parse(): 35 | for page in range(1, 31): 36 | encrypt_data = get_results(page) 37 | # solve error: execjs._exceptions.ProgramError: Error: Malformed UTF-8 data 38 | # 把返回的加密数据进行strip('"')操作 39 | decrypt_data = get_decrypt_data(encrypt_data.strip('"')) 40 | data_list = decrypt_data['data']['dataList'] 41 | for data in data_list: 42 | title = data['noticeName'] 43 | province = data['reginProvince'] 44 | bulletin_type = data['bulletinTypeName'] 45 | accept_time = data['noticeSendTime'] 46 | uuid = data['bulletinID'] 47 | detail_url = f'http://ctbpsp.com/#/bulletinDetail?uuid={uuid}&inpvalue=&dataSource=0' 48 | print(f'标题: {title}\n公告类型: {bulletin_type}\n省份: {province}\n接收时间: {accept_time}\n详情url地址: {detail_url}') 49 | print('===' * 30) 50 | 51 | 52 | if __name__ == '__main__': 53 | parse() 54 | -------------------------------------------------------------------------------- /ctyun/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:15 下午 3 | # @File: __init__.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /ctyun/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js'), 2 | // Object(u["c"] 3 | T = function (e) { 4 | var n = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "" 5 | , t = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {} 6 | , a = t.enc 7 | , r = void 0 === a ? "Utf8" : a 8 | , c = t.mode 9 | , i = void 0 === c ? "ECB" : c 10 | , o = t.padding 11 | , u = void 0 === o ? "Pkcs7" : o 12 | , d = CryptoJS.enc[r].parse(n) 13 | , l = { 14 | mode: CryptoJS.mode[i], 15 | padding: CryptoJS.pad[u] 16 | } 17 | , s = CryptoJS.TripleDES.encrypt(e, d, l); 18 | return s.toString() 19 | }, 20 | // Object(u["f"]) 21 | F = function (e) { 22 | var n = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; 23 | if (e && "string" === typeof e) { 24 | var t = n.text || "0" 25 | , a = n.length || 24; 26 | if (e.length < a) 27 | for (var r = e.length; r < a; r++) 28 | e += t; 29 | else 30 | e = e.substring(0, a); 31 | return e 32 | } 33 | }; 34 | 35 | //password: encodeURI(Object(u["c"])(s.value, Object(u["f"])(Object(u["g"])(r.value)))) 36 | function get_pwd(pwd, username) { 37 | return encodeURI(T(pwd, F(username))) 38 | } 39 | 40 | var pwd = '123456', 41 | username = 'liyufeng123', 42 | enc_pwd = get_pwd(pwd, username); 43 | console.log(enc_pwd) 44 | -------------------------------------------------------------------------------- /dewu/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:21 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /dewu/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:21 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | """ 7 | todo: https://m.poizon.com/router/ 8 | 破解得物产品列表页中请求参数 `sign` 9 | 接口: https://app.poizon.com/api/v1/h5/index/fire/index 10 | - POST请求 11 | - params中 `sign` 需要破解 12 | 通过搜索关键字 `sign:` 可以定位到加密函数在 `index.7cee99cc.js`文件第9296行,如下: 13 | todo``` 14 | var n = C(e.params); 15 | return e.params = L({ 16 | sign: n 17 | }, e.params), 18 | ``` 19 | 其中 `C(e.params)` 就是生成sign的入口,且e.params=发送post请求需要的参数。 20 | 接着就是常规操作,下断点,进入该函数之后,看下该函数做了什么操作,然后实行 `缺啥补啥` 的准则,扣js代码。 21 | """ 22 | 23 | import requests 24 | 25 | from utils import * 26 | 27 | 28 | def get_sign(page): 29 | ctx = Utils(js_file_name='demo.js').read_js_file() 30 | return ctx.call('get_sign', page) 31 | 32 | 33 | def get_results(page): 34 | headers = { 35 | 'Accept': 'application/json, text/plain, */*', 36 | 'Accept-Language': 'zh-CN,zh;q=0.9', 37 | 'Origin': 'https://m.poizon.com', 38 | 'Referer': 'https://m.poizon.com/', 39 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36', 40 | } 41 | sign = get_sign(page) 42 | logger.info(f'第 {page} 页: {sign}') 43 | json_data = { 44 | 'sign': sign, 45 | 'tabId': '', 46 | 'limit': 20, 47 | 'lastId': page, 48 | 'platform': 'h5', 49 | 'version': '4.73.0', 50 | 'isVisitor': False, 51 | 'newAdvForH5': True, 52 | } 53 | 54 | response = requests.post('https://app.poizon.com/api/v1/h5/index/fire/index', headers=headers, json=json_data) 55 | return response.json() 56 | 57 | 58 | def parse(): 59 | for page in range(1, 10): 60 | results = get_results(page) 61 | data_list = results['data']['hotList'] 62 | for data in data_list: 63 | product = data['product'] 64 | title = product['title'] 65 | soldCountText = product['soldCountText'] 66 | price = int(product['price']) / 100 67 | logoUrl = product['logoUrl'] 68 | print(f'产品名称: {title}\n价格: {price}\n销量: {soldCountText}\n图片地址: {logoUrl}') 69 | print('===' * 35) 70 | 71 | 72 | if __name__ == '__main__': 73 | parse() 74 | -------------------------------------------------------------------------------- /didiwaimai/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:56 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /didiwaimai/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:45 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 主页: https://passport.didichuxing.com/#/ 8 | 接口: https://epassport.diditaxi.com.cn/passport/login/v5/signInByPassword?wsgsig=xxx 9 | - get请求 10 | - 需要破解 `wsgsig` 参数 11 | todo 破解流程 12 | - 直接通过全局搜索关键字 `wsgsig` 可以直接定位到加密位置,如下 13 | - `wsgsig: E.a.getSign.apply(E.a, e)` 14 | - 在此处下断点,并点击登录。断点生效,说明此处为加密位置 15 | 16 | - 通过格式可以判断出,该参数的加密大概率是webpack,所以在该处往上查找 `E` 的定义,找到如下代码 17 | - `O = n("Yt3Z") 18 | , E = n.n(O);` 19 | - 从而确定该加密为webpack 20 | 21 | - 所以老老实实的找分发器,并扣所需要的模块 22 | - 在 `O = n("Yt3Z")` 处下断点,重新刷新页面,断点即可生效,在控制台输入 `n`,即为分发器,复制下来即可 23 | - 所需要的模块只有两个,分别为 `Yt3Z` 和 `3IRH` 24 | 25 | - 封装js代码,使入口函数返回值为 `wsgsig` 即可,带入到python代码中测试 26 | - 测试结果,当传入的账号和密码分别为 `16677882222` 和 `123456` 时,接口返回的结果如下: 27 | - ` 28 | {'errno': 51003, 'error': '用户信息不存在', 'requestid': '1673860276422932612', 'traceid': '0a22221b63c514b4950e7b955d141b02', 'time': '2023-01-16 17:11:16'} 29 | ` 30 | - 跟网页上的返回结果一致,验证成功! 31 | 32 | - 难度,入门 33 | ''' 34 | import requests 35 | 36 | from utils import * 37 | 38 | 39 | def get_wsgsig(data): 40 | ctx = Utils(js_file_name='demo.js').read_js_file() 41 | return ctx.call('get_wsgsig', data) 42 | 43 | 44 | def get_results(username, pwd): 45 | """ 46 | 获取接口返回信息 47 | :param username: 明文账号 48 | :param pwd: 明文密码 49 | :return: 响应结果 50 | """ 51 | headers = { 52 | 'Accept': 'application/json, text/plain, */*', 53 | 'Accept-Language': 'zh-CN,zh;q=0.9', 54 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36', 55 | } 56 | data = { 57 | 'q': '{"domain":"https://epassport.diditaxi.com.cn","role":13,"appid":50001,"source":70001,"api_version":"1.0.1","lang":"zh-CN","imei":"cef8ea1124037639533c070c708e672d","cell":"%s","country_calling_code":"+86","country_id":156,"password":"%s"}' % ( 58 | username, pwd), 59 | } 60 | wsgsig = get_wsgsig(data) 61 | logger.info(f'wsgsig: {wsgsig}') 62 | params = { 63 | 'wsgsig': wsgsig, 64 | } 65 | response = requests.post( 66 | 'https://epassport.diditaxi.com.cn/passport/login/v5/signInByPassword', 67 | params=params, 68 | headers=headers, 69 | data=data, 70 | ) 71 | return response.json() 72 | 73 | 74 | if __name__ == '__main__': 75 | results = get_results('16677882222', '123456') 76 | logger.info(f'接口响应结果:\n{results}') 77 | logger.info(f'账号信息: {results["error"]}') 78 | -------------------------------------------------------------------------------- /dmfw_mca/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:05 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /dmfw_mca/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js'); 2 | 3 | function decryptByDES(ciphertext, key) { 4 | var keyHex = CryptoJS.enc.Utf8.parse(key); 5 | var decrypted = CryptoJS.DES.decrypt({ 6 | ciphertext: CryptoJS.enc.Base64.parse(ciphertext) 7 | }, keyHex, { 8 | mode: CryptoJS.mode.ECB, 9 | padding: CryptoJS.pad.ZeroPadding 10 | }); 11 | var data = decrypted.toString(CryptoJS.enc.Utf8); 12 | var lastNum = data.lastIndexOf("}"); 13 | data = JSON.parse(data.substring(0, lastNum + 1)); 14 | return data; 15 | } -------------------------------------------------------------------------------- /dmfw_mca/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:18 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | todo changelog 20230314 8 | 接口变更 9 | - https://dmfw.mca.gov.cn/9095/stname/list 改变为 https://dmfw.mca.gov.cn/stname/listPub 10 | - 请求参数不变和请求方法都不变 11 | 响应数据变更 12 | - 原接口 https://dmfw.mca.gov.cn/9095/stname/list 响应数据为密文,需要解密 13 | - 新接口 https://dmfw.mca.gov.cn/stname/listPub 响应数据为明文 14 | 15 | ''' 16 | import requests 17 | 18 | headers = { 19 | 'Accept': '*/*', 20 | 'Accept-Language': 'zh-CN,zh;q=0.9', 21 | 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 22 | 'Origin': 'https://dmfw.mca.gov.cn', 23 | 'Referer': 'https://dmfw.mca.gov.cn/online/map.html', 24 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36', 25 | 'X-Requested-With': 'XMLHttpRequest', 26 | } 27 | 28 | 29 | def get_results(keyword): 30 | data = { 31 | 'type': 'place', 32 | 'stName': keyword, 33 | 'placeTypeCode': '', 34 | 'placeTypeCodeLen': '0', 35 | 'code': '', 36 | 'adminCodeLen': '0', 37 | 'year': '2022', 38 | 'searchType': '模糊', 39 | 'page': '1', 40 | 'size': '10', 41 | } 42 | response = requests.post('https://dmfw.mca.gov.cn/stname/listPub', headers=headers, data=data) 43 | return response.json() 44 | 45 | 46 | def parse(): 47 | while True: 48 | keyword = input('请输入关键字:') 49 | results = get_results(keyword) 50 | records = results['records'] 51 | if not records: 52 | print(f'该关键字 (`{keyword}`) 下没有数据') 53 | print(f'===' * 20) 54 | for record in records: 55 | title = record['standard_name'] 56 | province = record['province_name'] 57 | city = record['city_name'] 58 | area_name = record['area_name'] 59 | pca = f'{province}-{city}-{area_name}' 60 | place_type = record['place_type'] 61 | print(f'搜索关键字: {keyword}\n标准名称: {title}\n地址: {pca}\n地区所属类型: {place_type}') 62 | print('===' * 20) 63 | 64 | 65 | if __name__ == '__main__': 66 | parse() 67 | -------------------------------------------------------------------------------- /driver_path/chromedriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/driver_path/chromedriver -------------------------------------------------------------------------------- /ehsy/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:50 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /ehsy/demo.js: -------------------------------------------------------------------------------- 1 | /* 2 | 全局搜索请求头关键字 'ehsy-verify' 3 | 搜索结果只有一个,代码如下: 4 | "ehsy-verify": (0, o.aes_gobal)() 5 | 在该处下断点。下拉页面,断点生效。 6 | 7 | - 进入该函数内部,可定位到请求头参数生成的具体逻辑 8 | 9 | todo 逻辑如下 10 | - 生成一个长度为10的时间戳,并转字符串 t 11 | - 对该时间戳 t 进行md5加密得到n 12 | - 对 n 进行一系列数组操作 13 | - n.splice(2, 1, "e"),意思是在索引为2的位置删除一个元素,并添加新元素 'e' 14 | - 之后再把新数组转字符串,并加上最开始的时间戳 t。作为aes待加密的数据 15 | - aes的key就是对字符串 GvcaHhBsKa9kkHmf 进行md5加密 16 | - 最终返回的至就是请求头的值 17 | */ 18 | 19 | 20 | var CryptoJS = require('crypto-js'); 21 | 22 | function g(e) { 23 | var n = CryptoJS.enc.Utf8.parse(e) 24 | , i = CryptoJS.MD5('GvcaHhBsKa9kkHmf') 25 | , o = CryptoJS.AES.encrypt(n, i, { 26 | mode: CryptoJS.mode.ECB, 27 | padding: CryptoJS.pad.Pkcs7 28 | }); 29 | return o.toString() 30 | } 31 | 32 | function p() { 33 | var n, i, o, t = ((new Date).getTime() + "").slice(0, 10); 34 | var e = CryptoJS.MD5(t).toString(); 35 | return n = e.split(""), 36 | n.splice(2, 1, "e"), 37 | n.splice(6, 1, "h"), 38 | n.splice(12, 1, 6), 39 | n.splice(25, 1, "b"), 40 | i = n.join("") + t, 41 | o = g(i), 42 | o 43 | } 44 | -------------------------------------------------------------------------------- /ehsy/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:50 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import execjs 7 | import requests 8 | 9 | from loguru import logger 10 | 11 | headers = { 12 | "Accept": "*/*", 13 | "Accept-Language": "zh-CN,zh;q=0.9", 14 | "Cache-Control": "no-cache", 15 | "Connection": "keep-alive", 16 | "Origin": "https://m.ehsy.com", 17 | "Pragma": "no-cache", 18 | "Referer": "https://m.ehsy.com/", 19 | "Sec-Fetch-Dest": "empty", 20 | "Sec-Fetch-Mode": "cors", 21 | "Sec-Fetch-Site": "same-site", 22 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 23 | "content-type": "application/x-www-form-urlencoded", 24 | } 25 | 26 | url = "https://m2.ehsy.com/pb/product/search/filter" 27 | f = open('demo.js', 'r') 28 | js_str = f.readlines() 29 | ctx = execjs.compile(''.join(js_str)) 30 | 31 | 32 | def get_results(start): 33 | data = { 34 | "search": "{'catId':'16474','filterFieldsValues':{},'filters':{}}", 35 | "flag": "true", 36 | "sortType": "0", 37 | "start": start, 38 | "rows": "20", 39 | "cityId": "321", 40 | "token": "", 41 | "createFrom": "m" 42 | } 43 | ehsy_verify = ctx.call('p') 44 | logger.info(f'ehsy_verify: {ehsy_verify}') 45 | headers['ehsy-verify'] = ehsy_verify 46 | response = requests.post(url, headers=headers, data=data) 47 | return response.json() 48 | 49 | 50 | def main(): 51 | for start in range(0, 200, 20): 52 | results = get_results(start) 53 | data_list = results['data']['queryPage']['data'] 54 | for data in data_list: 55 | title = data['productName'] 56 | brand = data['brandName'] 57 | sku_code = data['skuCode'] 58 | sale = data['salePrice'] 59 | print(f'名称: {title}\n品牌型号: {brand}\n订货号: {sku_code}\n含税: {sale}') 60 | print('=====' * 15) 61 | 62 | 63 | if __name__ == '__main__': 64 | main() 65 | -------------------------------------------------------------------------------- /endata/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:33 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /endata/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:42 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | import json 6 | import requests 7 | 8 | from utils import * 9 | 10 | 11 | def get_results(params): 12 | headers = { 13 | 'Accept': 'text/plain, */*; q=0.01', 14 | 'Accept-Language': 'zh-CN,zh;q=0.9', 15 | 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 16 | 'Origin': 'https://www.endata.com.cn', 17 | 'Pragma': 'no-cache', 18 | 'Sec-Fetch-Dest': 'empty', 19 | 'Sec-Fetch-Mode': 'cors', 20 | 'Sec-Fetch-Site': 'same-origin', 21 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36', 22 | 'X-Requested-With': 'XMLHttpRequest', 23 | 'sec-ch-ua': '"Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"', 24 | 'sec-ch-ua-mobile': '?0', 25 | 'sec-ch-ua-platform': '"macOS"', 26 | } 27 | 28 | data = { 29 | 'startTime': params, 30 | 'MethodName': 'BoxOffice_GetMonthBox', 31 | } 32 | 33 | response = requests.post('https://www.endata.com.cn/API/GetData.ashx', headers=headers, data=data) 34 | return response.text 35 | 36 | 37 | def get_decrypt_data(encrypt_data): 38 | ctx = Utils(js_file_name='demo.js').read_js_file() 39 | return ctx.call('webInstace.shell', encrypt_data) 40 | 41 | 42 | def parse(): 43 | time_list = ['2021-12-01', '2022-01-01', '2022-02-01', '2022-03-01', '2022-04-01', '2022-05-01', '2022-06-01', 44 | '2022-07-01', '2022-08-01', '2022-09-01'] 45 | for params in time_list: 46 | results = get_results(params) 47 | decrypt_data = json.loads(get_decrypt_data(results)) 48 | data_list = decrypt_data['Data']['Table'] 49 | ymd_list = params.split('-') 50 | logger.info(f'{ymd_list[0]} 年 {ymd_list[1]} 月份票房数据如下:') 51 | for data in data_list: 52 | ranking = data['Irank'] 53 | m_name = data['MovieName'] 54 | r_time = data['releaseTime'] 55 | boxoffice = data['boxoffice'] 56 | avgboxoffice = data['avgboxoffice'] 57 | avgshowcount = data['avgshowcount'] 58 | box_pro = data['box_pro'] 59 | detail_url = f'https://www.endata.com.cn/BoxOffice/MovieStock/movieShow.html?id={data["EnMovieID"]}' 60 | print( 61 | f'排序: {ranking}\n电影名称: {m_name}\n上映时间: {r_time}\n单月票房(万): {boxoffice}\n平均票价: {avgboxoffice}\n场均人次: {avgshowcount}\n月度占比: {box_pro}%\n详情地址: {detail_url}') 62 | print('===' * 30) 63 | 64 | 65 | if __name__ == '__main__': 66 | parse() 67 | -------------------------------------------------------------------------------- /fenbi/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:24 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /fenbi/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:24 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 粉笔网登录破解 - https://fenbi.com/page/home 8 | 简单的RAS加密 9 | ''' 10 | import requests 11 | 12 | from utils import * 13 | 14 | 15 | def get_js_pwd(password): 16 | ctx = Utils(js_file_name='demo.js').read_js_file() 17 | return ctx.call('get_password', password) 18 | 19 | 20 | def get_json_data(user, pwd): 21 | headers = { 22 | 'Accept': 'application/json, text/plain, */*', 23 | 'Accept-Language': 'zh-CN,zh;q=0.9', 24 | 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 25 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36', 26 | } 27 | 28 | params = { 29 | 'kav': '12', 30 | 'app': 'web', 31 | } 32 | data = { 33 | 'password': get_js_pwd(pwd), 34 | 'persistent': 'true', 35 | 'app': 'web', 36 | 'phone': user, 37 | } 38 | response = requests.post('https://login.fenbi.com/api/users/loginV2?kav=12&app=web&av=80', params=params, 39 | headers=headers, data=data) 40 | return response.json() 41 | 42 | 43 | def main(): 44 | # user = input('请输入账号:') 45 | # pwd = input('请输入密码:') 46 | user = '1234567890' 47 | pwd = '111111' 48 | results = get_json_data(user, pwd) 49 | print(results) 50 | 51 | 52 | if __name__ == '__main__': 53 | # https://fenbi.com/page/home 54 | main() 55 | -------------------------------------------------------------------------------- /ggzyfw_fujian/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:30 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /ggzyfw_fujian/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js') 2 | 3 | function b(e) { 4 | var t = CryptoJS.enc.Utf8.parse('EB444973714E4A40876CE66BE45D5930') 5 | , n = CryptoJS.enc.Utf8.parse('B5A8904209931867') 6 | , a = CryptoJS.AES.decrypt(e, t, { 7 | iv: n, 8 | mode: CryptoJS.mode.CBC, 9 | padding: CryptoJS.pad.Pkcs7 10 | }); 11 | return a.toString(CryptoJS.enc.Utf8) 12 | } -------------------------------------------------------------------------------- /ggzyfw_fujian/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:30 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | changelog 20221018 8 | 加密方法没有变化,只是post请求的接口url地址发生变化 9 | 变化前的接口: https://ggzyfw.fujian.gov.cn/Trade/TradeInfo 10 | 变化后的接口: https://ggzyfw.fujian.gov.cn/FwPortalApi/Trade/TradeInfo 11 | ************************************************************** 12 | 13 | changelog 20220818 14 | todo: https://ggzyfw.fujian.gov.cn/web/index.html#/business/list 15 | 该网站需要破解两处加密 16 | 1. 请求头 `portal-sign` 破解 17 | portal-sign 是通过对请求参数的一些操作之后,合并成一串字符串,然后对这个字符串进行md5加密 18 | 2. 返回数据解密 19 | - 由于是需要对接口返回的值进行解密 20 | - 所以通过搜索关键字 `decrypt(` 定位到解密函数在 `app.3cebabfd.js` 文件中,在返回值处下断点,点击下一页,断点生效 21 | function b(e) { 22 | var t = CryptoJS.enc.Utf8.parse('BE45D593014E4A4EB4449737660876CE') 23 | , n = CryptoJS.enc.Utf8.parse('A8909931867B0425') 24 | , a = CryptoJS.AES.decrypt(e, t, { 25 | iv: n, 26 | mode: CryptoJS.mode.CBC, 27 | padding: CryptoJS.pad.Pkcs7 28 | }); 29 | return a.toString(CryptoJS.enc.Utf8) 30 | } 31 | - 在控制台输出 a.toString(CryptoJS.enc.Utf8),为明文数据。 32 | - AES-CBC模式,Pkcs7填充方式 33 | ''' 34 | 35 | import time 36 | import json 37 | import js2py 38 | import requests 39 | 40 | from utils import * 41 | 42 | 43 | def get_n(params): 44 | js_str = ''' 45 | function l(e, t) { 46 | return e.toString().toUpperCase() > t.toString().toUpperCase() ? 1 : e.toString().toUpperCase() == t.toString().toUpperCase() ? 0 : -1 47 | } 48 | 49 | function s(e) { 50 | for (var t = Object.keys(e).sort(l), n = "", a = 0; a < t.length; a++) 51 | if (void 0 !== e[t[a]]) 52 | if (e[t[a]] && e[t[a]] instanceof Object || e[t[a]] instanceof Array) { 53 | var c = JSON.stringify(e[t[a]]); 54 | n += t[a] + c 55 | } else 56 | n += t[a] + e[t[a]]; 57 | return n 58 | } 59 | 60 | function get_n(e) { 61 | for (var t in e) 62 | "" !== e[t] && void 0 !== e[t] || delete e[t]; 63 | var n = 'B3978D054A72A7002063637CCDF6B2E5' + s(e); 64 | return n 65 | } 66 | ''' 67 | context = js2py.EvalJs() 68 | context.execute(js_str) 69 | n = context.get_n(params) 70 | return n 71 | 72 | 73 | def get_data(Data): 74 | ctx = Utils(js_file_name='demo.js').read_js_file() 75 | return ctx.call('b', Data) 76 | 77 | 78 | def get_results(page): 79 | json_data = { 80 | 'pageNo': page, 81 | 'pageSize': 20, 82 | 'total': 6473, 83 | 'KIND': 'GCJS', 84 | 'GGTYPE': '1', 85 | 'PROTYPE': '', 86 | 'AREACODE': '', 87 | 'M_PROJECT_TYPE': '', 88 | 'timeType': '6', 89 | 'BeginTime': '2022-02-17 00:00:00', 90 | 'EndTime': '2022-08-17 23:59:59', 91 | 'createTime': [], 92 | 'ts': int(time.time() * 1000), 93 | } 94 | n = get_n(json_data) 95 | portal_sign = Utils(origin_md5_str=n).encrypt_md5() 96 | logger.info(f'第 {page} 页,portal_sign:{portal_sign}') 97 | headers = { 98 | 'Accept': 'application/json, text/plain, */*', 99 | 'Accept-Language': 'zh-CN,zh;q=0.9', 100 | 'Content-Type': 'application/json;charset=UTF-8', 101 | 'Origin': 'https://ggzyfw.fujian.gov.cn', 102 | 'Referer': 'https://ggzyfw.fujian.gov.cn/web/index.html', 103 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36', 104 | 'portal-sign': portal_sign, 105 | } 106 | response = requests.post('https://ggzyfw.fujian.gov.cn/FwPortalApi/Trade/TradeInfo', headers=headers, 107 | json=json_data) 108 | return response.json() 109 | 110 | 111 | def parse(): 112 | for page in range(1, 324): 113 | results = get_results(page) 114 | data = json.loads(get_data(results['Data'])) 115 | table_list = data['Table'] 116 | for table in table_list: 117 | city_level = table['AREANAME'] 118 | name = table['PLATFORM_NAME'] 119 | title = table['NAME'] 120 | update_time = table['TM1'] 121 | print(f'【{city_level} - {name}】{title} {str(update_time).split(" ")[0]}') 122 | print('===' * 35) 123 | 124 | 125 | if __name__ == '__main__': 126 | parse() 127 | -------------------------------------------------------------------------------- /hh1024/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:08 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /hh1024/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:08 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 主页: http://www.hh1024.com/#/login?redirect=%2FrealTimeLiving 8 | 登录接口: https://user.hrdjyun.com/wechat/phonePwdLogin 9 | - post请求 10 | - 请求参数中pwd和sig参数需要破解 11 | 12 | todo 破解流程 13 | - pwd 14 | - 根据经验,可以确定为md5加密 15 | 16 | - sig 17 | - 全局搜索 `sig:` 可以定位到关键代码如下: 18 | var l = Object(g["a"])(P(S(e))); 19 | sig: l 20 | - 接下来就是扣代码环节,缺啥补啥,没啥难度 21 | 22 | - 封装js代码,代入到python文件中 23 | - 当账号和密码分别为 `12345678919` 和 `123456` 时 24 | - 测试结果:{'status': 3, 'message': '手机号还未注册', 'data': None} 25 | - 跟网页上的返回结果一致,验证成功! 26 | 27 | - 基础入门,适合新手练习 28 | ''' 29 | 30 | import time 31 | import requests 32 | 33 | from utils import * 34 | 35 | 36 | def get_sig(params): 37 | ctx = Utils(js_file_name='demo.js').read_js_file() 38 | return ctx.call('get_sig', params) 39 | 40 | 41 | def get_results(username, pwd): 42 | headers = { 43 | 'Accept': 'application/json, text/plain, */*', 44 | 'Accept-Language': 'zh-CN,zh;q=0.9', 45 | 'Content-Type': 'application/json', 46 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36', 47 | } 48 | pwd = Utils(origin_md5_str=pwd).encrypt_md5() 49 | logger.info(f'加密后的密码: {pwd}') 50 | json_data = { 51 | 'phoneNum': str(username), 52 | 'pwd': pwd, 53 | 't': int(time.time() * 1000), 54 | 'tenant': 1, 55 | } 56 | sig = get_sig(json_data) 57 | logger.info(f'sig参数获取: {sig}') 58 | json_data['sig'] = sig 59 | response = requests.post('https://user.hrdjyun.com/wechat/phonePwdLogin', headers=headers, json=json_data) 60 | return response.json() 61 | 62 | 63 | if __name__ == '__main__': 64 | results = get_results('12345678919', '123456') 65 | logger.info(f'接口响应结果:\n{results}') 66 | logger.info(f'账号信息: {results["message"]}') 67 | -------------------------------------------------------------------------------- /hjs/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:30 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /hjs/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:30 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 主页地址: https://www.hfax.com/login.html#/?rsrc=https%3A%2F%2Fwww.hfax.com%2Fabout.html%23%2Fquestions 8 | 9 | 逆向参数: 登录所需的pwd 10 | 加密方式: 加盐的md5 11 | 12 | todo list 13 | - 全局搜索 `password:` 14 | - 可定位参数在 `login.xxx.js` 文件中。点击进入该文件之后,在再该文件中重新搜索 `password:`,可定位到以下代码 15 | - a = encryptByDES(this.password); 16 | - 在该处下断点,重新点击登录按钮,断点生效。 17 | - 单步调试,进入该函数后,发现以下代码 18 | - CryptoJS.MD5(t + "TuD00Iqz4ge7gzIe2rmjSAFFKtaIBmnr8S").toString() 19 | - 经过测试,该参数为md5加密 20 | - 在原密码的后边拼接了 `TuD00Iqz4ge7gzIe2rmjSAFFKtaIBmnr8S`,然后在进行md5加密 21 | 22 | ''' 23 | 24 | import requests 25 | 26 | from utils import * 27 | 28 | headers = { 29 | 'Accept': '*/*', 30 | 'Accept-Language': 'zh-CN,zh;q=0.9', 31 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36', 32 | 'X-Requested-With': 'XMLHttpRequest', 33 | } 34 | cookies = { 35 | # 经过测试,请求头中的cookies必须带上,并且里边的session不可少,值可为None 36 | 'SESSION': None, 37 | } 38 | 39 | 40 | def get_image_msg(): 41 | response = requests.get('https://www.hfax.com/pc-api/common/imageCode/login', headers=headers, cookies=cookies) 42 | results = response.json() 43 | data = results['data'] 44 | img_base64 = data['base64Str'] 45 | img_token = data['token'] 46 | return img_base64, img_token 47 | 48 | 49 | def verify_captcha(base64str): 50 | ''' 51 | 根据接收的base64图片,识别结果并返回 52 | :param base64str: 原始的图片base64信息,data:image/png;base64,/9j/4AA 53 | :return: 54 | ''' 55 | # 把 data:image/png;base64,的图片前缀信息删掉,这不属于图片内的信息 56 | image_base64 = str(base64str).split('base64,')[-1] 57 | res_code = ocr.classification(image_base64) 58 | return res_code 59 | 60 | 61 | def login(user_name, pwd): 62 | base64str, token = get_image_msg() 63 | img_code = verify_captcha(base64str) 64 | logger.info(f'验证码识别结果: {img_code}') 65 | encrypt_pwd = Utils(origin_md5_str=f'{pwd}TuD00Iqz4ge7gzIe2rmjSAFFKtaIBmnr8S').encrypt_md5() 66 | logger.info(f'加密之后的密码: {encrypt_pwd}') 67 | json_data = { 68 | 'username': user_name, 69 | 'password': encrypt_pwd, 70 | 'imgCode': img_code, 71 | 'imgToken': token, 72 | } 73 | response = requests.post('https://www.hfax.com/pc-api/user/login', headers=headers, json=json_data, cookies=cookies) 74 | return response.json() 75 | 76 | 77 | def main(): 78 | res = login('12345768090', '123456') 79 | # 因为我使用的是错误的账号和密码,故以下代码肯定能取到值 80 | code = res['errCode'] 81 | msg = res['errMsg'] 82 | logger.info(f'\nerror code: {code}\nerror msg: {msg}') 83 | 84 | 85 | if __name__ == '__main__': 86 | main() 87 | -------------------------------------------------------------------------------- /hsddcx/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:51 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /hsddcx/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 6:25 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import requests 7 | 8 | from utils import * 9 | 10 | ctx = Utils(js_file_name='demo.js').read_js_file() 11 | 12 | 13 | def get_decrypt(page, encrypt_data): 14 | if page: 15 | return ctx.call('get_encrypt_params', page) 16 | return ctx.call('get_decrypt_data', encrypt_data) 17 | 18 | 19 | def get_encrypt_results(page): 20 | headers = { 21 | 'Accept': 'application/json, text/plain, */*', 22 | 'Accept-Language': 'zh-CN,zh;q=0.9', 23 | 'Ali-Version': '7.6.15', 24 | 'Content-Type': 'application/json; charset=UTF-8', 25 | 'Origin': 'https://hsddcx.wsjkw.zj.gov.cn', 26 | 'Pragma': 'no-cache', 27 | 'Referer': 'https://hsddcx.wsjkw.zj.gov.cn/webapp/app-mobile/epidMap', 28 | 'Sec-Fetch-Dest': 'empty', 29 | 'Sec-Fetch-Mode': 'cors', 30 | 'Sec-Fetch-Site': 'same-origin', 31 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36', 32 | 'channel': 'H5', 33 | 'sec-ch-ua': '"Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"', 34 | 'sec-ch-ua-mobile': '?0', 35 | 'sec-ch-ua-platform': '"macOS"', 36 | 'x-resp-encrypt': '1', 37 | } 38 | data = get_decrypt(page, encrypt_data=None) 39 | logger.info(f'第 {page} 页加密参数: {data}') 40 | response = requests.post('https://hsddcx.wsjkw.zj.gov.cn/client-api/search/getNucleicAcidOrgList', headers=headers, 41 | data=data) 42 | return response.text 43 | 44 | 45 | def parse(encrypt_data): 46 | results = get_decrypt(page=None, encrypt_data=encrypt_data) 47 | t_res = results['result']['t'] 48 | data_list = t_res['data'] 49 | for data in data_list: 50 | name = data['orgName'] 51 | address = data['address'] 52 | level = data['levelName'] 53 | phone = data['phone'] if data['phone'] else '未知' 54 | is_free = data['isFree'] 55 | res_free = True if is_free == 1 else False 56 | work_time = data['workTime'] 57 | status = data['serviceStatus'] 58 | res = '畅通' if status == 2 else '休息' 59 | print(f'名称: {name}\n电话: {phone}\n地址: {address}\n级别: {level}\n是否免费: {res_free}\n工作时间: {work_time}\n当前状态: {res}') 60 | print('===' * 25) 61 | 62 | # 下一页逻辑,循环入口 63 | is_next_page = t_res['hasNextPage'] 64 | cur_page = t_res['pageNum'] 65 | if is_next_page: 66 | next_page = t_res['nextPage'] 67 | logger.info(f'有下一页, 当前页码: {cur_page}, 下一页: {next_page}') 68 | encrypt_data = get_encrypt_results(next_page) 69 | parse(encrypt_data) 70 | else: 71 | logger.info(f'没有下一页了,最后一页: {cur_page}') 72 | return 73 | 74 | 75 | if __name__ == '__main__': 76 | # 脚本启动入口 77 | encrypt_data = get_encrypt_results(1) 78 | parse(encrypt_data) 79 | -------------------------------------------------------------------------------- /images/chrome_version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/images/chrome_version.png -------------------------------------------------------------------------------- /images/chromedriver_version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/images/chromedriver_version.png -------------------------------------------------------------------------------- /images/fix_origin_chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/images/fix_origin_chrome.png -------------------------------------------------------------------------------- /images/origin_chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/images/origin_chrome.png -------------------------------------------------------------------------------- /images/response_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/images/response_type.png -------------------------------------------------------------------------------- /images/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/images/setting.png -------------------------------------------------------------------------------- /images/setting_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/images/setting_button.png -------------------------------------------------------------------------------- /iyunzhi/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 1:52 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /iyunzhi/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 1:47 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | import requests 6 | import json 7 | 8 | import execjs 9 | 10 | from loguru import logger 11 | 12 | headers = { 13 | "authority": "lark-acl.alibaba.com", 14 | "accept": "application/json, text/plain, */*", 15 | "accept-language": "zh-CN,zh;q=0.9", 16 | "cache-control": "no-cache", 17 | "content-type": "application/json;charset=UTF-8", 18 | "origin": "https://www.iyunzhi.com", 19 | "pragma": "no-cache", 20 | "referer": "https://www.iyunzhi.com/", 21 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" 22 | } 23 | 24 | f = open('demo.js') 25 | js_str = f.read() 26 | ctx = execjs.compile(''.join(js_str)) 27 | 28 | 29 | def get_login_res(password): 30 | url = "https://lark-acl.alibaba.com/idp/loginAccountAndPwd" 31 | params = { 32 | "access_token": "" 33 | } 34 | enc_pwd = ctx.call('get_encrypted_pwd', password) 35 | logger.info(f'\n加密前密码: {password}\n加密后密码: {enc_pwd}') 36 | data = { 37 | "loginId": "19929939949", 38 | "password": enc_pwd 39 | } 40 | data = json.dumps(data, separators=(',', ':')) 41 | response = requests.post(url, headers=headers, params=params, data=data) 42 | return response.json() 43 | 44 | 45 | def main(): 46 | pwd = '123456' 47 | login_res = get_login_res(pwd) 48 | logger.info(login_res) 49 | 50 | 51 | if __name__ == '__main__': 52 | main() 53 | 54 | -------------------------------------------------------------------------------- /jzsc/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:11 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /jzsc/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js') 2 | 3 | var f = CryptoJS.enc.Utf8.parse("jo8j9wGw%6HbxfFn") 4 | , m = CryptoJS.enc.Utf8.parse("0123456789ABCDEF"); 5 | 6 | function get_encrypt_data(t) { 7 | var e = CryptoJS.enc.Hex.parse(t) 8 | , n = CryptoJS.enc.Base64.stringify(e) 9 | , a = CryptoJS.AES.decrypt(n, f, { 10 | iv: m, 11 | mode: CryptoJS.mode.CBC, 12 | padding: CryptoJS.pad.Pkcs7 13 | }) 14 | , r = a.toString(CryptoJS.enc.Utf8); 15 | return r.toString() 16 | } 17 | -------------------------------------------------------------------------------- /jzsc/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:15 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | 7 | """ 8 | todo changelog version 20230314 9 | - 接口变更 10 | - 原接口: http://jzsc.mohurd.gov.cn/api/webApi/dataservice/query/comp/list 11 | - 变更后的接口: https://jzsc.mohurd.gov.cn/Api/webApi/dataservice/query/comp/list 12 | 13 | todo: http://jzsc.mohurd.gov.cn/data/company 14 | 由于是破解该网站返回数据加密的过程,所以可以根据关键字 `decrypt` 搜索进行定位关键代码。在`app.xxx.js`中可以定位到解密位置,打断点,点击下一页,断点生效。 15 | 把解密的函数copy下来,缺啥补啥。 16 | """ 17 | 18 | import json 19 | import requests 20 | 21 | from utils import * 22 | 23 | 24 | def get_decrypt_data(encrypt_data): 25 | """ 26 | 调用js,传入需要解密的数据,返回解密后的数据 27 | :param encrypt_data: 需要解密的数据 28 | :return: 解密后的数据 29 | """ 30 | ctx = Utils(js_file_name='demo.js').read_js_file() 31 | decrypt_data = ctx.call('get_encrypt_data', encrypt_data) 32 | return json.loads(decrypt_data) 33 | 34 | 35 | def get_encrypt_data(page): 36 | """ 37 | 获取数据 38 | :param page: 页码 39 | :return: 40 | """ 41 | headers = { 42 | 'Accept': 'application/json, text/plain, */*', 43 | 'Referer': 'http://jzsc.mohurd.gov.cn/data/company', 44 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36', 45 | 'timeout': '30000', 46 | } 47 | params = { 48 | 'pg': str(page), 49 | 'pgsz': '15', 50 | 'total': '450', 51 | } 52 | response = requests.get('https://jzsc.mohurd.gov.cn/APi/webApi/dataservice/query/comp/list', params=params, 53 | headers=headers) 54 | return response.text 55 | 56 | 57 | def parse(): 58 | for page in range(0, 30): 59 | logger.info(f'正在抓取第 {page + 1} 页数据...') 60 | encrypt_data = get_encrypt_data(page) 61 | decrypt_data = get_decrypt_data(encrypt_data) 62 | data_list = decrypt_data['data']['list'] 63 | for data in data_list: 64 | org_code = data['QY_ORG_CODE'] 65 | coname = data['QY_NAME'] 66 | try: 67 | faren = data['QY_FR_NAME'] 68 | except KeyError: 69 | faren = None 70 | address = data['QY_REGION_NAME'] 71 | print(f'统一社会信用代码: {org_code}\n企业名称: {coname}\n企业法定代表人: {faren}\n企业注册属地: {address}') 72 | print('===' * 20) 73 | 74 | 75 | if __name__ == '__main__': 76 | parse() 77 | -------------------------------------------------------------------------------- /kanzhun/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:09 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /kanzhun/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:09 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | """ 7 | 典型的 webpack 案例 8 | """ 9 | import requests 10 | 11 | from utils import * 12 | 13 | ctx = Utils(js_file_name='demo.js').read_js_file() 14 | 15 | 16 | def get_decrypt(company_id, page, encrypt_data, req_params): 17 | if not encrypt_data: # 破解加密参数 18 | results = ctx.call('get_params_b_kiv', company_id, page) 19 | else: # 对返回的加密数据进行解密 20 | results = ctx.call('get_decrypt_data', encrypt_data, req_params) 21 | return results 22 | 23 | 24 | def get_encrypt_data(company_id, page): 25 | headers = { 26 | 'authority': 'www.kanzhun.com', 27 | 'accept': 'application/json, text/plain, */*', 28 | 'accept-language': 'zh-CN,zh;q=0.9', 29 | 'content-type': 'application/x-www-form-urlencoded;charset=utf-8', 30 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36', 31 | 'x-requested-with': 'XMLHttpRequest', 32 | } 33 | req_params = get_decrypt(company_id, page, encrypt_data=None, req_params=None) 34 | logger.info(f'加密后的参数: {req_params}') 35 | response = requests.get('https://www.kanzhun.com/api_to/com_salary_v2/list.json', params=req_params, 36 | headers=headers) 37 | return req_params, response.text 38 | 39 | 40 | def parse(): 41 | company_id = '1HV52g~~' # 华为 42 | for page in range(1, 10): 43 | req_params, encrypt_data = get_encrypt_data(company_id, page) 44 | decrypt_data = get_decrypt(None, None, encrypt_data, req_params) 45 | salary_list = decrypt_data['resdata']['salarys'] 46 | for salary in salary_list: 47 | job_name = salary['jobTitle'] 48 | avgSalary = salary['avgSalary'] 49 | lowestSalary = salary['lowestSalary'] 50 | highestSalary = salary['highestSalary'] 51 | percentage = salary['percentage'] 52 | staffCount = salary['staffCount'] 53 | salaryContrast = salary['salaryContrast'] 54 | tag = '增加' if salaryContrast == 1 else '减少' 55 | updateTime = salary['updateTime'] 56 | print( 57 | f'职位名称: {job_name}\n数据来自 {staffCount} 名用户的贡献\n月均值: {avgSalary}\n较同行: {tag}{percentage}%\n同行最低工资: {lowestSalary}\n同行最高工资: {highestSalary}\n职位更新日期: {updateTime}') 58 | print('===' * 10) 59 | 60 | 61 | if __name__ == '__main__': 62 | parse() 63 | -------------------------------------------------------------------------------- /landchina/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:33 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /landchina/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:49 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 网址:https://www.landchina.com/#/supplyPlan 8 | 破解参数:请求头 Hash 9 | 10 | 步骤: 11 | - 全局搜索 'hash=',可定位到以下代码 12 | var e = t.headers 13 | , n = (c.a.isKey("manageLoginToken") && (n = c.a.get("manageLoginToken"), 14 | !Object.prototype.hasOwnProperty.call(e, "manageLoginToken")) && n && (e.Authorization = "Bearer " + n), 15 | i("lPiR")) 16 | , a = t.url.split("/"); 17 | return e.Hash = n(navigator.userAgent + (new Date).getDate() + a[a.length - 1]) 18 | 19 | - hash参数是由n函数生成,其中接收的参数为 20 | useragent + 【今天】的日期 + url以 / 分割后最后一个元素 21 | - n 是由 i("lPiR") 生成的 22 | 23 | 显然是webpack,接下来就是常规的扣代码 24 | - 生成器是 i 25 | - 总共只需要扣取三个模块 lPiR Ib8C yLpj 26 | 27 | 接下来就可以正常生成hash参数了 28 | 29 | 经过测试,不携带该参数也可以请求到数据 30 | 31 | 该站点纯属练习webpack 32 | 33 | ''' 34 | 35 | import json 36 | import execjs 37 | import requests 38 | 39 | from loguru import logger 40 | 41 | f = open('demo.js', 'r', encoding='utf8') 42 | js_str = f.read() 43 | ctx = execjs.compile(''.join(js_str)) 44 | 45 | headers = { 46 | "Accept": "application/json, text/plain, */*", 47 | "Accept-Language": "zh-CN,zh;q=0.9", 48 | "Content-Type": "application/json", 49 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", 50 | } 51 | 52 | 53 | def get_results(page): 54 | url = "https://api.landchina.com/tGyjh/plan/list" 55 | data = { 56 | "pageNum": page, 57 | "pageSize": 10, 58 | "startDate": "", 59 | "endDate": "" 60 | } 61 | hash = ctx.call('get_headers_hash', headers['User-Agent']) 62 | headers['Hash'] = hash 63 | logger.info(hash) 64 | data = json.dumps(data, separators=(',', ':')) 65 | response = requests.post(url, headers=headers, data=data) 66 | return response.json() 67 | 68 | 69 | def parse(): 70 | for page in range(1, 11): 71 | results = get_results(page) 72 | data_list = results['data']['list'] 73 | for data in data_list: 74 | xzq = data['xzqFullName'] 75 | title = data['biaoti'] 76 | update_date = data['fbSj'] 77 | print(f'行政区: {xzq}\n公告标题: {title}\n发布日期: {update_date}') 78 | print('---' * 20) 79 | print('***' * 30) 80 | 81 | 82 | if __name__ == '__main__': 83 | parse() 84 | -------------------------------------------------------------------------------- /liepin/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:33 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /liepin/demo.js: -------------------------------------------------------------------------------- 1 | /* 2 | - 控制台全局搜索 `X-Fscp-Trace-Id`,可以定位到在 `common.ee5c9e85.js` 文件中,有该参数的赋值,代码如下: 3 | ```javascript 4 | e.headers["X-Fscp-Trace-Id"] = w() 5 | ``` 6 | - 在该处打上断点,点击下一页,断点生效 7 | - 进入 w 函数中,发现如下代码 8 | ```javascript 9 | var w = function(e, t, n) { 10 | var r = (e = e || {}).random || (e.rng || h)(); 11 | if (r[6] = 15 & r[6] | 64, 12 | r[8] = 63 & r[8] | 128, 13 | t) { 14 | n = n || 0; 15 | for (var a = 0; a < 16; ++a) 16 | t[n + a] = r[a]; 17 | return t 18 | } 19 | return x(r) 20 | } 21 | ``` 22 | 最终返回的 `x(r)` 即最终的结果。 23 | 24 | - x 函数如下: 25 | ```javascript 26 | function x(e) { 27 | var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0 28 | , 29 | n = (g[e[t + 0]] + g[e[t + 1]] + g[e[t + 2]] + g[e[t + 3]] + "-" + g[e[t + 4]] + g[e[t + 5]] + "-" + g[e[t + 6]] + g[e[t + 7]] + "-" + g[e[t + 8]] + g[e[t + 9]] + "-" + g[e[t + 10]] + g[e[t + 11]] + g[e[t + 12]] + g[e[t + 13]] + g[e[t + 14]] + g[e[t + 15]]).toLowerCase(); 30 | return n 31 | } 32 | ``` 33 | - 缺啥补啥,需要注意的是 `new Uint8Array(16)`,参考博客 [js逆向 模拟window.Crypto.getRandomValues](https://blog.csdn.net/Little__Panda/article/details/113566803) 34 | */ 35 | 36 | // js逆向 模拟window.Crypto.getRandomValues 37 | function randoms(min, max) { 38 | return Math.floor(Math.random() * (max - min + 1) + min) 39 | } 40 | 41 | function getRandomValues(buf) { 42 | var min = 0, 43 | max = 255; 44 | if (buf instanceof Uint16Array) { 45 | max = 65535; 46 | } else if (buf instanceof Uint32Array) { 47 | max = 4294967295; 48 | } 49 | for (var element in buf) { 50 | buf[element] = randoms(min, max); 51 | } 52 | return buf; 53 | } 54 | 55 | for (var g = [], b = 0; b < 256; ++b) 56 | g.push((b + 256).toString(16).substr(1)); 57 | 58 | function m() { 59 | var p = new Uint8Array(16), r = []; 60 | for (getRandomValues(p), G = 0; G < p.length; ++G) 61 | r.push(p[G]) 62 | return r 63 | } 64 | 65 | function x(e) { 66 | var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0 67 | , 68 | n = (g[e[t + 0]] + g[e[t + 1]] + g[e[t + 2]] + g[e[t + 3]] + "-" + g[e[t + 4]] + g[e[t + 5]] + "-" + g[e[t + 6]] + g[e[t + 7]] + "-" + g[e[t + 8]] + g[e[t + 9]] + "-" + g[e[t + 10]] + g[e[t + 11]] + g[e[t + 12]] + g[e[t + 13]] + g[e[t + 14]] + g[e[t + 15]]).toLowerCase(); 69 | return n 70 | } 71 | 72 | function get_x_fscp_teace_id() { 73 | var r = m(); 74 | return x(r) 75 | } 76 | 77 | console.log(get_x_fscp_teace_id()) 78 | -------------------------------------------------------------------------------- /liuyan/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 6:27 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /liuyan/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 6:27 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | """ 7 | 网站首页(http://liuyan.people.com.cn/messageSearch) 8 | 需要逆向的参数: 请求参数中的signature 9 | 步骤: 10 | - 全局搜索 `signature`,可在`app.xxx.js`文件中找到如下代码: 11 | ``` 12 | h = function(e, t, c, s) { 13 | var a = e.indexOf("?"); 14 | a > 0 && (e = e.substring(0, a)); 15 | var i = e + JSON.stringify(t) + c; 16 | return s && (i += s), 17 | l()(i) 18 | } 19 | , d = function(e, t, c, s) { 20 | var a; 21 | a = c ? l()(c).substring(0, 16) : l()(s).substring(0, 16); 22 | var i = { 23 | appCode: s, 24 | token: c, 25 | signature: h(e, t, a, c), 26 | param: JSON.stringify(t) 27 | }; 28 | ``` 29 | - 通过分析该代码,可发现signature由h函数生成,且接收四个参数`e, t, a, c` 30 | - 而h函数最终返回 `l()(i)` 31 | - 其中i的值为: '/v2/threads/search{"position":0,"keywords":"","fid":null,"domainId":null,"typeId":null,"timeRange":null,"ansChecked":false,"stTime":null,"sortType":"0","page":10,"rows":10}a2eb17f65d6f4b3f' 32 | - 经过测试,最终signature的值就是对i进行md5加密得到的结果 33 | - 分析参数`i`的构成 34 | - 大致可分为三部分 35 | - para1: /v2/threads/search, 此为post请求所需要的url的后缀 36 | - para2: {"position":0,"keywords":"","fid":null,"domainId":null,"typeId":null,"timeRange":null,"ansChecked":false,"stTime":null,"sortType":"0","page":10,"rows":10}, 此为post请求,所携带的参数,其中page可变 37 | - para3: a2eb17f65d6f4b3f, 此为对 `appcode` 的值进行md5加密,并取前16位得到的值 38 | - 最终把这三部分进行拼接,得到最终的值,并进行md5加密,即可得到signature 39 | """ 40 | 41 | import requests 42 | import time 43 | 44 | from utils import * 45 | 46 | 47 | def get_results(page): 48 | headers = { 49 | 'Accept': 'application/json, text/plain, */*', 50 | 'Accept-Language': 'zh-CN', 51 | 'Content-Type': 'application/json;charset=UTF-8', 52 | 'Origin': 'http://liuyan.people.com.cn', 53 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36', 54 | 'token': '', 55 | } 56 | app_code = 'PC42ce3bfa4980a9' 57 | # app_code的值可由http://liuyan.people.com.cn/messageSearch,在其源代码中通过正则规则 `window.SITE_CONFIG['appCode'] =(.*?)'`得到 58 | params = { 59 | 'sortType': '0', 60 | } 61 | json_data = { 62 | 'appCode': 'PC42ce3bfa4980a9', 63 | 'token': '', 64 | 'param': '{"position":0,"keywords":"","fid":null,"domainId":null,"typeId":null,"timeRange":null,"ansChecked":false,"stTime":null,"sortType":"0","page":%s,"rows":10}' % page, 65 | } 66 | para1 = '/v2/threads/search' 67 | para2 = json_data['param'] 68 | para3 = Utils(origin_md5_str=app_code).encrypt_md5()[0:16] 69 | encrypt_str = para1 + para2 + para3 70 | signature = Utils(origin_md5_str=encrypt_str).encrypt_md5() 71 | json_data['signature'] = signature 72 | response = requests.post('http://liuyan.people.com.cn/v2/threads/search', params=params, headers=headers, 73 | json=json_data, verify=False) 74 | return response.json() 75 | 76 | 77 | def parse(): 78 | for page in range(1, 100): 79 | results = get_results(page) 80 | data_list = results['data']['data'] 81 | for data in data_list: 82 | title = data['subject'] 83 | typeName = data['typeName'] 84 | domainName = data['domainName'] 85 | content = data['content'] 86 | status = data['stateInfo'] 87 | forumName = data['forumName'] 88 | nickName = data['nickName'] 89 | date = data['createDateline'] 90 | # 时间戳转换为时间格式 91 | dateline = time.strftime("%Y-%m-%d %H:%M", time.localtime(date)) 92 | print( 93 | f'标题: {title}\n类型: {typeName}\n区域: {domainName}\n状态: {status}\n留言对象: {forumName}\n留言用户: {nickName}\n留言日期: {dateline}\n留言内容: {content}') 94 | print('===' * 30) 95 | 96 | 97 | if __name__ == '__main__': 98 | parse() 99 | -------------------------------------------------------------------------------- /maomaozu/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:43 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /maomaozu/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js'); 2 | var k = '55b3b62613aef1a0'; 3 | 4 | function aes_decrypt(e) { 5 | var a = k.split("").reverse().join(""); 6 | return decrypt(a, e) 7 | } 8 | 9 | function aes_encrypt(e) { 10 | return encrypt(k, e) 11 | } 12 | 13 | function decrypt(e, a) { 14 | e = CryptoJS.enc.Utf8.parse(e); 15 | var l = CryptoJS.AES.decrypt(a, e, { 16 | mode: CryptoJS.mode.CBC, 17 | padding: CryptoJS.pad.Pkcs7, 18 | iv: e 19 | }); 20 | return CryptoJS.enc.Utf8.stringify(l).toString() 21 | } 22 | 23 | function encrypt(e, a) { 24 | return e = CryptoJS.enc.Utf8.parse(e), 25 | a = CryptoJS.enc.Utf8.parse(a), 26 | CryptoJS.AES.encrypt(a, e, { 27 | mode: CryptoJS.mode.CBC, 28 | padding: CryptoJS.pad.Pkcs7, 29 | iv: e 30 | }).toString() 31 | } 32 | 33 | function get_encrypt_params(page) { 34 | var a = { 35 | "Type": 0, 36 | "page": page, 37 | "expire": (new Date).getTime() 38 | }, 39 | data = aes_encrypt(JSON.stringify(a)); 40 | return data 41 | } 42 | 43 | function get_decrypt_res(encrypt_data) { 44 | var decrypt_res = aes_decrypt(encrypt_data); 45 | return JSON.parse(decrypt_res) 46 | } 47 | 48 | -------------------------------------------------------------------------------- /maomaozu/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:07 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import time 7 | import requests 8 | 9 | from utils import * 10 | 11 | ctx = Utils(js_file_name='demo.js').read_js_file() 12 | 13 | 14 | def get_data(page, encrypt_data): 15 | if page: 16 | return ctx.call('get_encrypt_params', page) 17 | return ctx.call('get_decrypt_res', encrypt_data) 18 | 19 | 20 | def get_encrypt_res(page): 21 | headers = { 22 | 'Accept': '*/*', 23 | 'Accept-Language': 'zh-CN,zh;q=0.9', 24 | 'Cache-Control': 'no-cache', 25 | 'Content-Type': 'application/json; charset=UTF-8', 26 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36', 27 | } 28 | encrypt_para = get_data(page=page, encrypt_data=None) 29 | logger.info(f'第{page}页,加密参数: {encrypt_para}') 30 | response = requests.post('https://www.maomaozu.com/index/build.json', headers=headers, data=encrypt_para) 31 | return response.text 32 | 33 | 34 | def parse(page): 35 | encrypt_data = get_encrypt_res(page) 36 | decrypt_data = get_data(page=None, encrypt_data=encrypt_data) 37 | data_list = decrypt_data['list'] 38 | for data in data_list: 39 | title = data['Name'] 40 | address = data['Address'] 41 | addr = '-'.join(address[0: 2]) 42 | walk_time = address[-1] 43 | nearby_line = data['Line'] 44 | line = ', '.join(nearby_line) 45 | update_str = data['UpdateTimeStr'] 46 | update_ts = data['UpdateTime'] 47 | update_time = time.strftime("%Y-%m-%d", time.localtime(update_ts)) 48 | room_list = data['RoomList'] 49 | area_list = [f'{room[0]} m²' for room in room_list] 50 | area = ' | '.join(area_list) 51 | price = data['Price'] 52 | price_str = f'¥{price}/m² · 天' 53 | print( 54 | f'标题: {title}\n地址: {addr}, 步行 {walk_time} 分钟到\n附近地铁: {line}\n更新时间: {update_str}, {update_time}\n面积: {area}\n价格: {price_str}') 55 | print('===' * 30) 56 | 57 | 58 | if __name__ == '__main__': 59 | for page in range(1, 10): 60 | parse(page) 61 | -------------------------------------------------------------------------------- /music163/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:36 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /music_kuwo/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:53 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /my_37/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:49 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /my_37/demo.js: -------------------------------------------------------------------------------- 1 | /* 2 | * https://my.37.com/login.html?url=//my.37.com/ 3 | * 全局搜索 `password=`,在sq.login2015.js中发现 `h.password = td(f)` 4 | * 此处即为加密位置 5 | * 下断,重新点击登录按钮,单步调试就可以进入td的函数内部 6 | * 代码全部复制下来即可 7 | */ 8 | 9 | var ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 10 | 11 | function __rsa(str) { 12 | var out, i, len; 13 | var c1, c2, c3; 14 | len = str.length; 15 | i = 0; 16 | out = ""; 17 | while (i < len) { 18 | c1 = str.charCodeAt(i++) & 0xff; 19 | if (i == len) { 20 | out += ch.charAt(c1 >> 2); 21 | out += ch.charAt((c1 & 0x3) << 4); 22 | out += "=="; 23 | break 24 | } 25 | c2 = str.charCodeAt(i++); 26 | if (i == len) { 27 | out += ch.charAt(c1 >> 2); 28 | out += ch.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); 29 | out += ch.charAt((c2 & 0xF) << 2); 30 | out += "="; 31 | break 32 | } 33 | c3 = str.charCodeAt(i++); 34 | out += ch.charAt(c1 >> 2); 35 | out += ch.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); 36 | out += ch.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)); 37 | out += ch.charAt(c3 & 0x3F) 38 | } 39 | return out 40 | } 41 | 42 | function td(a) { 43 | var maxPos = ch.length - 2 44 | , w = []; 45 | for (i = 0; i < 15; i++) { 46 | w.push(ch.charAt(Math.floor(Math.random() * maxPos))); 47 | if (i === 7) { 48 | w.push(a.substr(0, 3)) 49 | } 50 | if (i === 12) { 51 | w.push(a.substr(3)) 52 | } 53 | } 54 | return __rsa(w.join("")) 55 | } 56 | 57 | console.log(td('123456')) 58 | -------------------------------------------------------------------------------- /mytokencap/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:46 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /newrank/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:08 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /newrank/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:13 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import js2py 7 | import requests 8 | 9 | from utils import * 10 | 11 | 12 | def get_nonce(): 13 | js_str = """ 14 | function get_nonce() { 15 | for (var a = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"], b = 0; b < 500; b++) 16 | for (var c = "", d = 0; d < 9; d++) { 17 | var e = Math.floor(16 * Math.random()); 18 | c += a[e] 19 | } 20 | return c 21 | } 22 | """ 23 | context = js2py.EvalJs() # 实例化解析js对象 24 | context.execute(js_str) # js对象转python 25 | nonce = context.get_nonce() # 调用js中的get_nonce,没有传参 26 | return nonce 27 | 28 | 29 | def get_xyz(h): 30 | ctx = Utils(js_file_name='demo.js').read_js_file() 31 | return ctx.call('b', h) 32 | 33 | 34 | def get_results(page): 35 | headers = { 36 | 'accept': 'application/json, text/javascript, */*; q=0.01', 37 | 'accept-language': 'zh-CN,zh;q=0.9', 38 | 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 39 | 'origin': 'https://www.newrank.cn', 40 | 'referer': 'https://www.newrank.cn/public/news.html', 41 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 42 | 'x-requested-with': 'XMLHttpRequest', 43 | } 44 | nonce = get_nonce() 45 | h = f'/xdnphb/index/getMedia?AppKey=joker&keyword=&pageNumber={page}&pageSize=10&nonce={nonce}' 46 | xyz = get_xyz(h) 47 | logger.info({'nonce': nonce, 'xyz': xyz}) 48 | data = { 49 | 'keyword': '', 50 | 'pageNumber': str(page), 51 | 'pageSize': '10', 52 | 'nonce': nonce, 53 | 'xyz': xyz, 54 | } # 请求携带的data参数,缺一不可 55 | response = requests.post('https://www.newrank.cn/xdnphb/index/getMedia', headers=headers, data=data) 56 | return response.json() 57 | 58 | 59 | def parse(): 60 | for page in range(1, 100): 61 | results = get_results(page) 62 | data_list = results['value'] 63 | for data in data_list: 64 | title = data['title'] 65 | desc = data['summary'] 66 | label = data['label'] 67 | author = data['author'] 68 | public_time = data['public_time'] 69 | url = data['url'] 70 | print(f'标题: {title}\n描述: {desc}\n标签: {label}\n作者: {author}\n更新时间: {public_time}\n详情页地址: {url}') 71 | print('***' * 30) 72 | 73 | 74 | if __name__ == '__main__': 75 | # https://www.newrank.cn/public/news.html 76 | parse() 77 | -------------------------------------------------------------------------------- /oauth/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:58 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /oklink/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:54 下午 3 | # @File: __init__.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /oklink/demo.js: -------------------------------------------------------------------------------- 1 | global.Buffer = global.Buffer || require('buffer').Buffer; 2 | 3 | if (typeof btoa === 'undefined') { 4 | global.btoa = function (str) { 5 | return new Buffer.from(str).toString('base64'); 6 | }; 7 | } 8 | 9 | if (typeof atob === 'undefined') { 10 | global.atob = function (b64Encoded) { 11 | return new Buffer.from(b64Encoded, 'base64').toString(); 12 | }; 13 | } 14 | var self = global 15 | 16 | window = {} 17 | 18 | function encryptTime(t){ 19 | var e = (1 * t + 1111111111111).toString().split(""), 20 | r = parseInt(10 * Math.random(), 10), 21 | n = parseInt(10 * Math.random(), 10), 22 | o = parseInt(10 * Math.random(), 10); 23 | return e.concat([r, n, o]).join("") 24 | } 25 | 26 | function encryptApiKey(){ 27 | //this.API_KEY = "a2c903cc-b31e-4547-9299-b6d07b7631ab" 28 | var t = "a2c903cc-b31e-4547-9299-b6d07b7631ab", 29 | e = t.split(""), 30 | r = e.splice(0, 8); 31 | return e.concat(r).join("") 32 | } 33 | 34 | function comb(e, t){ 35 | /* 36 | * var r = "".concat(t, "|").concat(e) 时 37 | * 得到的结果为:Mjc2ODExNzExOTg2MTg4OXwtYjMxZS00NTQ3LTkyOTktYjZkMDdiNzYzMWFiYTJjOTAzY2M= 38 | * 经过base64解密后的结果为:2768117119861889|-b31e-4547-9299-b6d07b7631aba2c903cc 39 | * 40 | * 而浏览器最终生成的x-apiKey的值为:LWIzMWUtNDU0Ny05Mjk5LWI2ZDA3Yjc2MzFhYmEyYzkwM2NjfDI3NjgxMTM1Nzc3MzE4ODk= 41 | * 经过解密后的值为:-b31e-4547-9299-b6d07b7631aba2c903cc|2768113577731889 42 | * 43 | * 两次解密的结果不一样,区别就是 `|` 前后的顺序不一致 44 | * 45 | * 所以,把t和e的位置颠倒一下即可 46 | * 即:当 r = "".concat(e, "|").concat(t) 时,能得到正确的x-apiKey 47 | */ 48 | var r = "".concat(e, "|").concat(t); 49 | return self.btoa(r) 50 | } 51 | 52 | function getApiKey(){ 53 | var t = (new Date).getTime(), 54 | e = encryptApiKey(); 55 | return t = encryptTime(t), comb(e, t) 56 | } 57 | 58 | var res = getApiKey(); 59 | console.log(res) -------------------------------------------------------------------------------- /oklink/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:56 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import time 7 | import requests 8 | 9 | from utils import * 10 | 11 | 12 | def get_apikey(): 13 | ctx = Utils(js_file_name='demo.js').read_js_file() 14 | return ctx.call('getApiKey') 15 | 16 | 17 | def get_json_data(): 18 | url = f'https://www.oklink.com/api/explorer/v1/btc/transactionsNoRestrict?t={str(int(time.time()) * 1000)}&limit=20&offset=0' 19 | headers = { 20 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 21 | 'x-apiKey': get_apikey() 22 | } 23 | response = requests.get(url, headers=headers) 24 | return response.json() 25 | 26 | 27 | def parse(): 28 | result = get_json_data() 29 | data_list = result['data']['hits'] 30 | for data in data_list: 31 | print( 32 | f'交易哈希: {data["hash"]}\n所在区块: {data["blockHeight"]}\n输入: {data["inputsCount"]}\n输出: {data["outputsCount"]}\n数量(BTC): {data["realTransferValue"]}') 33 | print('***' * 30) 34 | 35 | 36 | if __name__ == '__main__': 37 | parse() 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reverse_practice", 3 | "version": "1.0.0", 4 | "description": "***", 5 | "main": "index.js", 6 | "dependencies": { 7 | "crypto-js": "^4.1.1", 8 | "jsdom": "^20.0.0", 9 | "jsencrypt": "^3.2.1", 10 | "md5": "^2.3.0", 11 | "node-rsa": "^1.1.1", 12 | "zlib": "^1.0.5" 13 | }, 14 | "devDependencies": {}, 15 | "scripts": { 16 | "test": "echo \"Error: no test specified\" && exit 1" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/18839782321/reverse_practice.git" 21 | }, 22 | "keywords": [], 23 | "author": "", 24 | "license": "ISC", 25 | "bugs": { 26 | "url": "https://github.com/18839782321/reverse_practice/issues" 27 | }, 28 | "homepage": "https://github.com/18839782321/reverse_practice#readme" 29 | } 30 | -------------------------------------------------------------------------------- /passport_fang/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 6:03 下午 3 | # @File: __init__.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /passport_fang/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 6:03 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import execjs 7 | import requests 8 | from loguru import logger 9 | 10 | 11 | def get_js_pwd(password): 12 | with open('demo.js', 'r') as f: 13 | js_str = f.readlines() 14 | ctx = execjs.compile(''.join(js_str)) 15 | return ctx.call('get_password', password) 16 | 17 | 18 | def get_json_data(user, pwd): 19 | headers = { 20 | 'Accept': '*/*', 21 | 'Accept-Language': 'zh-CN,zh;q=0.9', 22 | 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 23 | 'Referer': 'https://passport.fang.com/', # 这个请求头不能少,否则报错 24 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36', 25 | } 26 | data = { 27 | 'uid': user, 28 | 'pwd': get_js_pwd(pwd), 29 | 'Service': 'soufun-passport-web', 30 | 'AutoLogin': '1', 31 | } 32 | 33 | response = requests.post('https://passport.fang.com/login.api', headers=headers, data=data) 34 | return response.json() 35 | 36 | 37 | def main(): 38 | user = 'username' 39 | pwd = 'password' 40 | results = get_json_data(user, pwd) 41 | print(results) 42 | msg = results['Message'] 43 | tip = results['Tip'] 44 | if msg == 'Success': 45 | logger.info( 46 | f'\n账号信息\nUserID: {results["UserID"]}\nUserName: {results["UserName"]}n\nCurrentIP: {results["Ip"]}') 47 | else: 48 | logger.info(f'Account Login Status: {msg}\t{tip}') 49 | 50 | 51 | if __name__ == '__main__': 52 | main() 53 | -------------------------------------------------------------------------------- /pycharm激活方案汇总/README.MD: -------------------------------------------------------------------------------- 1 | - 方案一:无限试用(靠谱,支持所有版本) 2 | - 方案二:永久激活(支持2020 3.3以下所有版本) 3 | - 方案三:正版激活(支持所有版本,永久更新) 4 | - 方案四:JetBrains 产品正版激活码,每个激活码有效期一年,会定期更新 -------------------------------------------------------------------------------- /pycharm激活方案汇总/激活方案一/无限30天试用(靠谱)/ide-eval-resetter-2.1.13.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/pycharm激活方案汇总/激活方案一/无限30天试用(靠谱)/ide-eval-resetter-2.1.13.zip -------------------------------------------------------------------------------- /pycharm激活方案汇总/激活方案一/无限30天试用(靠谱)/操作步骤.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/pycharm激活方案汇总/激活方案一/无限30天试用(靠谱)/操作步骤.docx -------------------------------------------------------------------------------- /pycharm激活方案汇总/激活方案三/正版激活(支持所有版本)(永久更新)/支持所有版本-正版激活.txt: -------------------------------------------------------------------------------- 1 | 1、正版激活的条件是不能破解过软件 2 | 3 | 2、如果破解过软件就按照下面步骤还原一下 4 | 5 | 3、用试用身份进入软件 6 | 7 | 4、进入软件后点help edit vm options 8 | 9 | 5、删掉最下面的一行,jar包路径 10 | 11 | 6、重启软件 12 | 13 | 7、然后就可以用正版激活码激活了 14 | 15 | 8、正版激活码是永久更新的,到期后重新在网站提取,重新激活即可 16 | 17 | 9、正版激活码永久更新地址:idea.medeming.com/jets -------------------------------------------------------------------------------- /pycharm激活方案汇总/激活方案二/永久破解(亲测2020 3.3以下版本通用)/BetterIntelliJ.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyf-code/reverse_practice/e7e984ab8926770c4c193f4e717bcc02cfe1cf44/pycharm激活方案汇总/激活方案二/永久破解(亲测2020 3.3以下版本通用)/BetterIntelliJ.zip -------------------------------------------------------------------------------- /pycharm激活方案汇总/激活方案二/永久破解(亲测2020 3.3以下版本通用)/reset_script/reset_jetbrains_eval_mac_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # reset jetbrains ide evals 3 | 4 | OS_NAME=$(uname -s) 5 | JB_PRODUCTS="IntelliJIdea CLion PhpStorm GoLand PyCharm WebStorm Rider DataGrip RubyMine AppCode" 6 | 7 | if [ $OS_NAME == "Darwin" ]; then 8 | echo 'macOS:' 9 | 10 | for PRD in $JB_PRODUCTS; do 11 | rm -rf ~/Library/Preferences/${PRD}*/eval 12 | rm -rf ~/Library/Application\ Support/JetBrains/${PRD}*/eval 13 | done 14 | elif [ $OS_NAME == "Linux" ]; then 15 | echo 'Linux:' 16 | 17 | for PRD in $JB_PRODUCTS; do 18 | rm -rf ~/.${PRD}*/config/eval 19 | rm -rf ~/.config/${PRD}*/eval 20 | done 21 | else 22 | echo 'unsupport' 23 | exit 24 | fi 25 | 26 | echo 'done.' 27 | -------------------------------------------------------------------------------- /pycharm激活方案汇总/激活方案二/永久破解(亲测2020 3.3以下版本通用)/reset_script/reset_jetbrains_eval_windows.vbs: -------------------------------------------------------------------------------- 1 | Set oShell = CreateObject("WScript.Shell") 2 | Set oFS = CreateObject("Scripting.FileSystemObject") 3 | sHomeFolder = oShell.ExpandEnvironmentStrings("%USERPROFILE%") 4 | sJBDataFolder = oShell.ExpandEnvironmentStrings("%APPDATA%") + "\JetBrains" 5 | 6 | Set re = New RegExp 7 | re.Global = True 8 | re.IgnoreCase = True 9 | re.Pattern = "\.?(IntelliJIdea|GoLand|CLion|PyCharm|DataGrip|RubyMine|AppCode|PhpStorm|WebStorm|Rider).*" 10 | 11 | Sub removeEval(ByVal file, ByVal sEvalPath) 12 | bMatch = re.Test(file.Name) 13 | If Not bMatch Then 14 | Exit Sub 15 | End If 16 | 17 | If oFS.FolderExists(sEvalPath) Then 18 | oFS.DeleteFolder sEvalPath, True 19 | End If 20 | End Sub 21 | 22 | If oFS.FolderExists(sHomeFolder) Then 23 | For Each oFile In oFS.GetFolder(sHomeFolder).SubFolders 24 | removeEval oFile, sHomeFolder + "\" + oFile.Name + "\config\eval" 25 | Next 26 | End If 27 | 28 | If oFS.FolderExists(sJBDataFolder) Then 29 | For Each oFile In oFS.GetFolder(sJBDataFolder).SubFolders 30 | removeEval oFile, sJBDataFolder + "\" + oFile.Name + "\eval" 31 | Next 32 | End If 33 | 34 | MsgBox "done" -------------------------------------------------------------------------------- /pycharm激活方案汇总/激活方案二/永久破解(亲测2020 3.3以下版本通用)/操作说明.txt: -------------------------------------------------------------------------------- 1 | 1、不需要重新下载应用; 2 | 2、本激活方法适用于2020全系列版本; 3 | 3、如果软件目前已过试用期且无法输入激活码(即激活码框不能输入),请卸载软件重新安装后再激活; 4 | 4、使用前请仔细阅读方法内的【使用步骤】; 5 | 6 | 图文教程:https://mp.weixin.qq.com/s/g6SnJCEP86dntNlRDFyfZw 7 | 8 | 注意:破解补丁的位置不要更换,不要删除,否则激活之后还会失效 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /pycharm激活方案汇总/激活方案二/永久破解(亲测2020 3.3以下版本通用)/激活补丁key-.txt: -------------------------------------------------------------------------------- 1 | BISACXYELK-eyJsaWNlbnNlSWQiOiJCSVNBQ1hZRUxLIiwibGljZW5zZWVOYW1lIjoiQ2hpbmFOQiIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN1cnJlbnRVc2UiOmZhbHNlLCJwcm9kdWN0cyI6W3siY29kZSI6IklJIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJBQyIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiRFBOIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlJTQyIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQUyIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlNGIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IkdPIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJETSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJDTCIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlMwIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlJDIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlJEIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJQQyIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlNWIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlJTVSIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUk0iLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IldTIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJEQiIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiREMiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUERCIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlBXUyIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQR08iLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUFBTIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlBQQyIsInBhaWRVcFRvIjoiMjA5OS0xMi0zMSIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQUkIiLCJwYWlkVXBUbyI6IjIwOTktMTItMzEiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUFNXIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IkRQIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlJTIiwicGFpZFVwVG8iOiIyMDk5LTEyLTMxIiwiZXh0ZW5kZWQiOnRydWV9XSwibWV0YWRhdGEiOiIwMTIwMjAwNzI4RVBKQTAwODAwNiIsImhhc2giOiIxNTAyMTM1NC8wOi0xMjUxMTE0NzE3IiwiZ3JhY2VQZXJpb2REYXlzIjowLCJhdXRvUHJvbG9uZ2F0ZWQiOmZhbHNlLCJpc0F1dG9Qcm9sb25nYXRlZCI6ZmFsc2V9-H7NUmWcLyUNV1ctnlzc4P79j15qL56G0jeIYWPk/HViNdMg1MqPM7BR+aHR28yyuxK7Odb2bFDS8CeHNUtv7nT+4fUs85JJiqc3wc1psRpZq5R77apXLOmvmossWpbAw8T1hOGV9IPUm1f2O1+kLBxrOkdqPpv9+JanbdL7bvchAid2v4/dyQMBYJme/feZ0Dy2l7Jjpwno1TeblEAu0KZmarEo15or5RUNwtaGBL5+396TLhnw1qL904/uPnGftjxWYluLjabO/uRu/+5td8UA/39a1nvGU2nORNLk2IdRGIheiwIiuirAZrII9+OxB+p52i3TIv7ugtkw0E3Jpkw==-MIIDlzCCAn+gAwIBAgIBCTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDEw1KZXRQcm9maWxlIENBMCAXDTE4MTEwMTEyMjk0NloYDzIwOTkwODA5MDIyNjA3WjBoMQswCQYDVQQGEwJDWjEOMAwGA1UECBMFTnVzbGUxDzANBgNVBAcTBlByYWd1ZTEZMBcGA1UEChMQSmV0QnJhaW5zIHMuci5vLjEdMBsGA1UEAxMUcHJvZDN5LWZyb20tMjAxODExMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCdXyaNhhRySH1a8d7c8SlLLFdNcQP8M3gNnq7gudcpHC651qxRrN7Qks8gdXlIkA4u3/lp9ylp95GiIIDo4ydYje8vlTWDq02bkyWW/G7gZ3hkbBhRUK/WnNyr2vwWoOgwx5CfTRMjKkPkfD/+jffkfNfdGmGcg9yfnqPP9/AizKzWTsXSeS+0jZ8Nw5tiYFW+lpceqlzwzKdTHug7Vs0QomUPccRtZB/TBBEuiC7YzrvLg4Amu0I48ETAcch/ztt00nx/oj/fu1DTnz4Iz4ilrNY+WVIEfDz/n3mz+PKI9kM+ZeB0jAuyLsiC7skGpIVGX/2HqmZTtJKBZCoveAiVAgMBAAGjgZkwgZYwSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TAJBgNVHRMEAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAsGA1UdDwQEAwIFoDAdBgNVHQ4EFgQUYSkb2hkZx8swY0GRjtKAeIwaBNwwDQYJKoZIhvcNAQELBQADggEBAJZOakWgjfY359glviVffBQFxFS6C+4WjYDYzvzjWHUQoGBFKTHG4xUmTVW7y5GnPSvIlkaj49SzbD9KuiTc77GHyFCTwYMz+qITgbDg3/ao/x/be4DD/k/byWqW4Rb8OSYCshX/fNI4Xu+hxazh179taHX4NaH92ReLVyXNYsooq7mE5YhR9Qsiy35ORviQLrgFrMCGCxT9DWlFBuiPWIOqN544sL9OzFMz+bjqjCoAE/xfIJjI7H7SqGFNrx/8/IuF0hvZbO3bLIz+BOR1L2O+qT728wK6womnp2LLANTPbwu7nf39rpP182WW+xw2z9MKYwwMDwGR1iTYnD4/Sjw= -------------------------------------------------------------------------------- /pycharm激活方案汇总/激活方案四/README.MD: -------------------------------------------------------------------------------- 1 | - 获取激活码[JetBrains 产品正版激活码](http://jets.idejihuo.com/) -------------------------------------------------------------------------------- /python2encrypt/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:30 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | import base64 6 | 7 | 8 | def base64_encode(text): 9 | encode_data = base64.b64encode(text.encode()) 10 | return encode_data 11 | 12 | 13 | def base64_decode(encode_data): 14 | decode_data = base64.b64decode(encode_data) 15 | return decode_data 16 | 17 | 18 | if __name__ == '__main__': 19 | text = 'I love Python!' 20 | encode_data = base64_encode(text) 21 | decode_data = base64_decode(encode_data) 22 | print('Base64 编码:', encode_data) 23 | print('Base64 解码:', decode_data) -------------------------------------------------------------------------------- /python2encrypt/base64_encrypt.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:40 下午 3 | # @File: base64_encrypt.py 4 | # @Author: liyf 5 | import base64 6 | from loguru import logger 7 | 8 | 9 | def base64_encode(encrypt_str): 10 | """ 11 | 编码 12 | :param str: 待编码的内容 13 | :return: 编码后的结果,返回字节类型 14 | """ 15 | # base64.b64encode(str) 报错:TypeError: a bytes-like object is required, not 'str' 16 | # 解决:str指定encode 17 | encode_res = base64.b64encode(encrypt_str.encode()) 18 | return encode_res 19 | 20 | 21 | def base64_decode(encode_res): 22 | """ 23 | 解码 24 | :param str: 待解码的内容 25 | :return: 解码后的结果 26 | """ 27 | decode_res = base64.b64decode(encode_res) 28 | return decode_res 29 | 30 | 31 | if __name__ == '__main__': 32 | encrypt_str = '123456' 33 | logger.info(f'待编码内容: {encrypt_str}') # 待编码内容: 123456 34 | encode_res = base64_encode(encrypt_str) 35 | logger.info(f'Base64 编码结果: {encode_res}') # Base64 编码结果: b'dXRmOA==' 36 | 37 | decode_res = base64_decode(encode_res) 38 | logger.info(f'待解码内容: {encode_res}') # 待解码内容: b'dXRmOA==' 39 | logger.info(f'Base64 解码结果: {decode_res}') # Base64 解码结果: b'123456' 40 | -------------------------------------------------------------------------------- /python2encrypt/md5_encrypt.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:31 下午 3 | # @File: md5_encrypt.py 4 | # @Author: liyf 5 | 6 | import hashlib 7 | from loguru import logger 8 | 9 | 10 | def encrypt(str) -> str: 11 | """ 12 | 实现md5加密 13 | :param str: 待加密字符串 14 | :return: 加密后的结果 15 | """ 16 | md5 = hashlib.md5() 17 | # md5.update(str) 报错信息:TypeError: Unicode-objects must be encoded before hashing 18 | # 解决:必须指定encode 19 | md5.update(str.encode('utf8')) 20 | return md5.hexdigest() 21 | 22 | 23 | if __name__ == '__main__': 24 | encrypt_str = '123456' 25 | logger.info(f'md5加密前为: {encrypt_str}') # md5加密前为: 123456 26 | res = encrypt(encrypt_str) 27 | logger.info(f'md5加密后为: {res}') # md5加密后为: e10adc3949ba59abbe56e057f20f883e 28 | -------------------------------------------------------------------------------- /python2encrypt/rsa_encrypt.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:01 下午 3 | # @File: rsa_encrypt.py 4 | # @Author: liyf 5 | 6 | import rsa 7 | 8 | 9 | def encrypt(public_key, encrypt_str): 10 | """ 11 | 加密 12 | :param public_key: 公钥 13 | :param encrypt_res: 待加密内容 14 | :return: 加密后结果 15 | """ 16 | encrypt_res = rsa.encrypt(encrypt_str.encode('utf8'), public_key) 17 | return encrypt_res 18 | 19 | 20 | def decrypt(private_key, decrypt_res): 21 | """ 22 | 解密 23 | :param private_key: 私钥 24 | :param decrypt_res: 待解密内容 25 | :return: 解密结果 26 | """ 27 | decrypt_res = rsa.decrypt(decrypt_res, private_key).decode('utf8') 28 | return decrypt_res 29 | 30 | 31 | if __name__ == '__main__': 32 | # 生成256位的公钥和私钥 33 | public_key, private_key = rsa.newkeys(256) 34 | print(f'公钥: {public_key}') 35 | # 公钥: PublicKey(80329290882825905238094319536975561780227467875701686277278961529165919738557, 65537) 36 | print(f'私钥: {private_key}') 37 | # 私钥: PrivateKey(80329290882825905238094319536975561780227467875701686277278961529165919738557, 65537, 70670703944811224473393719296632436057098567468736946452812955406438254630273, 63972005125771969816027718000509430022301, 1255694435791011123719403715131447457) 38 | 39 | encrypt_str = '123456' 40 | print(f'待加密内容: {encrypt_str}') # 待加密内容: 123456 41 | encrypt_res = encrypt(public_key, encrypt_str) 42 | print(f'rsa加密结果: {encrypt_res}') 43 | # rsa加密结果: b'SQ\x1f\xac\x9f\x91\xf4K\xc3H)c9\xa6\xf2<\xd4^b\xc2X\x95Z1\xcd\xee\xc0\xb2u\xd6\x90\xaf' 44 | decrypt_res = decrypt(private_key, encrypt_res) 45 | print(f'待解密内容: {encrypt_res}') 46 | # 待解密内容: b'\x9e\xac\x82\x87;A@7\x01\x1co\x06>W\xc9gy\xe3\xdc[l2\x14\xf0!+u\x8f\xe7N\xc4?' 47 | print(f'解密结果: {decrypt_res}') # 解密结果: 123456 48 | -------------------------------------------------------------------------------- /python2encrypt/sha_encrypt.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 6:19 下午 3 | # @File: sha_encrypt.py 4 | # @Author: liyf 5 | 6 | import hashlib 7 | from loguru import logger 8 | 9 | 10 | def sha1(text): 11 | results = hashlib.sha1(text.encode('utf8')).hexdigest() 12 | return results 13 | 14 | 15 | def sha256(text): 16 | results = hashlib.sha256(text.encode('utf8')).hexdigest() 17 | return results 18 | 19 | 20 | def sha512(text): 21 | results = hashlib.sha512(text.encode('utf8')).hexdigest() 22 | return results 23 | 24 | 25 | if __name__ == '__main__': 26 | text = '123456' 27 | logger.info(f'加密前的字符串: {text}') # 加密前的字符串: 123456 28 | res_sha1 = sha1(text) 29 | logger.success(f'sha1\n\tsha1加密结果: {res_sha1}\n\t长度: {len(res_sha1)}') 30 | # sha1加密结果: 7c4a8d09ca3762af61e59520943dc26494f8941b 31 | # 长度: 40 32 | res_sha256 = sha256(text) 33 | logger.success(f'sha256\n\tsha256加密结果: {res_sha256}\n\t长度: {len(res_sha256)}') 34 | # sha256加密结果: 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92 35 | # 长度: 64 36 | res_sha512 = sha512(text) 37 | logger.success(f'sha512\n\tsha512加密结果: {res_sha512}\n\t长度: {len(res_sha512)}') 38 | # sha512加密结果: ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413 39 | # 长度: 128 40 | -------------------------------------------------------------------------------- /qimingpian/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:34 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /qimingpian/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:45 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import requests 7 | 8 | from utils import * 9 | 10 | 11 | def get_encrypt_data(): 12 | headers = { 13 | 'Accept': 'application/json, text/plain, */*', 14 | 'Accept-Language': 'zh-CN,zh;q=0.9', 15 | 'Connection': 'keep-alive', 16 | 'Origin': 'https://www.qimingpian.cn', 17 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 18 | 'sec-ch-ua': '".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"', 19 | 'sec-ch-ua-mobile': '?0', 20 | 'sec-ch-ua-platform': '"macOS"', 21 | } 22 | 23 | data = { 24 | 'tag': '', 25 | 'unionid': '', 26 | } 27 | 28 | response = requests.post('https://vipapi.qimingpian.cn/DataList/productListVip', headers=headers, data=data).json() 29 | encrypt_data = response['encrypt_data'] 30 | return encrypt_data 31 | 32 | 33 | def get_decrypt_data(encrypt_data): 34 | ctx = Utils(js_file_name='demo.js').read_js_file() 35 | results = ctx.call('s', encrypt_data) 36 | data_list = results['list'] 37 | for data in data_list: 38 | investor_info = data['investor_info'] 39 | investors = '、'.join([investor['investor'] for investor in investor_info]) 40 | print( 41 | f'项目: {data["product"]}\n业务: {data["yewu"]}\n行业领域: {data["hangye1"]}\n地区: {data["province"]}\n投资轮次: {data["lunci"]}\n投资时间: {data["time"]}\n投资金额: {data["money"]}\n投资方: {investors}') 42 | print('***' * 40) 43 | 44 | 45 | if __name__ == '__main__': 46 | encrypt_data = get_encrypt_data() 47 | get_decrypt_data(encrypt_data) 48 | -------------------------------------------------------------------------------- /remark.md: -------------------------------------------------------------------------------- 1 | ### 生成 `requirements.txt` 2 | 3 | ``` 4 | pipreqs reverse_practice --encoding=utf8 --force 5 | ``` 6 | 7 | *** 8 | 9 | ### 一些常见的乱码 10 | 11 | - 数据来源于爬虫交流群里边,一个大佬发的,如有侵权,请联系本人删除。 12 | ![常见的乱码](images/response_type.png) 13 | 14 | *** 15 | 16 | ### 关于chrome浏览器 17 | 18 | - 逆向定位关键参数时,source面板不显示行号。[解决办法](chrome.md) 19 | 20 | *** 21 | 22 | ### 关于 `pycharm激活码` 和 `chromedriver` 环境的配置 23 | 24 | - [chromedriver](chromedriver.md) 25 | - [pycharm激活码配置](pycharm激活方案汇总) 26 | 27 | *** 28 | 29 | ### 忽略某个目录或者文件 30 | 31 | - 由于 `node_modules` 太大,且默认是可以被上传的。所以我们需要创建一个 `.gitignore` 文件,目的是忽略上传某个文件或者文件夹。 32 | - 步骤如下: 33 | > 创建 `.gitignore` 文件 34 | ```text 35 | cd reverse_practice 36 | touch .gitignore 37 | ``` 38 | > 创建好文件之后,在里边添加需要忽略的目录和文件即可 39 | - 忽略规则如下: 40 | ```text 41 | target // 忽略这个target目录 42 | angular.json // 忽略这个angular.json文件 43 | log/* // 忽略log下的所有文件 44 | css/*.css // 忽略css目录下的.css文件 45 | ``` 46 | 47 | *** 48 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | loguru==0.5.3 2 | requests==2.25.1 3 | ddddocr==1.4.4 4 | PyExecJS==1.5.1 5 | Js2Py==0.71 6 | lxml==4.6.3 7 | rsa==4.7.2 8 | fontTools==4.39.3 9 | -------------------------------------------------------------------------------- /souhu/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:42 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /souhu/demo.js: -------------------------------------------------------------------------------- 1 | /* 2 | 搜狐网,新闻详情页(https://www.sohu.com/a/611710835_123753) 3 | 图片解密 4 | 请求url地址,返回响应数据,返回的图片地址是加密的,但是所在的img标签的属性为data-src 5 | 6 | 故全局搜索data-src关键字,定位到关键代码 7 | aes解密 8 | */ 9 | 10 | window = global; 11 | var CryptoJS = require('crypto-js') 12 | 13 | function e(e, t) { 14 | return CryptoJS.AES.decrypt(e, CryptoJS.enc.Utf8.parse(t), { 15 | mode: CryptoJS.mode.ECB, 16 | padding: CryptoJS.pad.Pkcs7 17 | }).toString(CryptoJS.enc.Utf8) 18 | } 19 | 20 | var o = '9T8IQfyP7e1sMsEyWbYPvujwr47D8luFD15aBAmwHor+FqTy1mjFyNrrLjJO3WxqRwAgxG5o8r1Lcqis/SEI2lID2kTy3JccQzzIBZfATLE=', 21 | s = e(o, "www.souhu.com6666"), 22 | url = 'https:' + s; 23 | console.log('需要解密的data-src值:', o) 24 | console.log('解密后的值:', url) 25 | -------------------------------------------------------------------------------- /stream_capital/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:33 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /stream_capital/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js'); 2 | var nh = CryptoJS.enc.Utf8.parse("r4rt5A8L6ye6ts8y"), 3 | rh = CryptoJS.enc.Utf8.parse("fs0Hkjg8a23u8sE0"), 4 | oh = { 5 | Decrypt: function (e) { 6 | if (0 === e.length) 7 | return e; 8 | var t = CryptoJS.AES.decrypt(e, nh, { 9 | iv: rh, 10 | mode: CryptoJS.mode.CBC, 11 | padding: CryptoJS.pad.Pkcs7 12 | }) 13 | , n = CryptoJS.enc.Utf8.stringify(t); 14 | return JSON.parse(n) 15 | }, 16 | Encrypt: function (e) { 17 | var t = JSON.stringify(e); 18 | return CryptoJS.AES.encrypt(t, nh, { 19 | iv: rh, 20 | mode: CryptoJS.mode.CBC, 21 | padding: CryptoJS.pad.Pkcs7 22 | }).toString() 23 | } 24 | }; 25 | 26 | function get_enc_para(page) { 27 | var params = { 28 | "type": 0, 29 | "name": null, 30 | "page": page 31 | }; 32 | return oh.Encrypt(params) 33 | } 34 | -------------------------------------------------------------------------------- /stream_capital/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:33 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import execjs 7 | import requests 8 | 9 | from loguru import logger 10 | 11 | f = open('demo.js', 'r') 12 | js_str = f.read() 13 | ctx = execjs.compile(''.join(js_str)) 14 | 15 | headers = { 16 | "authority": "api.yuanchuan.cn", 17 | "accept": "application/json, text/plain, */*", 18 | "accept-language": "zh-CN,zh;q=0.9", 19 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36" 20 | } 21 | url = "https://api.yuanchuan.cn/yc/webbloglist?apptype=9" 22 | 23 | 24 | def get_results(page): 25 | enc_para = ctx.call('get_enc_para', page) 26 | logger.info(f'第{page}页请求参数: {enc_para}') 27 | response = requests.post(url, headers=headers, data=enc_para) 28 | return response.json() 29 | 30 | 31 | def get_decrypt_data(): 32 | for page in range(1, 11): 33 | results = get_results(page) 34 | decrypt_data = ctx.call('oh.Decrypt', results['data']) 35 | data_list = decrypt_data['list'] 36 | for data in data_list: 37 | title = data['title'] 38 | user_name = data['userName'] 39 | content = data['content'] 40 | post_date = data['ctime'] 41 | theme = data['themeTitle'] 42 | tags = '、'.join([tag['tagName'] for tag in data['tags']]) 43 | print(f'标题: {title}\n内容: {content}\n作者: {user_name}\t更新日期: {post_date}\n标签: {tags}\t主题标题: {theme}') 44 | print('===' * 20) 45 | print('***' * 30) 46 | break 47 | 48 | 49 | def main(): 50 | get_decrypt_data() 51 | 52 | 53 | if __name__ == '__main__': 54 | main() 55 | -------------------------------------------------------------------------------- /tonghuashun/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:21 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /tonghuashun/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:36 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import requests 7 | 8 | from lxml import etree 9 | 10 | from utils import * 11 | 12 | 13 | headers = { 14 | "Accept": "text/html, */*; q=0.01", 15 | "Accept-Language": "zh-CN,zh;q=0.9", 16 | "Cache-Control": "no-cache", 17 | "Pragma": "no-cache", 18 | "Proxy-Connection": "keep-alive", 19 | "Referer": "http://q.10jqka.com.cn/", 20 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36", 21 | "X-Requested-With": "XMLHttpRequest", 22 | } 23 | 24 | 25 | def get_results(page): 26 | ctx = Utils(js_file_name='demo.js').read_js_file() 27 | hexin_v = ctx.call('get_cookie') 28 | headers['hexin-v'] = hexin_v 29 | headers['cookie'] = f'v={hexin_v};' 30 | logger.info(f'hexin-v: {hexin_v}') 31 | url = f"http://q.10jqka.com.cn/index/index/board/all/field/zdf/order/desc/page/{page}/ajax/1/" 32 | response = requests.get(url, headers=headers, verify=False) 33 | return response.text 34 | 35 | 36 | def parse(): 37 | for page in range(1, 10): 38 | html = get_results(page) 39 | response = etree.HTML(html) 40 | tr_list = response.xpath('//tr') 41 | for tr in tr_list[1:]: 42 | item = {} 43 | item['code'] = tr.xpath('td[2]/a/text()')[0] # 股票代码 44 | item['name'] = tr.xpath('td[3]/a/text()')[0] # 股票名称 45 | item['cur_price'] = tr.xpath('td[4]/text()')[0] # 现价 46 | item['up_down_rate'] = tr.xpath('td[5]/text()')[0] # 涨跌幅 47 | item['up_down'] = tr.xpath('td[6]/text()')[0] # 涨跌 48 | item['up_speed'] = tr.xpath('td[7]/text()')[0] # 涨速 49 | item['change_hand'] = tr.xpath('td[8]/text()')[0] # 换手 50 | item['volume_rate'] = tr.xpath('td[9]/text()')[0] # 量比 51 | item['amplitude'] = tr.xpath('td[10]/text()')[0] # 振幅 52 | item['volume_business'] = tr.xpath('td[11]/text()')[0] # 成交额 53 | item['tradable_share'] = tr.xpath('td[12]/text()')[0] # 流通股 54 | item['tradable_market_value'] = tr.xpath('td[13]/text()')[0] # 流通市值 55 | item['earn_ratio'] = tr.xpath('td[14]/text()')[0] # 市盈率 56 | print(item) 57 | logger.info(f'第 {page} 页抓取结束~') 58 | 59 | 60 | if __name__ == '__main__': 61 | parse() 62 | -------------------------------------------------------------------------------- /tousu_sign/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:23 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /tousu_sign/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:55 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import time 7 | import requests 8 | 9 | from utils import * 10 | 11 | 12 | def get_req_params(page): 13 | ctx = Utils(js_file_name='demo.js').read_js_file() 14 | return ctx.call('get_signature', page) 15 | 16 | 17 | def ts2time(ts): 18 | time_local = time.localtime(ts) 19 | dt = time.strftime("%Y-%m-%d", time_local) 20 | return dt 21 | 22 | 23 | def get_results(page): 24 | headers = { 25 | 'accept': 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01', 26 | 'accept-language': 'zh-CN,zh;q=0.9', 27 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36', 28 | 'x-requested-with': 'XMLHttpRequest', 29 | } 30 | req_params = get_req_params(page) 31 | params = { 32 | 'ts': req_params['ts'], 33 | 'rs': req_params['rs'], 34 | 'signature': req_params['signature'], 35 | 'couid': '6384912431', 36 | 'sid': '26873', 37 | 'page_size': '10', 38 | 'page': str(page), 39 | } 40 | response = requests.get('https://tousu.sina.com.cn/api/company/service_complaints', params=params, headers=headers) 41 | return response.json() 42 | 43 | 44 | def parse(): 45 | for page in range(1, 20): 46 | results = get_results(page) 47 | data_list = results['result']['data']['complaints'] 48 | for data in data_list: 49 | title = data['main']['title'] 50 | cotitle = data['main']['cotitle'] 51 | appeal = data['main']['appeal'] 52 | dz = data['main']['upvote_amount'] 53 | zf = data['main']['share_amount'] 54 | pl = data['main']['comment_amount'] 55 | summary = data['main']['summary'] 56 | author = data['author']['title'] if 'title' in data['author'].keys() else '未知' 57 | ts = data['main']['timestamp'] 58 | # dt = ts2time(int(ts)) 59 | print( 60 | f'标题: {title}\n投诉人: {author} 在 {ts} 于黑猫投诉平台发起\n投诉对象: {cotitle}\n投诉要求: {appeal}\n投诉内容: {summary}\n点赞数({dz})评论数({pl})转发数({zf})') 61 | print('===' * 35) 62 | 63 | 64 | if __name__ == '__main__': 65 | parse() 66 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:37 下午 3 | # @File: utils.py 4 | # @Author: liyf 5 | 6 | import execjs 7 | import hashlib 8 | 9 | import ddddocr 10 | 11 | from loguru import logger 12 | 13 | ocr = ddddocr.DdddOcr(show_ad=False) 14 | 15 | 16 | class Utils: 17 | def __init__(self, js_file_name=None, origin_md5_str=None): 18 | ''' 19 | 初始化参数 20 | :param js_file_name: 需要读取的js文件名称 21 | :param origin_md5_str: 需要进行md5加密的字符串 22 | ''' 23 | self.js_file_name = js_file_name 24 | self.origin_md5_str = origin_md5_str 25 | 26 | def read_js_file(self): 27 | f = open(self.js_file_name, 'r', encoding='utf8') 28 | js_str = f.read() 29 | ctx = execjs.compile(''.join(js_str)) 30 | return ctx 31 | 32 | def encrypt_md5(self) -> str: 33 | md5 = hashlib.md5() 34 | md5.update(self.origin_md5_str.encode('utf8')) 35 | return md5.hexdigest() 36 | -------------------------------------------------------------------------------- /waitpay/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:02 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /waitpay/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:02 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 主页: https://static.waitwaitpay.com/web/sd_se/index.html#/ 8 | 9 | 参考文章: https://mp.weixin.qq.com/s/EQnBJwD8Uo6dHZ6RRPGhFQ 10 | 11 | webpack加密 12 | 采用自吐的办法,快速补全解密所需的模块 13 | 14 | todo 步骤: 15 | - 找到分发器,添加以下代码(首先需要在头部定义`var map_ = {}, code_ = '';`) 16 | ``` 17 | function n(r) { 18 | if (t[r]) 19 | return t[r].exports; 20 | var o = t[r] = { 21 | i: r, 22 | l: !1, 23 | exports: {} 24 | }; 25 | ================================================== 26 | // 自吐,只需要添加这几行代码即可,code_这个变量里面存的是导出的代码 27 | if (typeof (map_[r]) == "undefined") { 28 | map_[r] = 1; 29 | code_ = code_ + '"' + r + '":' + e[r] + ','; 30 | } 31 | ================================================== 32 | return e[r].call(o.exports, o, o.exports, n), 33 | o.l = !0, 34 | o.exports 35 | } 36 | ``` 37 | - 找到所有的模块,全部copy至本地,使用自吐的办法,在本地输出_code即可 38 | - 优点 39 | - 速度快,省去了扣代码的步骤 40 | ''' 41 | import requests 42 | 43 | from utils import * 44 | 45 | 46 | def get_decrypt_data(encrypt_data): 47 | # 传入加密数据,返回明文数据 48 | ctx = Utils(js_file_name='demo.js').read_js_file() 49 | return ctx.call('decrypt', encrypt_data) 50 | 51 | 52 | def get_encrypt_data(page): 53 | # 传入参数page,获取响应加密数据 54 | headers = { 55 | 'authority': 'api.waitwaitpay.com', 56 | 'accept': '*/*', 57 | 'accept-language': 'zh-CN,zh;q=0.9', 58 | 'cache-control': 'no-cache', 59 | 'origin': 'https://static.waitwaitpay.com', 60 | 'sec-ch-ua': '"Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"', 61 | 'sec-ch-ua-mobile': '?0', 62 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36', 63 | } 64 | params = { 65 | 'latitude': '39.9349', 66 | 'longitude': '116.454', 67 | 'page': str(page), 68 | # 'request_id': '5e50f62c-6662-4213-acd3-ec50ad7b8862', 69 | 'type': 'all', 70 | 'with_vouchers': 'false', 71 | } 72 | response = requests.get('https://api.waitwaitpay.com/api/vendors/nearby', params=params, headers=headers) 73 | return response.text 74 | 75 | 76 | def parse(): 77 | for page in range(1, 10): 78 | encrypt_data = get_encrypt_data(page) 79 | decrypt_data = get_decrypt_data(encrypt_data) 80 | data_list = decrypt_data['result']['list'] 81 | for data in data_list: 82 | shop_name = data['name'] 83 | brand = data['brand'] 84 | phone = data['phone'] 85 | city = data['city_name'] 86 | cate = data['category_name'] 87 | address = data['address'] 88 | avg_price = data['avg_price'] 89 | tag_list = data['recommand_vouchers'] 90 | tag = ';'.join([tag['title'] for tag in tag_list]) 91 | discount_rate = data['discount_rate'] 92 | print( 93 | f'店铺名称: {shop_name}\n品牌: {brand}\n电话: {phone}\n类别: {cate}\n标签: {tag}\n城市及详细地址: {city};{address}\n人均{avg_price},折扣: {discount_rate}折') 94 | print('===' * 20) 95 | 96 | 97 | if __name__ == '__main__': 98 | parse() 99 | -------------------------------------------------------------------------------- /webapi/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:04 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /webapi/demo.js: -------------------------------------------------------------------------------- 1 | function get_mcode() { 2 | var e = Math.floor((new Date).getTime() / 1e3); 3 | var input = "" + e; 4 | var keyStr = "ABCDEFGHIJKLMNOP" + "QRSTUVWXYZabcdef" + "ghijklmnopqrstuv" + "wxyz0123456789+/" + "="; 5 | var output = ""; 6 | var chr1, chr2, chr3 = ""; 7 | var enc1, enc2, enc3, enc4 = ""; 8 | var i = 0; 9 | do { 10 | chr1 = input.charCodeAt(i++); 11 | chr2 = input.charCodeAt(i++); 12 | chr3 = input.charCodeAt(i++); 13 | enc1 = chr1 >> 2; 14 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 15 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 16 | enc4 = chr3 & 63; 17 | if (isNaN(chr2)) { 18 | enc3 = enc4 = 64; 19 | } else if (isNaN(chr3)) { 20 | enc4 = 64; 21 | } 22 | output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) 23 | + keyStr.charAt(enc3) + keyStr.charAt(enc4); 24 | chr1 = chr2 = chr3 = ""; 25 | enc1 = enc2 = enc3 = enc4 = ""; 26 | } while (i < input.length); 27 | console.log(output) 28 | return output; 29 | } 30 | get_mcode() 31 | -------------------------------------------------------------------------------- /webapi/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:19 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import execjs 7 | import requests 8 | 9 | from utils import * 10 | 11 | 12 | def get_mcode(): 13 | ctx = Utils(js_file_name='demo.js').read_js_file() 14 | return ctx.call('get_mcode') 15 | 16 | 17 | def get_results(): 18 | """ 19 | 请求头中 `Referer` 参数不能缺,否则报错: 20 | {"resultmsg":"未经授权的访问,code:005","resultcode":401} 21 | """ 22 | headers = { 23 | 'Accept': 'application/json, text/javascript, */*; q=0.01', 24 | 'Accept-Language': 'zh-CN,zh;q=0.9', 25 | 'Referer': 'https://webapi.cninfo.com.cn/', 26 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 27 | 'X-Requested-With': 'XMLHttpRequest', 28 | 'mcode': get_mcode(), 29 | } 30 | response = requests.post('https://webapi.cninfo.com.cn/api/sysapi/p_sysapi1128', headers=headers) 31 | return response.json() 32 | 33 | 34 | def parse(): 35 | records = get_results()['records'] 36 | index = 0 37 | for record in records: 38 | index += 1 39 | print( 40 | f'序号: {index}\n证券代码: {record["SECCODE"]}\n资讯类型: {record["F003V"]}\n发布时间: {record["DECLAREDATE"]}\n资讯标题: {record["F001V"]}\n公告摘要: {record["F002V"]}') 41 | print('===' * 35) 42 | 43 | 44 | if __name__ == '__main__': 45 | # https://webapi.cninfo.com.cn/#/aiInfos 46 | parse() 47 | -------------------------------------------------------------------------------- /weibotop/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:39 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /weibotop/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js'); 2 | 3 | let s = CryptoJS.SHA1(CryptoJS.enc.Utf8.parse("tSdGtmwh49BcR1irt18mxG41dGsBuGKS")) 4 | , a = CryptoJS.enc.Hex.parse(s.toString(CryptoJS.enc.Hex).substr(0, 32)); 5 | 6 | function l(t) { 7 | var e = t 8 | , i = a 9 | , o = CryptoJS.AES.encrypt(e, i, { 10 | mode: CryptoJS.mode.ECB, 11 | padding: CryptoJS.pad.Pkcs7 12 | }); 13 | return CryptoJS.enc.Base64.stringify(o.ciphertext) 14 | } 15 | 16 | function h(t) { 17 | let e = (i = t = String(t), 18 | o = CryptoJS.enc.Base64.parse(i), 19 | r = a, 20 | CryptoJS.AES.decrypt({ 21 | ciphertext: o 22 | }, r, { 23 | mode: CryptoJS.mode.ECB, 24 | padding: CryptoJS.pad.Pkcs7 25 | }).toString(CryptoJS.enc.Utf8)); 26 | var i, o, r; 27 | return JSON.parse(e) 28 | } 29 | -------------------------------------------------------------------------------- /weibotop/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:57 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import execjs 7 | import requests 8 | 9 | from loguru import logger 10 | 11 | f = open('demo.js', 'r') 12 | js_str = f.read() 13 | ctx = execjs.compile(''.join(js_str)) 14 | 15 | headers = { 16 | "authority": "api.weibotop.cn", 17 | "accept": "application/json, text/javascript, */*; q=0.01", 18 | "accept-language": "zh-CN,zh;q=0.9", 19 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36" 20 | } 21 | 22 | 23 | def get_timeid_dec_data(timeid, encrypt_data): 24 | if timeid: 25 | return ctx.call('l', timeid) 26 | return ctx.call('h', encrypt_data) 27 | 28 | 29 | def get_latest_date(): 30 | ''' 31 | 获取最新一次的热搜日期 32 | :return: 33 | ''' 34 | url = "https://api.weibotop.cn/getlatest" 35 | response = requests.get(url, headers=headers) 36 | return response.json() 37 | 38 | 39 | def get_data(timeid): 40 | url = "https://api.weibotop.cn/currentitems" 41 | enc_timeid = get_timeid_dec_data(timeid, encrypt_data=None) 42 | logger.info(f'timeid: {enc_timeid}') 43 | params = { 44 | "timeid": enc_timeid 45 | } 46 | response = requests.get(url, headers=headers, params=params) 47 | return response.text 48 | 49 | 50 | def main(): 51 | latest_res = get_latest_date() 52 | timeid = latest_res[0] 53 | latest_date = latest_res[1] 54 | logger.info(f'最近一次更新日期为: {latest_date}') 55 | encrypt_data = get_data(timeid) 56 | decrypt_data = get_timeid_dec_data(timeid=None, encrypt_data=encrypt_data) 57 | for data in decrypt_data: 58 | title = data[0] 59 | rank_list_date = data[1] 60 | last_rank_list = data[2] 61 | heat = data[3] 62 | print(f'热搜名称: {title}\n上榜时间: {rank_list_date}\n最后在榜: {last_rank_list}\n热度: {heat}') 63 | print('***' * 20) 64 | 65 | 66 | if __name__ == '__main__': 67 | main() 68 | -------------------------------------------------------------------------------- /xhpfmapi/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:48 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /xhpfmapi/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js'), 2 | v = CryptoJS.enc.Utf8.parse(CryptoJS.MD5("Xinhuamm@2018").toString()); 3 | 4 | function decrypt(t) { 5 | var data = CryptoJS.TripleDES.decrypt({ 6 | ciphertext: CryptoJS.enc.Base64.parse(t.data) 7 | }, v, { 8 | mode: CryptoJS.mode.ECB, 9 | padding: CryptoJS.pad.Pkcs7 10 | }); 11 | return data.toString(CryptoJS.enc.Utf8); 12 | } 13 | 14 | function get_encrypt_params(params) { 15 | var n = JSON.stringify(params), 16 | s = CryptoJS.TripleDES.encrypt(n, v, { 17 | mode: CryptoJS.mode.ECB, 18 | padding: CryptoJS.pad.Pkcs7 19 | }); 20 | return CryptoJS.enc.Base64.stringify(s.ciphertext); 21 | } 22 | -------------------------------------------------------------------------------- /xhpfmapi/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:06 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 8 | 全局搜索关键字 'decrypt(' 即可定位到关键代码 9 | 10 | des加密 11 | 12 | 'Xinhuamm@2018' 进行md5加密得到的结果就是des的key 13 | ''' 14 | 15 | import requests 16 | import json 17 | import datetime 18 | 19 | from utils import * 20 | 21 | headers = { 22 | "authority": "xhpfmapi.zhongguowangshi.com", 23 | "accept": "application/json, text/plain, */*", 24 | "content-type": "application/json;charset=UTF-8", # 必须携带该请求头 25 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" 26 | } 27 | 28 | ctx = Utils(js_file_name='demo.js').read_js_file() 29 | 30 | url = "https://xhpfmapi.zhongguowangshi.com/v600/core/columnnewslist" 31 | 32 | 33 | def get_js_results(params, response_data): 34 | if params: 35 | results = ctx.call('get_encrypt_params', params) 36 | else: 37 | results = ctx.call('decrypt', response_data) 38 | return results 39 | 40 | 41 | def get_results(page): 42 | params = {"cid": "25295", "pn": page, "clientVer": "8.8.2", "clientLable": "h5", "source": 0, "userID": ""} 43 | param = get_js_results(params, response_data=None) 44 | logger.info(f'第 {page} 页参数: {param}') 45 | data = { 46 | "param": param 47 | } 48 | data = json.dumps(data, separators=(',', ':')) 49 | response = requests.post(url, headers=headers, data=data) 50 | encrypt_data = response.json() 51 | decrypt_data = get_js_results(params=None, response_data=encrypt_data) 52 | return json.loads(decrypt_data) 53 | 54 | 55 | def trans_ts(ts): 56 | timestamp = ts / 1000 # 将毫秒转换为秒 57 | dt = datetime.datetime.fromtimestamp(timestamp) 58 | return dt 59 | 60 | 61 | def main(): 62 | for page in range(1, 10): 63 | results = get_results(page) 64 | news_list = results['newsList'] 65 | for news in news_list: 66 | title = news['topic'] 67 | comment_count = news['commentCount'] 68 | detail_url = news['detailurl'] 69 | ts = news['relaseDateTimeStamp'] 70 | update_date = trans_ts(ts) 71 | print(f'标题: {title}\n评论数量: {comment_count}\n发布时间: {update_date}\n详情链接: {detail_url}') 72 | print('===' * 30) 73 | 74 | 75 | if __name__ == '__main__': 76 | main() 77 | -------------------------------------------------------------------------------- /xiniu/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:48 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /xiniu/demo.js: -------------------------------------------------------------------------------- 1 | var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" 2 | , _p = "W5D80NFZHAYB8EUI2T649RT2MNRMVE2O"; 3 | 4 | // c.c 5 | function e1(t) { 6 | if (null == t) 7 | return null; 8 | for (var e, n, r, o, i, a, c, u = "", s = 0; s < t.length;) 9 | o = (e = t.charCodeAt(s++)) >> 2, 10 | i = (3 & e) << 4 | (n = t.charCodeAt(s++)) >> 4, 11 | a = (15 & n) << 2 | (r = t.charCodeAt(s++)) >> 6, 12 | c = 63 & r, 13 | isNaN(n) ? a = c = 64 : isNaN(r) && (c = 64), 14 | u = u + _keyStr.charAt(o) + _keyStr.charAt(i) + _keyStr.charAt(a) + _keyStr.charAt(c); 15 | return u 16 | } 17 | 18 | // c.d 19 | function e2(t) { 20 | if (null == (t = _u_e(t))) 21 | return null; 22 | for (var e = "", n = 0; n < t.length; n++) { 23 | var r = _p.charCodeAt(n % _p.length); 24 | e += String.fromCharCode(t.charCodeAt(n) ^ r) 25 | } 26 | return e 27 | } 28 | 29 | function _u_e(t) { 30 | if (null == t) 31 | return null; 32 | t = t.replace(/\r\n/g, "\n"); 33 | for (var e = "", n = 0; n < t.length; n++) { 34 | var r = t.charCodeAt(n); 35 | r < 128 ? e += String.fromCharCode(r) : r > 127 && r < 2048 ? (e += String.fromCharCode(r >> 6 | 192), 36 | e += String.fromCharCode(63 & r | 128)) : (e += String.fromCharCode(r >> 12 | 224), 37 | e += String.fromCharCode(r >> 6 & 63 | 128), 38 | e += String.fromCharCode(63 & r | 128)) 39 | } 40 | return e 41 | } 42 | 43 | function get_payload(start) { 44 | var l = { 45 | payload: { 46 | limit: 20, 47 | sort: 1, 48 | start: start 49 | } 50 | } 51 | return e1(e2(JSON.stringify(l.payload))) 52 | } 53 | 54 | function d1(t) { 55 | var e, n, r, o, i, a, c = "", u = 0; 56 | for (t = t.replace(/[^A-Za-z0-9\+\/\=]/g, ""); u < t.length;) 57 | e = _keyStr.indexOf(t.charAt(u++)) << 2 | (o = _keyStr.indexOf(t.charAt(u++))) >> 4, 58 | n = (15 & o) << 4 | (i = _keyStr.indexOf(t.charAt(u++))) >> 2, 59 | r = (3 & i) << 6 | (a = _keyStr.indexOf(t.charAt(u++))), 60 | c += String.fromCharCode(e), 61 | 64 != i && (c += String.fromCharCode(n)), 62 | 64 != a && (c += String.fromCharCode(r)); 63 | return c 64 | } 65 | 66 | function d2(t) { 67 | for (var e = "", n = 0; n < t.length; n++) { 68 | var r = _p.charCodeAt(n % _p.length); 69 | e += String.fromCharCode(t.charCodeAt(n) ^ r) 70 | } 71 | return _u_d(e) 72 | } 73 | 74 | function _u_d(t) { 75 | for (var e = "", n = 0, r = 0, o = 0, i = 0; n < t.length;) 76 | (r = t.charCodeAt(n)) < 128 ? (e += String.fromCharCode(r), 77 | n++) : r > 191 && r < 224 ? (o = t.charCodeAt(n + 1), 78 | e += String.fromCharCode((31 & r) << 6 | 63 & o), 79 | n += 2) : (o = t.charCodeAt(n + 1), 80 | i = t.charCodeAt(n + 2), 81 | e += String.fromCharCode((15 & r) << 12 | (63 & o) << 6 | 63 & i), 82 | n += 3); 83 | return e 84 | } 85 | 86 | function get_decrypt_data(encrypt_data) { 87 | var d = d1(encrypt_data), 88 | y = d2(d) 89 | return y; 90 | } 91 | -------------------------------------------------------------------------------- /xiniu/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 6:03 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | """ 7 | todo: 8 | - 网站: https://www.xiniudata.com/industry/newest?from=data 9 | - 数据接口: https://www.xiniudata.com/api2/service/x_service/person_industry_list/list_industries_by_sort ,post请求,请求参数 payload, sig 10 | 11 | changelog 20220819 12 | 该网站有两处需要进行破解 13 | 1. 请求参数 payload 和 sig 14 | - 定位参数加密位置。使用常规的全局搜索这两个参数,搜索到的结果太多,不太好分析。此时我们采用 XHR 断点进行分析。 15 | - '/person_industry_list/list_industries_by_sort',下拉刷新数据,xhr断点生效。 16 | - 此时在断点生效的这个js文件中,第19090到19093行,会发现以下代码 17 | todo 18 | ''' 19 | var f = Object(c.c)(Object(c.d)(JSON.stringify(l.payload))) 20 | , p = Object(c.e)(f); 21 | l.payload = f, 22 | l.sig = p 23 | ''' 24 | - 该地方就是请求参数的加密位置 25 | - 扣js代码,缺啥补啥,此时生成的是payload参数 26 | - sig参数的加密逻辑 27 | - 对 `payload + W5D80NFZHAYB8EUI2T649RT2MNRMVE2O` 组成的字符串进行md5加密,取大写 28 | - 经过测试,大写和小写都行,无所谓 29 | - 不过为了和接口里边的请求参数形式一致,还是取大写 30 | 2. 接口返回的数据是加密后的,需要解密 31 | - 还是在xhr断点生效的这个js文件中,第19113和19115行发现以下代码 32 | todo 33 | ''' 34 | var d = Object(c.a)(l) 35 | , y = Object(c.b)(d) 36 | , v = JSON.parse(y); 37 | ''' 38 | - 此时,v 就是解密后的数据 39 | """ 40 | 41 | import json 42 | import execjs 43 | import hashlib 44 | import requests 45 | 46 | from utils import * 47 | 48 | 49 | def get_data(start, encrypt_data): 50 | """ 51 | 解析js文件,当 encrypt_data 不存在时,说明start存在,此时解析请求参数payload; 52 | 当 start 不存在时,说明encrypt_data存在,此时对返回数据解密进行解析 53 | :param start: 解析参数payload时,需要的参数 54 | :param encrypt_data: 返回结果解密,需要的参数 55 | :return: result 56 | """ 57 | ctx = Utils(js_file_name='demo.js').read_js_file() 58 | if not encrypt_data: 59 | callback = 'get_payload' 60 | params = start 61 | else: 62 | callback = 'get_decrypt_data' 63 | params = encrypt_data 64 | return ctx.call(str(callback), params) 65 | 66 | 67 | def get_results(page, start): 68 | headers = { 69 | 'authority': 'www.xiniudata.com', 70 | 'accept': 'application/json', 71 | 'accept-language': 'zh-CN,zh;q=0.9', 72 | 'origin': 'https://www.xiniudata.com', 73 | 'referer': 'https://www.xiniudata.com/industry/newest?from=data', 74 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36', 75 | } 76 | payload = get_data(start=start, encrypt_data=None) 77 | sig = Utils(origin_md5_str=f'{payload}W5D80NFZHAYB8EUI2T649RT2MNRMVE2O').encrypt_md5() 78 | params_dict = {'payload': payload, 'sig': sig} 79 | logger.info(f'第 {page + 1} 页: {params_dict}') 80 | # 请求参数,缺一不可 81 | json_data = { 82 | 'payload': payload, 83 | 'sig': sig.upper(), 84 | 'v': 1, 85 | } 86 | 87 | response = requests.post( 88 | 'https://www.xiniudata.com/api2/service/x_service/person_industry_list/list_industries_by_sort', 89 | headers=headers, json=json_data) 90 | return response.json() 91 | 92 | 93 | def parse(): 94 | for page in range(0, 10): 95 | start = page * 20 96 | results = get_results(page, start) 97 | decrypt_data = get_data(start=None, encrypt_data=results['d']) 98 | encrypt_data_json = json.loads(decrypt_data) 99 | data_list = encrypt_data_json['list'] 100 | for data in data_list: 101 | name = data['name'] 102 | compant_count = data['countCompany'] 103 | event = data['event'] 104 | companyVOs = ', '.join([item['name'] for item in data['companyVOs']]) 105 | update_time = data['updateTime'] 106 | print(f'赛道(数量): {name}({compant_count}) || {event}\n最近获投: {companyVOs}\n最近更新: {update_time}') 107 | print('===' * 35) 108 | 109 | 110 | if __name__ == '__main__': 111 | parse() 112 | -------------------------------------------------------------------------------- /xmly_login/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:30 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /xmly_login/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 4:30 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import requests 7 | 8 | from utils import * 9 | 10 | 11 | def get_nonce(): 12 | headers = { 13 | 'Accept': '*/*', 14 | 'Accept-Language': 'zh-CN,zh;q=0.9', 15 | 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 16 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36', 17 | } 18 | response = requests.get('https://passport.ximalaya.com/web/nonce/1673423703373', headers=headers) 19 | results = response.json() 20 | return results['nonce'] 21 | 22 | 23 | def get_pwd(pwd): 24 | ctx = Utils(js_file_name='get_pwd.js').read_js_file() 25 | return ctx.call('get_pwd', pwd) 26 | 27 | 28 | def get_signature(req_data): 29 | ctx = Utils(js_file_name='get_signature.js').read_js_file() 30 | return ctx.call('F', req_data) 31 | 32 | 33 | def get_results(password): 34 | nonce = get_nonce() 35 | logger.info(f'nonce: {nonce}') 36 | pwd = get_pwd(password) # password:明文密码 37 | logger.info(f'\n明文密码: {password}\n密文密码: {pwd}') 38 | json_data = { 39 | "account": "111111", # 账号 40 | "password": pwd, 41 | "nonce": nonce 42 | } 43 | signature = get_signature(json_data) 44 | logger.info(f'signature: {signature}') 45 | json_data['signature'] = signature 46 | json_data['rememberMe'] = True 47 | headers = { 48 | 'Accept': '*/*', 49 | 'Accept-Language': 'zh-CN,zh;q=0.9', 50 | 'Cache-Control': 'no-cache', 51 | 'Connection': 'keep-alive', 52 | 'Content-Type': 'application/json', 53 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36', 54 | } 55 | response = requests.post('https://passport.ximalaya.com/web/login/pwd/v1', headers=headers, 56 | json=json_data) 57 | return response.json() 58 | 59 | 60 | results = get_results('123456') 61 | msg = results['msg'] 62 | logger.info(f'登录结果: {msg}') # 登录结果: 账号或密码错误 63 | -------------------------------------------------------------------------------- /ybdzpz/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:21 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /ybdzpz/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 6:21 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | - 全局搜索关键字 `decrypt(` 可定位到如下关键代码: 8 | var r = i.decrypt(n, e) 9 | , s = r[r.length - 1]; 10 | return r = r.slice(0, r.length - s), 11 | t.from(r).toString("utf-8") 12 | - 在该处打断点,点击下一页之后,断点会生效。 13 | 14 | - 往前跟栈,可定位到如下代码: 15 | var e = Object(p["a"])(t.data); 16 | - 在该处再打一个断点,点击下一页,断点生效。 17 | - 在控制台输出 t.data,为加密数据 18 | - 在控制台输出 Object(p["a"])(t.data), 为解密后的数据 19 | 20 | - webpack加密,入口为 p = e("7d92")。 21 | - 其中e为分发器, 7d92 为模块名称 22 | - 在该处打断点,重新刷新页面,不要点击下一页,否则断点不会生效。 23 | - 接下来就是扣js代码了,没啥难度 24 | 25 | ''' 26 | 27 | import requests 28 | import json 29 | 30 | from utils import * 31 | 32 | headers = { 33 | "Accept": "application/json, text/plain, */*", 34 | "Accept-Language": "zh-CN,zh;q=0.9", 35 | "Cache-Control": "no-cache", 36 | "Connection": "keep-alive", 37 | "Content-Type": "application/json", 38 | "Origin": "https://ybdzpz.ylbz.gansu.gov.cn", 39 | "Pragma": "no-cache", 40 | "Referer": "https://ybdzpz.ylbz.gansu.gov.cn/hsa-local-prod/web/hallEnter/", 41 | "Sec-Fetch-Dest": "empty", 42 | "Sec-Fetch-Mode": "cors", 43 | "Sec-Fetch-Site": "same-origin", 44 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 45 | } 46 | 47 | ctx = Utils(js_file_name='demo.js').read_js_file() 48 | 49 | 50 | def get_decrypt_data(data): 51 | decrypt_data = ctx.call('decrypt', data) 52 | return decrypt_data 53 | 54 | 55 | def get_results(page): 56 | url = "https://ybdzpz.ylbz.gansu.gov.cn/hsa-pss-pw/web/pw/base/queryRtalPhacBInfo" 57 | data = { 58 | "rtalPhacName": "", 59 | "rtalPhacCode": "", 60 | "uscc": "", 61 | "admdvs": "", 62 | "pageNo": page, 63 | "pageSize": 10 64 | } 65 | data = json.dumps(data, separators=(',', ':')) 66 | response = requests.post(url, headers=headers, data=data) 67 | return response.json() 68 | 69 | 70 | def main(): 71 | for page in range(1, 10): 72 | results = get_results(page) 73 | decrypt_data = get_decrypt_data(results['data']) 74 | data_list = decrypt_data['data'] 75 | for data in data_list: 76 | shop_name = data['rtalPhacName'] 77 | addr = data['addr'] 78 | social_code = data['uscc'] 79 | scope = data['drugBizScp'] 80 | licence_code = data['phacPmtno'] 81 | shop_code = data['rtalPhacCode'] 82 | print( 83 | f'药店名称: {shop_name}\n药店地址: {addr}\n统一社会信用代码: {social_code}\n药店经营范围: {scope}\n药店经营企业许可证号: {licence_code}\n药店代码: {shop_code}') 84 | print('===' * 30) 85 | 86 | 87 | if __name__ == '__main__': 88 | main() 89 | -------------------------------------------------------------------------------- /yiche/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:37 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yiche/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 1:55 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | """ 7 | 获取易车网汽车配置信息 8 | 根据cid获取value,用来拼接字符串,最终进行加密计算得到x-sign 9 | todo:{name: 'pc', value: '19DDD1FBDFF065D3A4DA777D2D7A81EC', cid: '508'}, 10 | {name: 'phone', value: 'DB2560A6EBC65F37A0484295CD4EDD25', cid: '601'}, 11 | {name: 'h5', value: '745DFB2027E8418384A1F2EF1B54C9F5', cid: '601'}, 12 | {name: 'business_applet', value: '64A1071F6C3C3CC68DABBF5A90669C0A', cid: '601'}, 13 | {name: 'wechat', value: 'AF23B0A6EBC65F37A0484395CE4EDD2K', cid: '601'}, 14 | {name: 'tencent', value: '1615A9BDB0374D16AE9EBB3BBEE5353C', cid: '750'} 15 | 16 | 通过搜索关键字 x-sign 定位到代码 17 | 关键代码: r = "cid=" + t.cid + "¶m=" + n + o + t.timestamp, 18 | u = (0, x.md5)(r); 19 | 计算出来的u就是x-sign的值,经测试,r经过md5加密就是u的值 20 | """ 21 | 22 | import json 23 | import time 24 | import hashlib 25 | import requests 26 | 27 | 28 | def get_s_sign(params) -> str: 29 | md5 = hashlib.md5() 30 | md5.update(params.encode('utf8')) 31 | return md5.hexdigest() 32 | 33 | 34 | def get_results(cid, para): 35 | t_str = str(int(time.time() * 1000)) 36 | # 根据cid的不同,val的值不同 37 | val = '19DDD1FBDFF065D3A4DA777D2D7A81EC' 38 | params = 'cid=%s¶m=%s%s%s' % (cid, para, val, t_str) 39 | x_sign = get_s_sign(params) 40 | headers = { 41 | 'Accept': '*/*', 42 | 'Referer': 'https://car.yiche.com/yunqueq1/peizhi/', 43 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36', 44 | 'content-type': 'application/json;charset=UTF-8', 45 | # 以下四个请求头缺一不可 46 | 'x-city-id': '2401', # 城市标识 47 | 'x-platform': 'pc', 48 | 'x-sign': x_sign, # 经过加密得到的值 49 | 'x-timestamp': t_str, # 13位的时间戳 50 | } 51 | params = { 52 | 'cid': cid, 53 | 'param': para, 54 | } 55 | response = requests.get('https://mapi.yiche.com/web_api/car_model_api/api/v1/car/config_new_param', params=params, 56 | headers=headers) 57 | return response.json() 58 | 59 | 60 | def parse(): 61 | para = {"cityId": "2401", "serialId": "5485"} 62 | cid = 508 63 | results = get_results(cid, json.dumps(para)) 64 | print(results) 65 | 66 | 67 | if __name__ == '__main__': 68 | parse() 69 | -------------------------------------------------------------------------------- /ypwk/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:35 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /ypwk/demo.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 一品威客(https://www.epwk.com/login.html)登录破解 3 | * 接口:https://www.epwk.com/api/epwk/v1/user/login 4 | - post请求 5 | - 参数以明文的形式传递 6 | - data = { 7 | 'username': '账号', 8 | 'password': '明文密码', 9 | 'code': '', 10 | 'hdn_refer': '', 11 | } 12 | * 破解参数:请求头中的Signature的值 13 | * todo 思路如下: 14 | * 全局搜索 `Signature`,很容易定位到加密位置 15 | * 下断点,重新请求,然后跟进去代码,可以定位到关键的加密函数,如下 16 | ``` 17 | var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {} 18 | , e = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "a75846eb4ac490420ac63db46d2a03bf" 19 | , r = e + d(data) + d(t) + e; 20 | return r = f(r), 21 | r = m(r) 22 | ``` 23 | 24 | * 经过两次加密,首先经过md5加密,r = f(r),其中f函数实现对参数r进行md5加密 25 | * 其次经过 `AES-CBC-Pkcs7` 模式加密,k和iv都能获取到。 26 | ``` 27 | return function(data) { 28 | return c.a.AES.encrypt(data, l.key, { 29 | iv: l.iv, 30 | mode: c.a.mode.CBC, 31 | padding: c.a.pad.Pkcs7 32 | }).toString() 33 | }(data) 34 | ``` 35 | * 最终得到Signature的值 36 | */ 37 | 38 | var CryptoJS = require('crypto-js'); 39 | 40 | var d = function (t) { 41 | var e = ""; 42 | return Object.keys(t).sort().forEach((function (r) { 43 | e += r + ("object" === n_a(t[r]) ? JSON.stringify(t[r], (function (t, e) { 44 | return "number" == typeof e && (e = String(e)), 45 | e 46 | } 47 | )).replace(/\//g, "\\/") : t[r]) 48 | } 49 | )), 50 | e 51 | }, 52 | f = function (data) { 53 | return CryptoJS.MD5(data).toString() 54 | }, 55 | l_t = { 56 | key: CryptoJS.enc.Utf8.parse("fX@VyCQVvpdj8RCa"), 57 | iv: CryptoJS.enc.Utf8.parse(function (t) { 58 | for (var e = "", i = 0; i < t.length - 1; i += 2) { 59 | var r = parseInt(t[i] + "" + t[i + 1], 16); 60 | e += String.fromCharCode(r) 61 | } 62 | return e 63 | }("00000000000000000000000000000000")) 64 | }, 65 | m = function (data) { 66 | return function (data) { 67 | return CryptoJS.AES.encrypt(data, l_t.key, { 68 | iv: l_t.iv, 69 | mode: CryptoJS.mode.CBC, 70 | padding: CryptoJS.pad.Pkcs7 71 | }).toString() 72 | }(data) 73 | }; 74 | 75 | function n_a(e) { 76 | return typeof e 77 | } 78 | 79 | function h_e() { 80 | var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 5; 81 | return Math.random().toString(36).substring(3, 3 + e) 82 | } 83 | 84 | function get_signature(ts) { 85 | var l = { 86 | "i": false, 87 | "j": false, 88 | "h": true, 89 | "d": "prod", 90 | "a": "https://s1.weikeimg.com/_nuxt/", 91 | "e": "https://im2.epwitkey.com", 92 | "b": "4ac490420ac63db4", 93 | "c": "a75846eb4ac490420ac63db46d2a03bf", 94 | "f": "af9f93d4530c6167", 95 | "g": "c93ce713af9f93d4530c6167b78a3871" 96 | }, 97 | t = { 98 | "App-Ver": "", 99 | "Os-Ver": "", 100 | "Device-Ver": "", 101 | Imei: "", 102 | "Access-Token": "", 103 | Timestemp: ts, 104 | NonceStr: "".concat(ts).concat(h_e()), 105 | "App-Id": l.j ? l.f : l.b, 106 | "Device-Os": "web" 107 | }; 108 | var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {} 109 | , e = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "a75846eb4ac490420ac63db46d2a03bf" 110 | , r = e + d(data) + d(t) + e 111 | , r = f(r), 112 | r = m(r); 113 | return {signature: r, params: t} 114 | } 115 | 116 | var ts = parseInt((new Date).getTime() / 1e3); 117 | console.log(get_signature(ts)) -------------------------------------------------------------------------------- /yuanrenxue/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:22 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/readme.md: -------------------------------------------------------------------------------- 1 | ## 关于题目 2 | 3 | - 以 `topic` 开头的文件夹,来源于猿人学逆向练习网站 [猿人学Python - 内部学员练习平台 正式版](https://www.python-spider.com/challenge/) 4 | 5 | - 以 `scrape` 开头的文件夹,来源于崔佬搭建的逆向网站 [Scrape Center - 案例列表](https://scrape.center/) 6 | 7 | - 以 `wangluozhe` 开头的文件夹,来源于K哥搭建的网站 [网络者 - 反反爬虫练习平台](https://wangluozhe.com/challenge/) 8 | -------------------------------------------------------------------------------- /yuanrenxue/scrape_login1/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:28 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/scrape_login1/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:52 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | import requests 6 | import json 7 | import execjs 8 | 9 | from loguru import logger 10 | 11 | headers = { 12 | "Accept": "application/json, text/plain, */*", 13 | "Accept-Language": "zh-CN,zh;q=0.9", 14 | "Cache-Control": "no-cache", 15 | "Connection": "keep-alive", 16 | "Content-Type": "application/json;charset=UTF-8", 17 | "Origin": "https://login1.scrape.center", 18 | "Pragma": "no-cache", 19 | "Referer": "https://login1.scrape.center/", 20 | "Sec-Fetch-Dest": "empty", 21 | "Sec-Fetch-Mode": "cors", 22 | "Sec-Fetch-Site": "same-origin", 23 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 24 | } 25 | 26 | 27 | def get_token(params): 28 | js_str = ''' 29 | // 补atob 和btoa 环境 30 | // ============================================================ 31 | global.Buffer = global.Buffer || require('buffer').Buffer; 32 | if (typeof btoa === 'undefined') { 33 | global.btoa = function (str) { 34 | return new Buffer.from(str).toString('base64'); 35 | }; 36 | } 37 | 38 | if (typeof atob === 'undefined') { 39 | global.atob = function (b64Encoded) { 40 | return new Buffer.from(b64Encoded, 'base64').toString(); 41 | }; 42 | } 43 | var self = global 44 | // ============================================================ 45 | var re_utob = /[\\uD800-\\uDBFF][\\uDC00-\\uDFFFF]|[^\\x00-\\x7F]/g, 46 | utob = function (e) { 47 | return e.replace(re_utob, cb_utob) 48 | }, 49 | _encode = function (e) { 50 | return self.btoa(utob(e)) 51 | }, 52 | cb_utob = function (e) { 53 | if (e.length < 2) { 54 | var r = e.charCodeAt(0); 55 | return r < 128 ? e : r < 2048 ? fromCharCode(192 | r >>> 6) + fromCharCode(128 | 63 & r) : fromCharCode(224 | r >>> 12 & 15) + fromCharCode(128 | r >>> 6 & 63) + fromCharCode(128 | 63 & r) 56 | } 57 | r = 65536 + 1024 * (e.charCodeAt(0) - 55296) + (e.charCodeAt(1) - 56320); 58 | return fromCharCode(240 | r >>> 18 & 7) + fromCharCode(128 | r >>> 12 & 63) + fromCharCode(128 | r >>> 6 & 63) + fromCharCode(128 | 63 & r) 59 | }; 60 | 61 | var c = { 62 | encode: function (e, r) { 63 | return r ? _encode(String(e)).replace(/[+\/]/g, (function (e) { 64 | return "+" == e ? "-" : "_" 65 | } 66 | )).replace(/=/g, "") : _encode(String(e)) 67 | } 68 | } 69 | 70 | function get_token(e) { 71 | var token = c.encode(JSON.stringify(e)); 72 | return token 73 | } 74 | ''' 75 | ctx = execjs.compile(''.join(js_str)) 76 | token = ctx.call('get_token', params) 77 | return token 78 | 79 | 80 | def get_login_res(): 81 | url = "https://login1.scrape.center/" 82 | params = { 83 | 'username': 'admin', 84 | 'password': 'admin' 85 | } 86 | token = get_token(params) 87 | logger.info(f'token: {token}') 88 | data = { 89 | "token": token 90 | } 91 | data = json.dumps(data, separators=(',', ':')) 92 | response = requests.post(url, headers=headers, data=data) 93 | logger.info(f'请求状态码: {response.status_code}') 94 | 95 | 96 | if __name__ == '__main__': 97 | get_login_res() 98 | -------------------------------------------------------------------------------- /yuanrenxue/scrape_spa2/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:47 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/scrape_spa2/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 6:20 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import requests 7 | 8 | from utils import * 9 | 10 | 11 | def get_token(page): 12 | ctx = Utils(js_file_name='demo.js').read_js_file() 13 | return ctx.call('get_token', page) 14 | 15 | 16 | def get_results(page): 17 | headers = { 18 | 'Accept': 'application/json, text/plain, */*', 19 | 'Accept-Language': 'zh-CN,zh;q=0.9', 20 | 'Cache-Control': 'no-cache', 21 | 'Connection': 'keep-alive', 22 | 'Pragma': 'no-cache', 23 | 'Referer': 'https://spa2.scrape.center/page/9', 24 | 'Sec-Fetch-Dest': 'empty', 25 | 'Sec-Fetch-Mode': 'cors', 26 | 'Sec-Fetch-Site': 'same-origin', 27 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36', 28 | 'sec-ch-ua': '"Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"', 29 | 'sec-ch-ua-mobile': '?0', 30 | 'sec-ch-ua-platform': '"macOS"', 31 | } 32 | token = get_token(page) 33 | logger.info(f'当前页码: {page}, token: {token}') 34 | params = { 35 | 'limit': '10', 36 | 'offset': str((page - 1) * 10), 37 | 'token': token, 38 | } 39 | response = requests.get('https://spa2.scrape.center/api/movie/', params=params, headers=headers) 40 | return response.json() 41 | 42 | 43 | def parse(): 44 | for page in range(1, 12): 45 | results = get_results(page) 46 | data_list = results['results'] 47 | for data in data_list: 48 | name = data['name'] 49 | tag = data['categories'] 50 | regions = data['regions'] 51 | score = data['score'] 52 | minute = data['minute'] 53 | published_at = data['published_at'] 54 | alias = data['alias'] 55 | print( 56 | f'电影名称: {name}\n别名: {alias}\n类型: {tag}\n国家: {regions}\n评分: {score}\n时长: {minute}\n上映时间: {published_at}') 57 | print('***' * 15) 58 | 59 | 60 | if __name__ == '__main__': 61 | parse() 62 | -------------------------------------------------------------------------------- /yuanrenxue/scrape_spa6/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 3:20 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/scrape_spa6/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 6:20 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | import requests 6 | 7 | from utils import * 8 | 9 | 10 | def get_token(page): 11 | ctx = Utils(js_file_name='demo.js').read_js_file() 12 | return ctx.call('get_token', page) 13 | 14 | 15 | def get_results(page): 16 | headers = { 17 | 'Accept': 'application/json, text/plain, */*', 18 | 'Accept-Language': 'zh-CN,zh;q=0.9', 19 | 'Cache-Control': 'no-cache', 20 | 'Connection': 'keep-alive', 21 | 'Pragma': 'no-cache', 22 | 'Referer': 'https://spa2.scrape.center/page/9', 23 | 'Sec-Fetch-Dest': 'empty', 24 | 'Sec-Fetch-Mode': 'cors', 25 | 'Sec-Fetch-Site': 'same-origin', 26 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36', 27 | 'sec-ch-ua': '"Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"', 28 | 'sec-ch-ua-mobile': '?0', 29 | 'sec-ch-ua-platform': '"macOS"', 30 | } 31 | token = get_token(page) 32 | logger.info(f'当前页码: {page}, token: {token}') 33 | params = { 34 | 'limit': '10', 35 | 'offset': str((page - 1) * 10), 36 | 'token': token, 37 | } 38 | response = requests.get('https://spa6.scrape.center/api/movie/', params=params, headers=headers) 39 | return response.json() 40 | 41 | 42 | def parse(): 43 | for page in range(1, 12): 44 | results = get_results(page) 45 | data_list = results['results'] 46 | for data in data_list: 47 | name = data['name'] 48 | tag = data['categories'] 49 | regions = data['regions'] 50 | score = data['score'] 51 | minute = data['minute'] 52 | published_at = data['published_at'] 53 | alias = data['alias'] 54 | print( 55 | f'电影名称: {name}\n别名: {alias}\n类型: {tag}\n国家: {regions}\n评分: {score}\n时长: {minute}\n上映时间: {published_at}') 56 | print('***' * 15) 57 | 58 | 59 | if __name__ == '__main__': 60 | parse() 61 | -------------------------------------------------------------------------------- /yuanrenxue/topic13/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 1:31 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/topic13/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 1:31 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | import os 6 | 7 | import base64 8 | import requests 9 | 10 | from loguru import logger 11 | from fontTools.ttLib import TTFont 12 | 13 | 14 | def get_results(page): 15 | headers = { 16 | 'authority': 'www.python-spider.com', 17 | 'accept': 'application/json, text/javascript, */*; q=0.01', 18 | 'accept-language': 'zh-CN,zh;q=0.9', 19 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 20 | 'x-requested-with': 'XMLHttpRequest', 21 | } 22 | 23 | data = { 24 | 'page': page, 25 | } 26 | 27 | response = requests.post('https://www.python-spider.com/api/challenge13', headers=headers, data=data) 28 | return response.json() 29 | 30 | 31 | def parse_woff(page, woff): 32 | # base64解码,并保存为tff文件格式 33 | b = base64.b64decode(woff) 34 | woff_name = f'topic13_{page}.woff' 35 | xml_name = f'topic13_{page}.xml' 36 | with open(woff_name, 'wb') as f: 37 | f.write(b) 38 | f.close() 39 | font = TTFont(woff_name) 40 | font.saveXML(xml_name) 41 | extraNames = font.get('post').__dict__['extraNames'] 42 | woff_dict = { 43 | val.replace('uni', '&#x'): 0 if index >= 9 else index + 1 44 | for index, val in enumerate(extraNames) 45 | } 46 | os.remove(woff_name) 47 | os.remove(xml_name) 48 | logger.info(f'已删除文件: {woff_name} 和 {xml_name}') 49 | return woff_dict 50 | 51 | 52 | def parse(): 53 | count = 0 54 | for page in range(1, 101): 55 | results = get_results(page) 56 | woff = results['woff'] 57 | woff_dict = parse_woff(page, woff) 58 | datas = results['data'] 59 | for data in datas: 60 | count += int(''.join([f'{woff_dict[key]}' for key in data['value'].strip().split(' ')])) 61 | logger.info(f'前 {page} 页之和为: {count}') 62 | logger.info('***' * 20) 63 | 64 | 65 | if __name__ == '__main__': 66 | # 答案: 4943577 67 | parse() 68 | -------------------------------------------------------------------------------- /yuanrenxue/topic14/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:19 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/topic14/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js') 2 | 3 | var window = {} 4 | 5 | 6 | function aes_encrypt(word) { 7 | var k = 'wdf2ff*TG@*(F4)*YH)g430HWR(*)' + 'wse'; 8 | var key = CryptoJS.enc.Utf8.parse(k); 9 | var srcs = CryptoJS.enc.Utf8.parse(word); 10 | var encrypted = CryptoJS.AES.encrypt(srcs, key, { 11 | mode: CryptoJS.mode.ECB, 12 | padding: CryptoJS.pad.Pkcs7 13 | }); 14 | return encrypted.toString(); 15 | } 16 | 17 | function get_uc(page){ 18 | window.t = Date.parse(new Date()) / 1000; 19 | word = window.t + '|' + page 20 | uc = aes_encrypt(word) 21 | return uc 22 | } 23 | -------------------------------------------------------------------------------- /yuanrenxue/topic14/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:27 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | """ 7 | js_fuck 8 | """ 9 | 10 | import requests 11 | 12 | from utils import * 13 | 14 | 15 | def get_uc(page): 16 | ctx = Utils(js_file_name='demo.js').read_js_file() 17 | return ctx.call('get_uc', page) 18 | 19 | 20 | def get_results(page): 21 | headers = { 22 | 'authority': 'www.python-spider.com', 23 | 'accept': 'application/json, text/javascript, */*; q=0.01', 24 | 'accept-language': 'zh-CN,zh;q=0.9', 25 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 26 | 'x-requested-with': 'XMLHttpRequest', 27 | } 28 | uc = get_uc(page) 29 | logger.info(f'page: {page}, uc: {uc}') 30 | data = { 31 | 'page': page, 32 | 'uc': uc 33 | } 34 | response = requests.post('https://www.python-spider.com/api/challenge14', headers=headers, data=data) 35 | return response.json() 36 | 37 | 38 | if __name__ == '__main__': 39 | # 答案: 5175137 40 | count = 0 41 | for page in range(1, 101): 42 | results = get_results(page) 43 | data_List = results['data'] 44 | for data in data_List: 45 | count += int(str(data['value']).strip()) 46 | logger.info(f' 前 {page} 页数字相加之和为: {count}') 47 | logger.info('***' * 20) 48 | -------------------------------------------------------------------------------- /yuanrenxue/topic25/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:09 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/topic25/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:05 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | ''' 7 | 主页接口:https://www.python-spider.com/challenge/25 8 | 9 | 刷新该页面出现以下两个接口: 10 | - challenge25 接口 11 | - 获取数据接口,从第一页开始 12 | - challenge25verify 接口 13 | - 这个是获取图片的接口,接口返回的图片格式是base64 14 | 15 | 滑动图片,出现第三个接口 16 | - challenge25CheckVerify 接口 17 | - 参数是识别出来的缺口距离 18 | - 返回值中有个 rate 值,当这个值大于95%时候,请求下一页才能成功,否则请求失败 19 | 20 | 21 | 该代码识别准确率不高,只能识别出来前几页。使用的ddddocr,如果有更好的识别方法,欢迎交流 22 | ''' 23 | 24 | import os 25 | import base64 26 | import ddddocr 27 | import requests 28 | 29 | from loguru import logger 30 | 31 | path = 'images' 32 | 33 | if not os.path.exists(path): 34 | os.makedirs(path) 35 | 36 | bg_name, slide_name = 'bg', 'slide' 37 | 38 | headers = { 39 | 'authority': 'www.python-spider.com', 40 | 'accept': 'application/json, text/javascript, */*; q=0.01', 41 | 'accept-language': 'zh-CN,zh;q=0.9', 42 | 'cache-control': 'no-cache', 43 | 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 44 | 'origin': 'https://www.python-spider.com', 45 | # cookie参数必须携带,为renponse header中set-cookie的值 46 | 'cookie': 'sessionid=svm5k9nf9z6ublc7qjbndn3n84q85f0k; expires=Fri, 14 Apr 2023 09:43:14 GMT; HttpOnly; Max-Age=21600; Path=/; SameSite=Lax', 47 | 'pragma': 'no-cache', 48 | 'referer': 'https://www.python-spider.com/challenge/25', 49 | 'sec-ch-ua': '"Chromium";v="112", "Google Chrome";v="112", "Not:A-Brand";v="99"', 50 | 'sec-ch-ua-mobile': '?0', 51 | 'sec-ch-ua-platform': '"macOS"', 52 | 'sec-fetch-dest': 'empty', 53 | 'sec-fetch-mode': 'cors', 54 | 'sec-fetch-site': 'same-origin', 55 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36', 56 | 'x-requested-with': 'XMLHttpRequest', 57 | } 58 | 59 | 60 | def get_results(page, distant): 61 | if page: 62 | data = {'page': str(page)} 63 | url = 'https://www.python-spider.com/api/challenge25' 64 | response = requests.post(url, headers=headers, data=data) 65 | else: 66 | data = {'distant': str(distant)} 67 | url = 'https://www.python-spider.com/api/challenge25CheckVerify' 68 | response = requests.post(url, headers=headers, data=data) 69 | return response.json() 70 | 71 | 72 | def trans_image(name, b64_str): 73 | ''' 74 | base64字符串还原成图片,并保存 75 | :return: 76 | ''' 77 | imgdata = base64.b64decode(b64_str) 78 | f = open(f'{path}/{name}.png', 'wb') 79 | f.write(imgdata) 80 | f.close() 81 | 82 | 83 | def get_distance(path): 84 | ''' 85 | 识别缺口距离 86 | :param path: 图片存放的位置 87 | :return: 88 | ''' 89 | det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False) 90 | puzzle_path = f'{path}/{slide_name}.png' 91 | bg_path = f'{path}/{bg_name}.png' 92 | puzzle_bytes = open(puzzle_path, 'rb').read() 93 | bg_bytes = open(bg_path, 'rb').read() 94 | res = det.slide_match(puzzle_bytes, bg_bytes, simple_target=True) 95 | distance = res['target'][0] 96 | return distance 97 | 98 | 99 | def get_image(): 100 | url = 'https://www.python-spider.com/api/challenge25verify' 101 | response = requests.get(url, headers=headers) 102 | results = response.json() 103 | for name, b64_str in results.items(): 104 | trans_image(bg_name if name == 'img1' else slide_name, b64_str) 105 | 106 | 107 | def get_rate(): 108 | get_image() 109 | distance = get_distance(path) 110 | rate_res = get_results(page=None, distant=distance) 111 | rate = rate_res["rate"] 112 | return distance, rate 113 | 114 | 115 | def main(): 116 | count = 0 117 | for page in range(1, 101): 118 | results = get_results(page, distant=None) 119 | data_list = results['data'] 120 | count += sum([int(data['value']) for data in data_list]) 121 | logger.info(f'前 {page} 页的和为: {count}') 122 | distance, rate = get_rate() 123 | num = int(str(rate).split('.')[0]) 124 | logger.info(f'缺口位置: {distance}, 成功率: {rate}') 125 | while num < 95: 126 | distance, rate = get_rate() 127 | num = int(str(rate).split('.')[0]) 128 | logger.info(f'第 {page + 1} 页, distance: {distance}, rate: {rate}') 129 | else: 130 | continue 131 | 132 | 133 | if __name__ == '__main__': 134 | main() 135 | -------------------------------------------------------------------------------- /yuanrenxue/topic55/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:03 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/topic55/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js') 2 | 3 | function decode(str) { 4 | var CryptoJS = require("crypto-js"); 5 | var KEY = 'aiding6666666666'; 6 | var key = CryptoJS.enc.Utf8.parse(KEY); 7 | var decrypted = CryptoJS.AES.decrypt(str, key, { 8 | // iv: iv, 9 | mode: CryptoJS.mode.ECB, 10 | padding: CryptoJS.pad.Pkcs7, 11 | }); 12 | return decrypted.toString(CryptoJS.enc.Utf8) 13 | } 14 | 15 | function get_data_list(result) { 16 | return JSON.parse(decode(result)).data; 17 | } 18 | -------------------------------------------------------------------------------- /yuanrenxue/topic55/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:05 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | """ 7 | AES加密 8 | ECB模式,Pkcs7填充方式 9 | """ 10 | import requests 11 | 12 | from utils import * 13 | 14 | 15 | def get_results(page): 16 | headers = { 17 | 'authority': 'www.python-spider.com', 18 | 'accept': 'application/json, text/javascript, */*; q=0.01', 19 | 'accept-language': 'zh-CN,zh;q=0.9', 20 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 21 | 'x-requested-with': 'XMLHttpRequest', 22 | } 23 | 24 | data = { 25 | 'page': page, 26 | } 27 | 28 | response = requests.post('https://www.python-spider.com/api/challenge55', headers=headers, data=data) 29 | return response.json() 30 | 31 | 32 | def get_data_list(result): 33 | ctx = Utils(js_file_name='demo.js').read_js_file() 34 | return ctx.call('get_data_list', result) 35 | 36 | 37 | if __name__ == '__main__': 38 | # 答案: 5082763 39 | count = 0 40 | for page in range(1, 101): 41 | results = get_results(page) 42 | data_List = get_data_list(results['result']) 43 | for data in data_List: 44 | count += int(str(data['value']).strip()) 45 | logger.info(f' 前 {page} 页数字相加之和为: {count}') 46 | -------------------------------------------------------------------------------- /yuanrenxue/topic56/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:39 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/topic56/demo.js: -------------------------------------------------------------------------------- 1 | window = global; 2 | 3 | var JSEncryt = require('jsencrypt') 4 | , PVA = '-----BEGIN RSA PRIVATE KEY-----\n' + 5 | 'MIIEpAIBAAKCAQEAy5R1R2yM5jPPvkO2F47qVqMkYj7o92DF8y1yMkCSxY1WwqG0\n' + 6 | 'dCdUZTnaoBuAz99wGt55oGLcdalV71nPUiGWs/b6GzVN5v72baz/Q2OxHtkrFKqL\n' + 7 | 'VX16LW31cW9hAntN84RCbvTeB0MNV+SHmXjIf17OQLCtDKHBZWZ5NKyqFstO+KOd\n' + 8 | 'u32d2jsw+DT5lOBzDUBk/wUw2KyFJVx7eK6sSXEyWqBk2nxMRDNYixIEN1V1EBSq\n' + 9 | 'f+OwKK5Mxi04r38+Qog8z03/t/u6CfAOWVmi+MdrD1VHXv/P7bnFlgRcLzKwK1QL\n' + 10 | 'TSLBE1PrMmNNj0oRjByhMoI9tY5X6mRBqLyDhwIDAQABAoIBAGO++RmGO6D9CNAJ\n' + 11 | '4Bm52eKaK5UBiubOIR8NiNLLZb5qinRxg3eX35d7Wb2xzBLNwOFBWSl21trFncfY\n' + 12 | '4qY0s+C4ZYHYQ7Om/7nsFeQAYAOj1yJYj01TXf4NTsGGF2t+W8qxZlV0H6dCOLL0\n' + 13 | 'U2YkUmRp4Le8eQVj6dyTcVaYNPxWQBnb9ZOEIEvEjeoO/DD7CCmt7LDCey9KrTQl\n' + 14 | 'Avuc2nN6uRV1Wfm0P8conKPJtVdgzMvJujNdpz+bBDqwsqgeCICjs/hSCNO81VH3\n' + 15 | 'DD7J0mG2OHqowOVqagoDHpBprHOUKxAeTs9I0KEL+hEI4zXCDL69+Xs6azuts733\n' + 16 | 'zSOmwxkCgYEA25czfPVxxcK685LhaAvwbmzWHqNp07ytRNGf+Aww6OdgWkdgPy0n\n' + 17 | '20Gkg0HAqsxGcgZJk6cAkOy5hBLNHpHlGbeWFi+62lVNYUv3hAxumtiPyBMu7avE\n' + 18 | 'ZQCTXND1H1f/2enRDJRxQsR8y/SX1ivmC5U6fx7hbpKxnXyRHnvSlk8CgYEA7VWp\n' + 19 | 'hLNkn4AEaPPW0TknwKG40At/hjecX2zWAyZVt4ydDSeKgMEOUdmvGGlSCrefAl0n\n' + 20 | 'PTfM9SdIDcO5OTa2wUayKLIsrb6TDnG6KXXN6z3HR3Q4qKJbG83eaMYDqqziPPV+\n' + 21 | 'xzRVWShI3EGwkLczASmiYy+sEAT0OkxP59xTKUkCgYBgaGjFkukJfy4fJDxsNtmv\n' + 22 | 'UX9MYkhjGrIjxbjq6UdL6dGGsVGTSxr1i0NUETkqg5bmFtaUybxY5GWqk6qUok8o\n' + 23 | 'VE7DnN73Xn4jmnun8OFagHvXxnxTApeuFGueU2tbAIKmxJ3wXPfA7Y0w6kkDUbCl\n' + 24 | 'IzZUe1VT+3mZgAgijxBsxwKBgQDNytiJ62/V6hBo3P6pPtEcdF6nb0DtpazfBaVw\n' + 25 | '572twaywqlermzsKeCIenbx49I1ZZGLQ72C2NpCA9vTWCn5fiyiSpyScp0ImZTDS\n' + 26 | 'IIckctYoPDug5d7wdgtjeEfXp78osopyuwtCmu7Kpd8vLNt6J5raPI0K+vC22FL1\n' + 27 | 'LpOhmQKBgQCFeU448fL87N1MjMyusi8wJ5MLcn+kHbLTtpskTpfQM2p3Cnp4oL+7\n' + 28 | 'BI4AlXlKItV37rJIjZxQgLWhGoTZPplZaW4ooJCFJbazce5ua5fnsFS0oXhDN7uw\n' + 29 | 'jaq+v5t8G6gFS09hEa4kz9O53t/7UGuQqh0Bxb0cJ9iNeAlhagvBDQ==\n' + 30 | '-----END RSA PRIVATE KEY-----\n'; 31 | 32 | var A = new JSEncryt(); 33 | A.setPrivateKey(PVA) 34 | 35 | function get_decrypt_data(encrypt_data) { 36 | return JSON.parse(A.decrypt(encrypt_data)) 37 | } -------------------------------------------------------------------------------- /yuanrenxue/topic56/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:52 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import requests 7 | 8 | from utils import * 9 | 10 | 11 | def get_results(page): 12 | headers = { 13 | 'authority': 'www.python-spider.com', 14 | 'accept': 'application/json, text/javascript, */*; q=0.01', 15 | 'accept-language': 'zh-CN,zh;q=0.9', 16 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 17 | 'x-requested-with': 'XMLHttpRequest', 18 | } 19 | data = { 20 | 'page': page, 21 | } 22 | response = requests.post('https://www.python-spider.com/api/challenge56', headers=headers, data=data) 23 | return response.json() 24 | 25 | 26 | def get_decrypt_data(result): 27 | ctx = Utils(js_file_name='demo.js').read_js_file() 28 | return ctx.call('get_decrypt_data', result) 29 | 30 | 31 | if __name__ == '__main__': 32 | # 答案: 4976861 33 | count = 0 34 | for page in range(1, 101): 35 | results = get_results(page) 36 | data_List = get_decrypt_data(results['result']) 37 | for data in data_List['data']: 38 | count += int(str(data['value']).strip()) 39 | logger.info(f' 前 {page} 页数字相加之和为: {count}') 40 | -------------------------------------------------------------------------------- /yuanrenxue/topic57/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 1:37 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/topic57/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js') 2 | 3 | function I(X, l) { 4 | var C = X 5 | , q = CryptoJS.enc.Utf8.parse(C) 6 | , v = CryptoJS.TripleDES.decrypt(l, q, { 7 | 'mode': CryptoJS.mode.ECB, 8 | 'padding': CryptoJS.pad.Pkcs7 9 | }); 10 | return v.toString(CryptoJS.enc.Utf8); 11 | } 12 | 13 | function get_data_list(result) { 14 | var datas = JSON.parse(I(result.slice(0, 8), result.slice(8)))['data'] 15 | return datas 16 | } -------------------------------------------------------------------------------- /yuanrenxue/topic57/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:20 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | """ 7 | AES加密 8 | CBC模式,Pkcs7填充方式 9 | """ 10 | import requests 11 | 12 | from utils import * 13 | 14 | 15 | def get_results(page): 16 | headers = { 17 | 'authority': 'www.python-spider.com', 18 | 'accept': 'application/json, text/javascript, */*; q=0.01', 19 | 'accept-language': 'zh-CN,zh;q=0.9', 20 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 21 | 'x-requested-with': 'XMLHttpRequest', 22 | } 23 | data = { 24 | 'page': page, 25 | } 26 | response = requests.post('https://www.python-spider.com/api/challenge57', headers=headers, data=data) 27 | return response.json() 28 | 29 | 30 | def get_data_list(result): 31 | ctx = Utils(js_file_name='demo.js').read_js_file() 32 | return ctx.call('get_data_list', result) 33 | 34 | 35 | if __name__ == '__main__': 36 | # 答案: 5153708 37 | count = 0 38 | for page in range(1, 101): 39 | results = get_results(page) 40 | data_List = get_data_list(results['result']) 41 | for data in data_List: 42 | count += int(str(data['value']).strip()) 43 | logger.info(f' 前 {page} 页数字相加之和为: {count}') 44 | -------------------------------------------------------------------------------- /yuanrenxue/topic58/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:22 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/topic58/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:23 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | """ 7 | post请求中的 token 参数破解 8 | 对 页码 进行md5加密,并取16位 9 | """ 10 | import hashlib 11 | import requests 12 | 13 | from loguru import logger 14 | 15 | 16 | def get_page_md5(page: str): 17 | md5 = hashlib.md5() 18 | md5.update(page.encode('utf8')) 19 | return md5.hexdigest()[8:-8].lower() 20 | 21 | 22 | def get_html(page): 23 | headers = { 24 | 'authority': 'www.python-spider.com', 25 | 'accept': 'application/json, text/javascript, */*; q=0.01', 26 | 'accept-language': 'zh-CN,zh;q=0.9', 27 | 'origin': 'https://www.python-spider.com', 28 | 'referer': 'https://www.python-spider.com/challenge/58', 29 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 30 | 'x-requested-with': 'XMLHttpRequest', 31 | } 32 | data = { 33 | 'page': page, 34 | 'token': get_page_md5(str(page)), 35 | } 36 | response = requests.post('https://www.python-spider.com/api/challenge58', headers=headers, data=data) 37 | return response.json() 38 | 39 | 40 | def get_total_res_sum(): 41 | count = 0 42 | for page in range(1, 101): 43 | results = get_html(page) 44 | for res in results['data']: 45 | count += int(str(res['value']).strip()) 46 | logger.info(f'前 {page} 页之和为: {count}') 47 | 48 | 49 | if __name__ == '__main__': 50 | # 答案: 4994898 51 | get_total_res_sum() 52 | -------------------------------------------------------------------------------- /yuanrenxue/topic60/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:17 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/topic60/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js') 2 | 3 | // 3DES加密,page必须为字符串 4 | function get_data(page) { 5 | var d = CryptoJS.enc.Utf8.parse('aiding88'), 6 | D = CryptoJS.TripleDES.encrypt(page, d, { 7 | 'mode': CryptoJS.mode.ECB, 8 | 'padding': CryptoJS.pad.Pkcs7 9 | }) 10 | return D.toString() 11 | } 12 | -------------------------------------------------------------------------------- /yuanrenxue/topic60/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 2:42 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | """ 7 | 3DES加密 8 | ECB模式,Pkcs7填充方式 9 | """ 10 | import requests 11 | 12 | from utils import * 13 | 14 | 15 | def get_results(page): 16 | headers = { 17 | 'authority': 'www.python-spider.com', 18 | 'accept': 'application/json, text/javascript, */*; q=0.01', 19 | 'accept-language': 'zh-CN,zh;q=0.9', 20 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 21 | 'x-requested-with': 'XMLHttpRequest', 22 | } 23 | data = { 24 | 'page': page, 25 | } 26 | des_data = get_jiami(page) 27 | url = f'https://www.python-spider.com/api/challenge60/{des_data}' 28 | response = requests.post(url, headers=headers, data=data) 29 | return response.json() 30 | 31 | 32 | def get_jiami(page): 33 | ctx = Utils(js_file_name='demo.js').read_js_file() 34 | return ctx.call('get_data', page) 35 | 36 | 37 | def parse(): 38 | count = 0 39 | for page in range(1, 101): 40 | results = get_results(str(page)) 41 | data_list = results['data'] 42 | for data in data_list: 43 | count += int(str(data['value']).strip()) 44 | logger.info(f'前 {page} 页之和为: {count}') 45 | logger.info(f'本题答案为: {count}') # 本题答案为: 5004204 46 | 47 | 48 | if __name__ == '__main__': 49 | parse() 50 | -------------------------------------------------------------------------------- /yuanrenxue/wangluozhe2/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:44 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/wangluozhe2/demo.js: -------------------------------------------------------------------------------- 1 | var hexcase = 0; 2 | 3 | function hex_sha1(s) { 4 | return binb2hex(core_sha1(AlignSHA1(s))); 5 | } 6 | 7 | function core_sha1(blockArray) { 8 | var x = blockArray; 9 | var w = Array(80); 10 | var a = 1732584173; 11 | var b = -271733877; 12 | var c = -1752584194; 13 | var d = 271733878; 14 | var e = -1009589776; 15 | for (var i = 0; i < x.length; i += 16) { 16 | var olda = a; 17 | var oldb = b; 18 | var oldc = c; 19 | var oldd = d; 20 | var olde = e; 21 | for (var j = 0; j < 80; j++) { 22 | if (j < 16) 23 | w[j] = x[i + j]; 24 | else 25 | w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); 26 | var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j))); 27 | e = d; 28 | d = c; 29 | c = rol(b, 30); 30 | b = a; 31 | a = t; 32 | } 33 | a = safe_add(a, olda); 34 | b = safe_add(b, oldb); 35 | c = safe_add(c, oldc); 36 | d = safe_add(d, oldd); 37 | e = safe_add(e, olde); 38 | } 39 | return new Array(a, b, c, d, e); 40 | } 41 | 42 | function sha1_ft(t, b, c, d) { 43 | if (t < 20) { 44 | return (b & c) | ((~b) & d); 45 | } 46 | if (t < 40) { 47 | return b ^ c ^ d; 48 | } 49 | if (t < 60) { 50 | return (b & c) | (b & d) | (c & d); 51 | } 52 | return b ^ c ^ d; 53 | } 54 | 55 | function sha1_kt(t) { 56 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514; 57 | } 58 | 59 | function safe_add(x, y) { 60 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 61 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 62 | return (msw << 16) | (lsw & 0xFFFF); 63 | } 64 | 65 | function rol(num, cnt) { 66 | return (num << cnt) | (num >>> (32 - cnt)); 67 | } 68 | 69 | function AlignSHA1(str) { 70 | var nblk = ((str.length + 8) >> 6) + 1; 71 | var blks = new Array(nblk * 16); 72 | for (var i = 0; i < nblk * 16; i++) { 73 | blks[i] = 0; 74 | } 75 | for (i = 0; i < str.length; i++) { 76 | blks[i >> 2] |= str.charCodeAt(i) << (24 - (i & 3) * 8); 77 | } 78 | blks[i >> 2] |= 0x80 << (24 - (i & 3) * 8); 79 | blks[nblk * 16 - 1] = str.length * 8; 80 | return blks; 81 | } 82 | 83 | function binb2hex(binarray) { 84 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 85 | var str = ""; 86 | for (var i = 0; i < binarray.length * 4; i++) { 87 | str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xF) + hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8)) & 0xF); 88 | } 89 | return str; 90 | } 91 | 92 | function get_signature() { 93 | var sign = hex_sha1(Date.parse(new Date).toString()); 94 | return sign 95 | } 96 | -------------------------------------------------------------------------------- /yuanrenxue/wangluozhe2/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:55 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | 6 | import requests 7 | 8 | from utils import * 9 | 10 | ctx = Utils(js_file_name='demo.js').read_js_file() 11 | headers = { 12 | "authority": "wangluozhe.com", 13 | "accept": "application/json, text/javascript, */*; q=0.01", 14 | "accept-language": "zh-CN,zh;q=0.9", 15 | "content-type": "application/x-www-form-urlencoded; charset=UTF-8", 16 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 17 | "x-requested-with": "XMLHttpRequest" 18 | } 19 | cookies = { 20 | "session": "21ccbbfc-d378-446a-9ab3-335d00344df0.08Ft_EA-0fD2Ae6LYWysllGyZTA", 21 | } 22 | 23 | 24 | def get_signature(): 25 | signature = ctx.call('get_signature') 26 | return signature 27 | 28 | 29 | def get_results(page): 30 | url = "https://wangluozhe.com/challenge/api/2" 31 | signature = get_signature() 32 | logger.info(f'第{page}页, signature: {signature}') 33 | data = { 34 | "page": str(page), 35 | "count": "10", 36 | "_signature": signature 37 | } 38 | response = requests.post(url, headers=headers, cookies=cookies, data=data) 39 | return response.json() 40 | 41 | 42 | def main(): 43 | count = 0 44 | for page in range(1, 101): 45 | results = get_results(page) 46 | page_count = sum(res['value'] for res in results['data']) 47 | count += page_count 48 | logger.info(f'前{page}页之和为: {count}') # 答案为: 5186861 49 | 50 | 51 | if __name__ == '__main__': 52 | main() 53 | -------------------------------------------------------------------------------- /yuanrenxue/wangluozhe3/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:06 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/wangluozhe3/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js'); 2 | 3 | function encryptByDES(message, key) { 4 | var keyHex = CryptoJS.enc.Utf8.parse(key); 5 | var encrypted = CryptoJS.DES.encrypt(message, keyHex, { 6 | mode: CryptoJS.mode.ECB, 7 | padding: CryptoJS.pad.Pkcs7 8 | }); 9 | return encrypted.ciphertext.toString(); 10 | } 11 | 12 | function get_signature() { 13 | var message = 'https://wangluozhe.com/challenge/3'; 14 | message = message + '|' + Date.parse(new Date()).toString(); 15 | var key = Date.parse(new Date()).toString(), 16 | sign = encryptByDES(message, key); 17 | return sign 18 | } -------------------------------------------------------------------------------- /yuanrenxue/wangluozhe3/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:12 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | import requests 6 | 7 | from utils import * 8 | 9 | ctx = Utils(js_file_name='demo.js').read_js_file() 10 | 11 | headers = { 12 | "authority": "wangluozhe.com", 13 | "accept": "application/json, text/javascript, */*; q=0.01", 14 | "accept-language": "zh-CN,zh;q=0.9", 15 | "content-type": "application/x-www-form-urlencoded; charset=UTF-8", 16 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 17 | "x-requested-with": "XMLHttpRequest" 18 | } 19 | cookies = { 20 | "session": "21ccbbfc-d378-446a-9ab3-335d00344df0.08Ft_EA-0fD2Ae6LYWysllGyZTA", 21 | } 22 | 23 | 24 | def get_signature(): 25 | signature = ctx.call('get_signature') 26 | return signature 27 | 28 | 29 | def get_results(page): 30 | url = "https://wangluozhe.com/challenge/api/3" 31 | signature = get_signature() 32 | logger.info(f'第{page}页, signature: {signature}') 33 | data = { 34 | "page": str(page), 35 | "count": "10", 36 | "_signature": signature 37 | } 38 | response = requests.post(url, headers=headers, cookies=cookies, data=data) 39 | return response.json() 40 | 41 | 42 | def main(): 43 | count = 0 44 | for page in range(1, 101): 45 | results = get_results(page) 46 | page_count = sum(res['value'] for res in results['data']) 47 | count += page_count 48 | logger.info(f'前{page}页之和为: {count}') # 答案为: 5022790 49 | 50 | 51 | if __name__ == '__main__': 52 | main() 53 | -------------------------------------------------------------------------------- /yuanrenxue/wangluozhe4/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:15 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /yuanrenxue/wangluozhe4/demo.js: -------------------------------------------------------------------------------- 1 | window = global; 2 | 3 | var CryptoJS = require('crypto-js'); 4 | let date = Date.parse(new Date()), 5 | key_tmp = date * 1234, 6 | iv_tmp = date * 4321, 7 | key = CryptoJS.enc.Utf8.parse(key_tmp), 8 | iv = CryptoJS.enc.Utf8.parse(iv_tmp); 9 | (function tmp(date, key, iv) { 10 | function Encrypt(word) { 11 | let srcs = CryptoJS.enc.Utf8.parse(word); 12 | let encrypted = CryptoJS.AES.encrypt(srcs, key, { 13 | iv: iv, 14 | mode: CryptoJS.mode.CBC, 15 | padding: CryptoJS.pad.Pkcs7 16 | }); 17 | return encrypted.ciphertext.toString().toUpperCase(); 18 | } 19 | 20 | window.sign = Encrypt(date); 21 | })(date, key, iv); 22 | 23 | function get_signature(){ 24 | return window.sign 25 | } -------------------------------------------------------------------------------- /yuanrenxue/wangluozhe4/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 11:23 上午 3 | # @File: demo.py 4 | # @Author: liyf 5 | import requests 6 | 7 | from utils import * 8 | 9 | ctx = Utils(js_file_name='demo.js').read_js_file() 10 | 11 | headers = { 12 | "authority": "wangluozhe.com", 13 | "accept": "application/json, text/javascript, */*; q=0.01", 14 | "accept-language": "zh-CN,zh;q=0.9", 15 | "content-type": "application/x-www-form-urlencoded; charset=UTF-8", 16 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 17 | "x-requested-with": "XMLHttpRequest" 18 | } 19 | cookies = { 20 | "session": "21ccbbfc-d378-446a-9ab3-335d00344df0.08Ft_EA-0fD2Ae6LYWysllGyZTA", 21 | } 22 | 23 | 24 | def get_signature(): 25 | signature = ctx.call('get_signature') 26 | return signature 27 | 28 | 29 | def get_results(page): 30 | url = "https://wangluozhe.com/challenge/api/4" 31 | signature = get_signature() 32 | logger.info(f'第{page}页, signature: {signature}') 33 | data = { 34 | "page": str(page), 35 | "count": "10", 36 | "_signature": signature 37 | } 38 | response = requests.post(url, headers=headers, cookies=cookies, data=data) 39 | return response.json() 40 | 41 | 42 | def main(): 43 | count = 0 44 | for page in range(1, 101): 45 | results = get_results(page) 46 | page_count = sum(res['value'] for res in results['data']) 47 | count += page_count 48 | logger.info(f'前{page}页之和为: {count}') # 答案为: 5042028 49 | 50 | 51 | if __name__ == '__main__': 52 | main() 53 | -------------------------------------------------------------------------------- /zbcg_sznsyy/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 10:16 上午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | 6 | -------------------------------------------------------------------------------- /zyfuw/__init__.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:36 下午 3 | # @File: __init__.py.py 4 | # @Author: liyf 5 | -------------------------------------------------------------------------------- /zyfuw/demo.js: -------------------------------------------------------------------------------- 1 | var CryptoJS = require('crypto-js') 2 | 3 | function get_detail_url(hh) { 4 | var s = 'qnbyzzwmdgghmcnm'; 5 | var aa = hh.split("/"); 6 | var aaa = aa.length; 7 | var bbb = aa[aaa - 1].split('.'); 8 | var ccc = bbb[0]; 9 | var cccc = bbb[1]; 10 | var r = /^\+?[1-9][0-9]*$/; 11 | if (r.test(ccc) && cccc.indexOf('jhtml') != -1) { 12 | var srcs = CryptoJS.enc.Utf8.parse(ccc); 13 | var k = CryptoJS.enc.Utf8.parse(s); 14 | var en = CryptoJS.AES.encrypt(srcs, k, { 15 | mode: CryptoJS.mode.ECB, 16 | padding: CryptoJS.pad.Pkcs7 17 | }); 18 | var ddd = en.toString(); 19 | ddd = ddd.replace(/\//g, "^"); 20 | ddd = ddd.substring(0, ddd.length - 2); 21 | var bbbb = ddd + '.' + bbb[1]; 22 | aa[aaa - 1] = bbbb; 23 | var uuu = ''; 24 | for (i = 0; i < aaa; i++) { 25 | uuu += aa[i] + '/' 26 | } 27 | uuu = uuu.substring(0, uuu.length - 1); 28 | console.log(uuu) 29 | return uuu 30 | } 31 | } 32 | 33 | get_detail_url('http://ggzy.zwfwb.tj.gov.cn:80/jyxxcgjg/992535.jhtml') 34 | -------------------------------------------------------------------------------- /zyfuw/demo.py: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | # @Date: 5:38 下午 3 | # @File: demo.py 4 | # @Author: liyf 5 | import requests 6 | 7 | from lxml import etree 8 | 9 | from utils import * 10 | 11 | 12 | def get_html(url): 13 | headers = { 14 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 15 | 'Accept-Language': 'zh-CN,zh;q=0.9', 16 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36', 17 | 'Host': 'ggzy.zwfwb.tj.gov.cn', 18 | 'Accept-Encoding': 'gzip, deflate', 19 | 'Cookie': 'clientlanguage=zh_CN; JSESSIONID=B2C036872F09FB3066BC1E1D71CF6D69' 20 | } 21 | 22 | response = requests.get(url, headers=headers, verify=False) 23 | return response 24 | 25 | 26 | def get_index_url(url): 27 | response = get_html(url) 28 | if response.status_code != 200: 29 | print(f'状态码: {response.status_code}, 重新请求: {url}') 30 | get_index_url(url) 31 | html = response.text 32 | response = etree.HTML(html) 33 | li_list = response.xpath('//ul[@class="article-list2"]/li') 34 | for li in li_list: 35 | index_url = li.xpath('div/a/@url')[0] 36 | span_list = li.xpath('div/a//text()') 37 | title = ''.join(span_list).strip() 38 | get_detail_url(index_url, title) 39 | 40 | 41 | def get_detail_url(index_url, title): 42 | ctx = Utils(js_file_name='demo.js').read_js_file() 43 | detail_url = ctx.call('get_detail_url', index_url) 44 | item = { 45 | 'url': detail_url, 46 | 'title': title 47 | } 48 | print(item) 49 | 50 | 51 | if __name__ == '__main__': 52 | for page in range(1, 10): 53 | # http://ggzy.zwfwb.tj.gov.cn/jyxx/index_1.jhtml 54 | url = f'http://ggzy.zwfwb.tj.gov.cn/jyxx/index_{page}.jhtml' 55 | get_index_url(url) 56 | # break 57 | --------------------------------------------------------------------------------