记一次微信公众号批量投票,主要记录思路,具体的公众号已打码。
主线思路:
1.分析投票所需数据(判断 是通过ip 还是 需要注册账号后才可以进行投票)
2.批量注册第三方平台的账号(若拥有大量可用微信号,则可用微信号直接替代此步)
3.利用已注册的账号进行遍历,随机投票,每日循环。
实施步骤:
1.使用 mitmproxy 监测投票过程(亦可用fiddler进行抓包),分析并记录 必要请求及所需数据。
上图中红色字体所标记数据为 用户数据,
Referer 中涉及到 被投票用户的 work_id 和 library_id ,可以通过分享页面的url获取
data 中涉及到 被投票用户的work_id 和 投票者的token ,投票者的token 是每个用户特有的识别码,故需要进行注册账号
注:请求所需的 代理ip 下方有介绍,主要是通过实时爬取 站大爷的可用ip 来实现。
2. 注册该公众号平台的账号,并使用 selenium 模拟chrome访问,获取控件并填写信息。
图中信息均为必填信息,
昵称, 现在各种平台比较多,可以比较快捷的获取大量用户名,或者自己编辑
密码、确认密码 更不用说,是比较容易填写的,初看比较困难的是如何获取到大量的手机号,以及能得到其验证码。
因为国家针对sim卡实行实名制,所以正规渠道比较少。在网上搜索后发现,
①. 有很多的接码平台可以实现此类功能,但是大多要付费、还有很多api要了解,乍一看比较麻烦,就没有使用这种办法。
②.还发现有一些机构个人会在网上免费公开少量的手机号,可以在线接收短信注册码验证码(例 点击查看),类似的网站如果需要可以自行在网上搜索。此方法的确可以使用,但是实操时发现很多手机号发送验证码后不能及时接收到,即同一时间有很多用户使用,导致运营商延迟较大。所以也没使用这种办法。
③. 最后因为找不到手机号,就 按了F12 ,这下才发现,原来每次点击 验证码后,都会响应到一个json串,即验证码,于是得来全不费工夫。最后自己随机生成手机号,并获取响应到的json串,以此达到 获取验证码的效果。至此,批量注册账号的问题得以解决了。
注册完账号后,发现 用户的token值 并不会显示出来,
于是在网页的js中开始检索, 发现 通过 get_user_token() 方法可以直接获取当前用户的token,在F12 的 console 中调试后发现可行。就通过此方法获取的 token 值。
3. 获取大量实时免费的高匿代理ip。
通过前两步,已经可以实现注册账号、进行投票了,但没有高匿代理ip,极易被人察觉,所以这一步就是想办法获取代理ip了。
初步调研了目前主流的免费的代理ip网站,最终选择了站大爷,因为每个小时都更新,而且使用公众号的主站测试了一下,发现大部分是可以成功访问的。
项目中使用的:
数据库:SSDB,详细信息可参见git
代理ip池: proxy_pool,详细信息可参见git
为了尽量少的影响他人服务器,我的请求速度写的极慢,按需修改。
代码部分:
1,投票
import jsonimport randomimport timeimport pyssdbimport requestsfrom selenium import webdriverclass vote_wechat(object):"""投票部分先 请求 upload_visit 上传服务器数据,返回值为result: 1 说明被服务器认可然后 请求add_praise 上传token ,服务器返回成功requests.get("http://192.168.1.7:5010/get/").content.decode('utf-8')此行的意思是 请求局域网内的代理ip库,从中随机取一个可用ip可以根据自己的配置情况自行修改"""def __init__(self,token="******",proxy={'http': requests.get("http://192.168.1.7:5010/get/").content.decode('utf-8')}):# 默认微信用户 - 小号self.token = token# 默认代理ip - 随机选取self.proxy = proxy# 被投票人信息work_id = "******"library_id = "******"self.url = 'http://www.y***/wh/api/activity/fruit/add_praise'Agent = ['Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16A366 MicroMessenger/6.7.3(0x16070321) NetType/WIFI Language/zh_CN','Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4X Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044304 Mobile Safari/537.36 MicroMessenger/6.7.2.1340(0x2607023A) NetType/WIFI Language/zh_CN','Mozilla/5.0 (Linux; Android 7.1.1; vivo X20A Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044304 Mobile Safari/537.36 MicroMessenger/6.7.2.1340(0x2607023A) NetType/4G Language/zh_CN','Mozilla/5.0 (Linux; Android 7.1.1; OD105 Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044208 Mobile Safari/537.36 wxwork/2.4.9 MicroMessenger/6.3.22 NetType/4G Language/zh','Mozilla/5.0 (Linux; Android 7.1.1; OPPO R11st Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044304 Mobile Safari/537.36 MicroMessenger/6.7.2.1340(0x2607023A) NetType/WIFI Language/zh_CN','Mozilla/5.0 (Linux; Android 8.0; SM-G9500 Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044208 Mobile Safari/537.36 MicroMessenger/6.7.2.1340(0x2607023A) NetType/WIFI Language/zh_CN','Mozilla/5.0 (Linux; Android 8.0; DUK-AL20 Build/HUAWEIDUK-AL20; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044353 Mobile Safari/537.36 MicroMessenger/6.7.3.1360(0x26070333) NetType/WIFI Language/zh_CN Process/tools','Mozilla/5.0 (Linux; Android 8.0; MHA-AL00 Build/HUAWEIMHA-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044304 Mobile Safari/537.36 MicroMessenger/6.7.3.1360(0x26070333) NetType/NON_NETWORK Language/zh_CN Process/tools','Mozilla/5.0 (Linux; Android 8.1; EML-AL00 Build/HUAWEIEML-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.143 Crosswalk/24.53.595.0 XWEB/358 MMWEBSDK/23 Mobile Safari/537.36 MicroMessenger/6.7.2.1340(0x2607023A) NetType/4G Language/zh_CN','Mozilla/5.0 (Linux; Android 8.1; PAR-AL00 Build/HUAWEIPAR-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044304 Mobile Safari/537.36 MicroMessenger/6.7.3.1360(0x26070333) NetType/WIFI Language/zh_CN Process/tools',]self.Agent = Agent[random.randint(0, len(Agent) - 1)]self.headers = {"Host": "www.y***","Proxy-Connection": "keep-alive","Content-Length": "101","Accept": "application/json, text/javascript, */*; q=0.01","Origin": "http://www.y***","X-Requested-With": "XMLHttpRequest",'User-Agent': self.Agent,"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8","Referer": "http://www.y***/wh/web/picture.html?page=picture&work_id={work_id}&from=singlemessage&library_id={library_id}&is_weixin=1&login_version=1&is_login=1".format(work_id=work_id, library_id=library_id),"Accept-Encoding": "gzip, deflate","Accept-Language": "zh-CN,en-US;q=0.9"}self.data = {"issign": "1","mac": "","work_id": work_id,"token": token}def get_proxy(self):return requests.get("http://192.168.1.7:5010/get/").content.decode('utf-8')def run(self):i = 0while i < 3:try:# 投票前先请求分享页面,增加浏览数url_read = 'http://www.y***/wh/api/asset/info/?workID=******&mac=&token='hreader_read = {"Host": "www.y***","Proxy-Connection": "keep-alive","Accept": "application/json, text/javascript, */*; q=0.01","Origin": "http://www.y***","X-Requested-With": "XMLHttpRequest",'User-Agent': self.Agent,"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8","Accept-Encoding": "gzip, deflate","Accept-Language": "zh-CN,en-US;q=0.9"}for j in range(random.randint(2, 5)):# 请求分享页,增加浏览量req_read = requests.get(url_read, headers=hreader_read, proxies=self.proxy)time.sleep(random.random() * 10)req = requests.post(self.url, data=self.data, headers=self.headers, proxies=self.proxy)req_json = json.loads(req.content)if req.status_code == 200 and 'praise_times' in req_json:print('\r累计{}票,本账号今日已投{}票'.format(req_json['praise_times'], req_json['has_vote']))i += 1time.sleep(random.randint(2, 5))else:print(req_json['err_msg'])except Exception as e:# self.proxy = {'http': self.get_proxy()}print('遇到问题{},跳过1次'.format(e))i += 1time.sleep(1)
2,注册账号
class register_user(object):"""自动注册一个账号(用手机号注册账号,获取每个账号的token,一个账号需要1分钟左右时间创建)格式:ip 账号 token小号 ******大号 ******:return:账号所用ip/手机号/token"""def __init__(self, proxy=requests.get("http://192.168.1.7:5010/get/").content.decode('utf-8')):self.info_list = []self.token_ = 'null'self.proxy = proxyself.agent = vote_wechat().Agentself.nickname = self.nickname()[random.randint(0, 500)]self.tele_num = self.random_(17)self.regest_url = 'http://www.y***/wh/web/mreg.html'options = webdriver.ChromeOptions()options.add_argument('--headless')options.add_argument("disable-infobars")options.add_argument('User-Agent={}'.format(self.agent))options.add_argument('--proxy-server={0}'.format(self.proxy))self.chrome = webdriver.Chrome(chrome_options=options)self.chrome.set_page_load_timeout(20)self.chrome.get(self.regest_url)def nickname(self):# 从SSDB数据库取昵称(根据自身数据情况进行替换)c = pyssdb.Client('192.168.1.7')nick = []user_list = c.hkeys('User_name_icon', '', '', 500)for i in user_list:rc = i.decode('utf-8').split('|,|')[1]nick.append(rc)c.disconnect()return nickdef random_(self, up, num=9):"""随机生成手机号码:param up: 手机号前缀,默认2位:param num:默认9位数:return:默认11位随机数字"""nex = []for i in range(num):the_o = random.randint(0, 9)nex.append(str(the_o))return str(up) + ''.join(nex)def send_sms(self):# 发送验证码请求send_sms_url = 'http://www.y***/wh/api/common/send_validate_sms/'header_send_sms = {"Accept": "application/json, text/javascript, */*; q=0.01","Accept-Encoding": "gzip, deflate","Accept-Language": "zh-CN,zh;q=0.9","Content-Length": "32","Content-Type": "application/x-www-form-urlencoded; charset=UTF-8","Host": "www.y***","Origin": "http://www.y***","Proxy-Connection": "keep-alive","Referer": "http://www.y***/wh/web/mreg.html","User-Agent": self.agent,"X-Requested-With": "XMLHttpRequest",}data_send_sms = {'phone': self.tele_num,'name': self.nickname,}proxy_send_sms = {'http': self.proxy}send_sms_req = requests.post(send_sms_url, headers=header_send_sms, data=data_send_sms, proxies=proxy_send_sms)v_code = json.loads(send_sms_req.content)['v_code']return v_codedef get_proxy(self):return requests.get("http://192.168.1.7:5010/get/").content.decode('utf-8')def edit_info(self):print('\r正在浏览器编辑中......', end='')# 输入昵称、手机号、密码、确认密码,等待10秒后,输入验证码nickname_input = self.chrome.find_element_by_id("doc-ipt-1")nickname_input.send_keys(self.nickname)phone_input = self.chrome.find_element_by_id("doc-ipt-2")phone_input.send_keys(self.tele_num)psd_input = self.chrome.find_element_by_id("doc-ipt-3")psd_input.send_keys(self.tele_num)psd_again_input = self.chrome.find_element_by_id("doc-ipt-4")psd_again_input.send_keys(self.tele_num)time.sleep(10)# 输入验证码print('\r发送验证码中......', end='')verification_input = self.chrome.find_element_by_id("doc-ipt-5")verification_input.send_keys(self.send_sms())def run(self):self.edit_info()# 随机等待15-50秒后,提交信息time.sleep(random.randint(15, 50))btn = self.chrome.find_element_by_id('confirm_btn')btn.click()# 执行js,获取token值js = 'document.getElementById("doc-ipt-1").className = get_user_token()'count = 0while self.token_ == 'null' or count > 10:count += 1print('\r“token_” key is :', self.token_, end='')time.sleep(1)self.chrome.execute_script(js)self.token_ = self.chrome.find_element_by_id("doc-ipt-1").get_attribute('class')print('\r{} {} {}'.format(self.proxy, self.tele_num, self.token_))self.info_list.extend([self.proxy, self.tele_num, self.token_])return self.info_list
3,代理ip写入,检查是否为高匿、是否可访问
# 检查url是否可以通过代理ip访问class check_url(object):"""检查url是否可以通过代理ip访问case:check = check_url('/ip')while not check.check_ip():http_str = check.refresh()if check.proxies['http'] == http_str:breakcheck.proxies['http'] = http_str"""def __init__(self, url, ip_proxy=None):self.url = urlif ip_proxy:self.proxies = {'http': ip_proxy}else:self.proxies = {'http': requests.get("http://192.168.1.7:5010/get/").content.decode('utf-8')}def check_ip(self):# 能访问返回Truetry:# 超过20秒的代理就不要了r = requests.get(self.url, proxies=self.proxies, timeout=10, verify=False)if r.status_code == 200:# print(r.content)print('{}可以正常访问'.format(self.proxies['http']))return Trueexcept Exception as e:print('\r{}---->{}---更换ip中'.format(self.proxies['http'], e), end='')time.sleep(0.1)def refresh(self):return requests.get("http://192.168.1.7:5010/get/").content.decode('utf-8')# 从站大爷ip网站中取最新ip,写入文件def write_zdy_ip():# 写入文件位置为:E:\ip3.txtdef now_time(time_str="%Y-%m-%d-%H-", replace=['年', '月', '日', '时'], replace_str='-'):time_stamp = time.localtime(time.time())str_now_time = str(time_stamp.tm_year) + replace_str + str(time_stamp.tm_mon) + replace_str + \str(time_stamp.tm_mday) + replace_str + str(time_stamp.tm_hour) + replace_str# str_now_time = time.strftime(time_str, time_stamp) # 含0show_now_time = str_now_timefor item in replace:# 将 中文 转化成 unicodeshow_now_time = show_now_time.replace(replace_str, item, 1)item = item.encode('unicode_escape').decode()str_now_time = str_now_time.replace(replace_str, item, 1)print('当前时间:', show_now_time)return str_now_timezdy_url = '/dayProxy.html'headers = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3","Cookie": "acw_tc=781bad0815554276156886732e5dc4c8fa7bc5f5f7d49920ab817374586a8b; ASPSESSIONIDQSCADTTD=CPLINKOCBKENHNPBEHDCMAKJ; __51cke__=; Hm_lvt_8fd158bb3e69c43ab5dd05882cf0b234=1555427618; ASPSESSIONIDACRDDQQA=GMPHOIPCLFKBFGCPFMBDFAPM; __tins__16949115=%7B%22sid%22%3A%55427617018%2C%20%22vd%22%3A%204%2C%20%22expires%22%3A%55429600579%7D; __51laig__=4; Hm_lpvt_8fd158bb3e69c43ab5dd05882cf0b234=1555427801","Host": "","User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36",}referer = {'Referer': '/dayProxy.html'}res = requests.get(zdy_url, headers=headers)if res.status_code == 200:soup = BeautifulSoup(res.content, "html.parser")panel = soup.find('div', class_='panel-body')panel = str(panel)time_str = now_time()pattern = r'.+href="(.+)">{}.+'.format(time_str)pattern_ = r'.+href="(.+)">{}.+'.format('\u5e74')if len(re.findall(pattern, panel)) < 1:href_day = re.findall(pattern_, panel)[0]url_day = '' + re.findall(pattern_, panel)[0]else:href_day = re.findall(pattern, panel)[0]url_day = '' + re.findall(pattern, panel)[0]options = webdriver.ChromeOptions()options.add_argument('--headless')options.add_argument("disable-infobars")chrome_day = webdriver.Chrome(chrome_options=options)chrome_day.get(zdy_url)hre = chrome_day.find_elements_by_css_selector('a[href="{}"]'.format(href_day))[0]hre.click()chrome_day.refresh()text = chrome_day.find_elements_by_css_selector('.cont')[0].textwith open('E:\ip3.txt', 'w', encoding='utf-8') as f:f.write(text)print('ip已写入...', end='')# 从站大爷将ip放置txt文件(E:\ip3.txt)中,开始执行ip_proxy = []userful_ip = []with open('E:\ip3.txt', 'r', encoding='utf-8') as f:for item in f:ip = item.split('@')[0]type = re.findall(r'.+\[(.+)\].+', item)[0]if type == '高匿':ip_proxy.append(ip)print('共{}个高匿ip,现在开始检查可用性...'.format(len(ip_proxy)))# 检查高匿ip是否可以访问目标网站for i in range(len(ip_proxy)):check = check_url('http://www.y***', ip_proxy[i])if not check.check_ip():print('{}不可用'.format(ip_proxy[i]))else:userful_ip.append(ip_proxy[i])print('共{}个可用ip,可用ip集合:'.format(len(userful_ip)), userful_ip)return userful_ip
4,主函数
# 批量 新建账号def new_start(userful_ip):for i in range(len(userful_ip)):try:print('第{}次开始运行...'.format(i + 1))info_list = register_user(proxy=userful_ip[i]).run()info_str = info_list[0] + '|' + info_list[1] + '|' + info_list[2] + '\n'with open(r"E:\users.txt", 'a') as f:f.write(info_str)print('已成功写入第{}个用户,响应等待中...'.format(i + 1))time.sleep(random.randint(30, 600))except Exception as e:print('Error:', e)# 批量 投票def wechat_start():info_ip, token, ip_token = [], [], []# with open(r'E:\users.txt', 'r') as f:with open(r'E:\users_repeat2.txt', 'r') as f:for item in f:item_list = item.split('|')info_ip.append(item_list)for info in info_ip:if info[0] not in ip_token:ip_token.append(info[0])token.append(info[2].strip())# else:#info__str = info[0] + '|' + info[1] + '|' + info[2]#with open(r"E:\users_repeat2.txt", 'a') as f:# f.write(info__str)print('可用用户:', len(ip_token))# time.sleep(100)# 10个用户一组进行投票,每个人间隔3~6分钟,每组间隔15~30分钟# 创建一个10的列表down = [i * 10 for i in range(1, 20)]# 将所有用户投票for i in range(len(token)):if i+1 < 1:continuefor itemm in down:if i == itemm:time.sleep(random.randint(60 * 15, 60 * 30))print('正在使用第%s个用户投票' % str(i+1))wechat_yhl = vote_wechat(token=token[i], proxy={'http': ip_token[i]})wechat_yhl.run()time.sleep(random.randint(60 * 3, 60 * 6))# 0.获得最新ipuserful_ip = write_zdy_ip()# 1. 注册new_start(userful_ip)# 2. 遍历 账号文件夹去投票wechat_start()while True:# 无限注册账号try:new_start(write_zdy_ip())time.sleep(60 * 90)except Exception:print('遇到问题,重试中...')time.sleep(10)