美文网首页Scrapy
微信刷票工具

微信刷票工具

作者: 红薯爱帅 | 来源:发表于2021-06-07 20:37 被阅读0次

    1. 概述

    闲来无事,做一个微信刷票工具,只是验证了技术思路是否可行。不涉及任何商业利益!

    2. 技术预研

    微信投票工具很多,有一些是微信官方的,这个可能没办法破解;有一些是需要关注公众号,与微信深度绑定,不容易破解。
    剩下一些,要么只获取了微信openid,或者只通过ip做了限制,破解起来简单一些,可以一试。

    3. 破解思路

    3.1. 确认投票机制

    • 打开手机微信,进入投票页面,下拉可以看到投票网站的地址,如果不是wx的,可以尝试搞一下子

    • 通过电脑chrome浏览器模拟微信浏览器,打开投票页面,确认投票api

    • 确认投票api比较麻烦,需要慢慢摸索,有时候需要看看上下文的请求,有时候可能需要看看js源码,分析投票机制,也需要反复尝试

    # 在chrome增加一个device,user-agent设置为wechat浏览器即可
    Mozilla/5.0 (Linux; Android 7.0; MI 5s Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.137 Mobile Safari/537.36 wxwork/2.4.16 MicroMessenger/6.3.22 NetType/WIFI Language/zh
    

    Chrome浏览器模拟微信浏览器
    Chrome 修改 user agent 简单模拟微信内置浏览器

    3.2. 编写投票脚本

    基于#2.1的探索,如果只是基于IP的投票限制,反而简单许多。
    可以搞一个代理IP池,通过代理IP池发起投票request,基本可以成功。

    代理IP池,依赖免费代理源,定时抓取page解析得到可用的代理IP

    https://github.com/jhao104/proxy_pool
    免费的可用率太低,大概1/10,网速也比较慢;做爬虫的话,可以买一个收费的,当前场景够用

    • 代码clone下来之后,如何执行
    DB_CONN=redis://127.0.0.1:6379/0 sh start.sh
    
    • 也可以通过docker启动
    docker run --network host --env DB_CONN=redis://127.0.0.1:6379/0 -p 5010:5010 jhao104/proxy_pool
    
    image.png

    投票脚本

    import requests
    from retry import retry
    import random
    import time
    import string
    import hashlib
    import pickle
    import pathlib
    
    
    def get_user_agent():
        android_user_agents = [
            'Mozilla/5.0 (Linux; Android 7.0; MI 5s Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.137 Mobile Safari/537.36 wxwork/2.4.16 MicroMessenger/6.3.22 NetType/WIFI Language/zh',
            'Mozilla/5.0 (Linux; Android 9; PCNM00 Build/PKQ1.190630.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/045129 Mobile Safari/537.36 MMWEBID/1926 MicroMessenger/7.0.12.1620(0x27000C37) Process/tools NetType/WIFI Language/zh_CN ABI/arm64',
            'Mozilla/5.0 (Linux; Android 10; LYA-AL00 Build/HUAWEILYA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/045130 Mobile Safari/537.36 MMWEBID/9034 MicroMessenger/7.0.12.1620(0x27000C36) Process/tools NetType/WIFI Language/zh_CN ABI/arm64',
            'Mozilla/5.0 (Linux; Android 9; Redmi Note 8 Pro Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/67.0.3396.87 XWEB/1171 MMWEBSDK/200201 Mobile Safari/537.36 MMWEBID/229 MicroMessenger/7.0.12.1620(0x27000C37) Process/tools NetType/WIFI Language/zh_CN ABI/arm64',
            'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190716.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/67.0.3396.87 XWEB/1171 MMWEBSDK/191201 Mobile Safari/537.36 MMWEBID/4454 MicroMessenger/7.0.10.1580(0x27100AFF) Process/toolsmp NetType/WIFI Language/zh_CN ABI/arm32',
            'Mozilla/5.0 (Linux; Android 9; BKL-AL20 Build/HUAWEIBKL-AL20; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/045130 Mobile Safari/537.36 MMWEBID/7838 MicroMessenger/7.0.11.1600(0x27000B34) Process/tools NetType/4G Language/zh_CN ABI/arm64',
            'Mozilla/5.0 (Linux; Android 10; VOG-AL00 Build/HUAWEIVOG-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/045130 Mobile Safari/537.36 MMWEBID/2687 MicroMessenger/7.0.10.1580(0x27000AFE) Process/tools NetType/WIFI Language/zh_CN ABI/arm64',
        ]
        return random.choice(android_user_agents)
    
    
    def get_req_key():
        letters = random.sample('abcdefghijklmnopqrstuvwxyz', 4)
        digits = random.sample(string.digits, 4)
        return ''.join([f'{x}{y}' for x, y in zip(digits, letters)])
    
    
    def get_hash(key):
        hash_str = hashlib.md5()
        hash_str.update(key.encode('utf-8'))
        return hash_str.hexdigest()
    
    
    def get_proxy():
        return requests.get("http://127.0.0.1:5010/get/").json()
    
    
    def delete_proxy(proxy):
        requests.get("http://127.0.0.1:5010/delete/?proxy={}".format(proxy))
    
    
    def pickle_dump(data, file):
        with open(file, 'wb') as f:
            pickle.dump(data, f)
    
    
    def pickle_load(file):
        with open(file, 'rb') as f:
            return pickle.load(f)
    
    
    @retry(tries=3, delay=1)
    def fake_req(proxy):
        req_key = get_req_key()
        user_agent = get_user_agent()
        url = f'http://{req_key}.gd-cj.com/index.php?g=Wap&m=Vote&a=ticket'
        headers = {
            'Content-Length': '114',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'User-Agent': user_agent,
            'Origin': f'http://{req_key}.gd-cj.com',
            'Host': f'{req_key}.gd-cj.com',
            'Referer': f'http://{req_key}.gd-cj.com/index.php?g=Wap&m=Vote&a=detail&token=Fxea5C5sj3562xdE&id=556&zid=2230',
            'X-Requested-With': 'XMLHttpRequest'
        }
        form_data = dict(
            zid='2230', vid='556', token='Fxea5C5sj3562xdE',
            __hash__=f'{get_hash(req_key)}_{get_hash(user_agent)}'
        )
        print(f'proxy: {proxy}')
        resp = requests.post(url, headers=headers, data=form_data,
                             proxies={"http": "http://{}".format(proxy)},
                             timeout=10)
        print(f'response: {resp.status_code} - {resp.content}')
    
        try:
            resp_json = resp.json()
            return resp_json.get('status') == 108
        except:
            pass
    
        return False
    
    
    if __name__ == '__main__':
        used_proxy_file = './proxy_list.pkl'
        total, success = 0, 0
        proxy_list = pickle_load(used_proxy_file) if pathlib.Path(used_proxy_file).exists() else []
        proxy = None
    
        while True:
            try:
                proxy = get_proxy().get("proxy")
                delete_proxy(proxy)
                if proxy is None:
                    time.sleep(10)
                    continue
                if proxy in proxy_list:
                    time.sleep(0.1)
                    continue
                proxy_list.append(proxy)
                pickle_dump(proxy_list, used_proxy_file)
                total += 1
    
                if fake_req(proxy):
                    success += 1
                    print('=================== bingo')
    
            except Exception as e:
                # print(f'exception: {e}')
                pass
            
            print(f'success: {success}, total: {total}')
            time.sleep(random.randint(1, 5))
    

    4. 总结

    时间仓促,只是走通思路,代码没有仔细设计与调整,进而更加仿真,减少被发现的可能,比如

    • request里面__hash__字段的生成机制(随意生成的,貌似不要也行。。)
    • req_key的作用是啥(只是仿照原来的规则,生成了一个)

    IP代理工具jhao104/proxy_pool很赞,省了不少事情。做了几个小优化:

    • 有一个bugfix
    • 解析免费代理源,只看了第一页,修改为前10页
    • 内部还有一些逻辑可以优化

    道高一尺,魔高一丈,技术就是在不断的battle情况下,才日益精进

    相关文章

      网友评论

        本文标题:微信刷票工具

        本文链接:https://www.haomeiwen.com/subject/zexncktx.html