lqg 2 years ago
commit
860eaac622

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+*.pyc
+/data/driver/

+ 15 - 0
README.md

@@ -0,0 +1,15 @@
+# twitter account creator
+
+twitter account creator
+
+
+## develop
+
+```
+virtualenv .venv
+.venv\scripts\activate
+pip install -r requirements.txt
+
+python main.py
+```
+

+ 8 - 0
bin/genTwitter

@@ -0,0 +1,8 @@
+#!/bin/bash
+# @Contact :   liuyuqi.gov@msn.cn
+# @Time    :   2022/11/26 22:34:10
+# @License :   (C)Copyright 2022 liuyuqi.
+# @Desc    :   
+###############################################################################
+
+python main.py

+ 8 - 0
conf/config.json

@@ -0,0 +1,8 @@
+{
+    "proxy": {
+        "ip": "127.0.0.1:1080",
+        "password": ""
+    },
+    "username": "",
+    "pwd": ""
+}

+ 5 - 0
main.py

@@ -0,0 +1,5 @@
+
+from twitter_account_creator import main
+
+if __name__ == '__main__':
+    main()

+ 8 - 0
requirements.txt

@@ -0,0 +1,8 @@
+selenium==4.6.1
+requests==2.28.1
+colorwed
+json
+random
+undetected_chromedriver==3.1.7
+webdriver-manager==3.8.5
+

+ 41 - 0
setup.py

@@ -0,0 +1,41 @@
+"""Setup script for 君乐宝"""
+
+import setuptools
+
+
+# Get version information without importing the package
+SHORT_DESCRIPTION = '君乐宝助手'
+LONG_DESCRIPTION = open('README.md', 'rt').read()
+
+CLASSIFIERS = [
+    'Development Status :: 5 - Production/Stable',
+    'Intended Audience :: Developers',
+    'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
+    'Programming Language :: Python :: 3',
+    'Programming Language :: Python :: 3.3',
+    'Programming Language :: Python :: 3.4',
+    'Programming Language :: Python :: 3.5',
+    'Programming Language :: Python :: 3.6',
+    'Programming Language :: Python :: Implementation :: PyPy',
+    'Topic :: Software Development :: Build Tools',
+]
+
+setuptools.setup(
+    name='reflutter',
+    version='0.6.5',
+    description=SHORT_DESCRIPTION,
+    long_description=LONG_DESCRIPTION,
+    author='impact',
+    author_email='liuyuqi.gov@msn.cn',
+    url='https://git.yoqi.me/lyq/TwitterAccountCreator',
+    packages=setuptools.find_packages(),
+    license='GPLv3+',
+    platforms=['any'],
+    keywords='distutils setuptools egg pip requirements',
+    classifiers=CLASSIFIERS,
+    entry_points={
+        'console_scripts': [
+            'jlb = crawl_jlb.__init__:main',
+        ],
+    },
+)

+ 13 - 0
twitter_account_creator/__init__.py

@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@Contact :   liuyuqi.gov@msn.cn
+@Time    :   2022/11/26 18:38:42
+@License :   Copyright © 2017-2022 liuyuqi. All Rights Reserved.
+@Desc    :   
+'''
+
+from twitter_account_creator.twitter_creator import Twitter
+
+def main():
+    Twitter().run()

+ 0 - 0
twitter_account_creator/models/__init__.py


+ 31 - 0
twitter_account_creator/models/api.py

@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@Contact :   liuyuqi.gov@msn.cn
+@Time    :   2022/11/26 18:42:36
+@License :   Copyright © 2017-2022 liuyuqi. All Rights Reserved.
+@Desc    :   
+'''
+
+# email
+_emailHost=r"https://email-fake.com"
+
+# phone
+_phoneHost=r"http://smspva.com"
+apiKey="xx"
+getNumber=_phoneHost+"/priemnik.php?metod=get_number&country=ES&service=opt41&apikey="+apiKey
+getSms=_phoneHost+"/priemnik.php?metod=get_sms&country=ES&service=opt41&apikey="+apiKey
+getBalance=_phoneHost+"/priemnik.php?metod=get_balance&service=opt4&apikey="+apiKey
+
+# twitter
+_twitterHost=r"https://twitter.com"
+accountAccess=_twitterHost+"/account/access"
+signup=_twitterHost+"/i/flow/signup"
+
+# 获取随机昵称
+getNickName=r"https://api.namefake.com"
+
+# webdriver downlaod url
+edgeDriver="https://msedgedriver.azureedge.net/%s/edgedriver_win64.zip"
+
+

+ 43 - 0
twitter_account_creator/models/email.py

@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@Contact :   liuyuqi.gov@msn.cn
+@Time    :   2022/11/26 19:59:10
+@License :   Copyright © 2017-2022 liuyuqi. All Rights Reserved.
+@Desc    :   
+'''
+import time
+import re
+import sys
+from selenium.webdriver.common.by import By as by
+from twitter_account_creator.models import api
+
+
+class Email(object):
+
+    def __init__(self):
+        pass
+
+    def getEmail(driver):
+        ''' 获取邮箱
+        '''
+        driver.get(api._host)
+        time.sleep(7)
+        try:
+            return driver.find_element(by.XPATH, "/")
+        except Exception:
+            return "error"
+
+    def getCode(driver, email):
+        '''获取验证码
+        '''
+        driver.get(api._host+"")
+        time.sleep(7)
+        try:
+            return driver.title.split(" ")[0]
+        except Exception:
+            return "error code"
+
+
+if __name__ == "__main__":
+    pass

+ 41 - 0
twitter_account_creator/models/phone.py

@@ -0,0 +1,41 @@
+from email import header
+
+
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@Contact :   liuyuqi.gov@msn.cn
+@Time    :   2022/11/26 19:59:03
+@License :   Copyright © 2017-2022 liuyuqi. All Rights Reserved.
+@Desc    :   获取手机号,手机验证码
+'''
+import json,re,sys,logging,requests
+from twitter_account_creator.models import api
+class Phone(object):
+
+    def __init__(self, apiKey):
+        pass
+
+    def getBalance(self):
+        res = json.loads(requests.get(api.getBalance).text)
+        if res["response"] == "error":
+            return {"balance": res["error_msg"]}
+        if res["response"] == "1":
+            return {"balance": res["balance"]}
+        return {"balance": "something went wrong :/"}
+
+    def getNumber(self):
+        try:
+            res = json.loads(requests.get(api.getNumber).text)
+            number = res["number"]
+            _id = res["id"]
+            return number, _id
+        except:
+            return "error_number", "error_id"
+    def getSMS(self, id):
+        try:
+            res = json.loads(requests.get(api.getSms).text)
+            if res["sms"] != None:
+                return res["sms"]
+        except:
+            return "error_code"

+ 288 - 0
twitter_account_creator/twitter_creator.py

@@ -0,0 +1,288 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@Contact :   liuyuqi.gov@msn.cn
+@Time    :   2022/11/26 22:54:35
+@License :   Copyright © 2017-2022 liuyuqi. All Rights Reserved.
+@Desc    :   
+'''
+
+import argparse
+import json,os,re,logging
+from time import sleep, time
+import random
+from twitter_account_creator.models.phone import Phone
+from twitter_account_creator.utils.chrome import Chrome
+from twitter_account_creator.utils.edge import Edge
+from twitter_account_creator.utils.firefox import Firefox
+from selenium.webdriver.common.by import By as by
+import requests
+from twitter_account_creator.models import api
+from selenium import webdriver
+from selenium.webdriver.common.keys import Keys
+
+class Twitter(object):
+
+    def __init__(self,proxy=None):
+        self.parser = None
+        self.sess=requests.Session()
+        self.sess.proxies={
+            "127.0.0.1:1080"
+        }
+        self.driver=None
+
+
+    def signup(self, apkKey :str, url, text, proxy=None):
+        '''注册'''
+        self.driver.get(api.signup)
+        time.sleep(5)
+        
+        # 点击注册按钮
+        try:
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Sign up with phone or email')]").click(); time.sleep(10)
+        except:
+            pass
+
+        # 获取手机号码,填入手机号码
+        try:
+            # driver.find_element(by.XPATH, "//span[contains(text(), 'Use email instead')]").click(); time.sleep(1.5)
+            _email = self.driver.find_element(by.XPATH, "//input[@name='phone_number']")
+            pv = Phone()
+            number, _id = pv.getNumber()
+            number = f"+34{number}"
+            time.sleep(3.5)
+            # driver.switch_to.window(driver.window_handles[0])
+            _email.click(); _email.send_keys(f"{number}")
+        except Exception:
+            pass
+        
+        # 输入用户名
+        try:
+            name = self.getRandomName()
+            _name = self.driver.find_element(by.XPATH, "//input[@name='name']")
+            _name.click(); _name.send_keys(name); time.sleep(1.5)
+        except Exception:
+            pass
+        
+
+        try:
+            self.driver.find_element(by.XPATH, "//select[@id='SELECTOR_1']/option[@value='1']").click(); time.sleep(0.5)
+            self.driver.find_element(by.XPATH, "//select[@id='SELECTOR_2']/option[@value='1']").click(); time.sleep(0.5)
+            self.driver.find_element(by.XPATH, "//select[@id='SELECTOR_3']/option[@value='1987']").click(); time.sleep(0.5)
+        except Exception:
+            pass
+
+        try:
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Next')]").click(); time.sleep(5.5)
+        except Exception:
+            pass
+
+        try:
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Next')]").click(); time.sleep(5.5)
+        except Exception:
+            pass
+
+        try:
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Sign up')]").click(); time.sleep(5.5)
+        except Exception:
+            pass
+        try:
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'OK')]").click(); time.sleep(5.5)
+        except Exception:
+            pass
+        time.sleep(105)
+        try:
+            ver =self.driver.find_element(by.XPATH, "//input[@name='verfication_code']")
+            # driver.switch_to.window(driver.window_handles[1])
+            # ver_code = get_code(driver, email)
+            check=True
+            while check:
+                # text_res = get_sms(_id)
+                ver_code = pv.get_sms(_id)
+                if ver_code != "" and ver_code != None:
+                    check =False
+                time.sleep(5)
+            time.sleep(3.5)
+            # driver.switch_to.window(driver.window_handles[0])
+            ver.click(); ver.send_keys(ver_code)
+            time.sleep(1.5)
+        except Exception:
+            pass
+
+        try:
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Next')]").click(); time.sleep(5.5)
+        except Exception:
+            pass
+
+        try:
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Next')]").click(); time.sleep(5.5)
+            # time.sleep(60*24)
+        except Exception:
+            pass
+        
+        # 输入密码
+        try:
+            password = self.driver.find_element(by.XPATH, "//input[@name='password']"); password.click(); password.send_keys("Vojko123")
+            time.sleep(5.5)
+        except Exception:
+            pass
+
+        try:
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Next')]").click(); time.sleep(5.5)
+            # time.sleep(60*24)
+        except Exception:
+            pass
+
+        # check_phone_verification(driver, api_key)
+        
+        if not os.path.exists("data/accounts"):
+            os.makedirs("data/accounts")
+
+        try:
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Accept all cookies')]").click(); time.sleep(5.5)
+        except:
+            pass
+        try:
+            img_name = random.randint(1000, 9999)
+            open(f"data/{img_name}.jpg", "wb").write(requests.get("https://thispersondoesnotexist.com/image").content)
+            # img_info = random.choice(list(filter(None, open("infos.txt", "r").read().split("\n"))))
+            # img_name = img_info.split("\t")[0]
+            # bio = img_info.split("\t")[1]
+            time.sleep(3.5)
+            try:
+                self.driver.find_elements(by.XPATH, "//input[@data-testid='fileInput']")[1].send_keys(os.path.abspath(f"data/{img_name}.jpg")) # f"data/{img_name}.jpg"
+            except:
+                try:
+                    self.driver.find_element(by.XPATH, "//input[@data-testid='fileInput']").send_keys(os.path.abspath(f"data/{img_name}.jpg")) # f"data/{img_name}.jpg"
+                except:
+                    pass
+            time.sleep(1.5)
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Apply')]").click(); time.sleep(1.5)
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Next')]").click(); time.sleep(5.5)
+            os.remove(f"data/{img_name}.jpg")
+            # os.remove(f"data/{img_name}")
+        except Exception as e:
+            # print(e)
+            pass
+
+        # try:
+        #     txt_area = driver.find_element(by.XPATH, '//textarea[@data-testid="ocfEnterTextTextInput"]')
+        #     txt_area.click(); txt_area.send_keys(bio); time.sleep(0.5)
+        #     driver.find_element(by.XPATH, "//span[contains(text(), 'Next')]").click(); time.sleep(5.5)
+        # except:
+        #     pass
+
+        try:
+            self.driver.get("https://twitter.com"); time.sleep(7)
+            try:
+                self.driver.find_element(by.XPATH, "//span[contains(text(), 'Profile')]").click(); time.sleep(7)
+            except:
+                try:
+                    self.driver.find_element(by.XPATH, "//a[@data-testid='AppTabBar_Profile_Link']").click(); time.sleep(7)
+                except:
+                    pass
+            try:
+                username_ = self.driver.current_url.replace("https://twitter.com/", "")
+            except:
+                username_ = ""
+            img_name = random.randint()
+            open(f"data/{img_name}.jpg", "wb").write(requests.get("https://thispersondoesnotexist.com/image").content)
+            try:
+                self.driver.find_element(by.XPATH, "//span[contains(text(), 'Edit profile')]").click(); time.sleep(5.5)
+            except:
+                try:
+                    self.driver.find_element(by.XPATH, "//span[contains(text(), 'Set Up Profile')]").click(); time.sleep(5.5)
+                except:
+                    try:
+                        self.driver.find_element(by.XPATH, "//span[contains(text(), 'Set up profile')]").click(); time.sleep(5.5)
+                    except:
+                        pass
+            # driver.find_element(by.XPATH, "//input[@data-testid='fileInput']").send_keys(f"data/{img_name}.jpg")
+            self.driver.find_elements(by.XPATH, "//input[@data-testid='fileInput']")[1].send_keys(os.path.abspath(f"data/{img_name}.jpg"))
+            time.sleep(1.5)
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Apply')]").click(); time.sleep(1.5)
+            self.driver.find_element(by.XPATH, "//span[contains(text(), 'Save')]").click(); time.sleep(5.5)
+        except:
+            pass
+
+        time.sleep(1.5)
+
+        # 评论
+        # driver.get(url); time.sleep(7)
+        # self.comments(driver, text)
+        
+        # 写入账户
+        os.makedirs("data/accounts") if not os.path.exists("data/accounts") else False
+        with open("data/accounts/accounts.txt", "a") as file:
+            file.write(f"{number}:Vojko123:{username_}\n")
+        self.driver.quit()
+
+
+    def comments(self,driver,text):
+        try:
+            add_comment = driver.find_element(by.XPATH, "//div[@data-testid='reply']")        
+            add_comment.click(); time.sleep(3.5)
+            add_comment = driver.find_element(by.XPATH, "//div[@data-testid='tweetTextarea_0']")
+            add_comment.click(); add_comment.send_keys(text); time.sleep(1.5)
+            add_comment.send_keys(" "); time.sleep(1.5)
+            try:
+                driver.find_element(by.XPATH, "//span[contains(text(), 'Reply')]").click()
+            except:
+                try:
+                    driver.find_element(by.XPATH, "//span[contains(text(), 'Tweet')]").click()
+                except:
+                    try:
+                        add_comment.send_keys(Keys.ENTER)
+                    except:
+                        pass
+            # driver.find_element(by.XPATH, "//span[contains(text(), 'Tweet')]").click()
+            time.sleep(5.5)
+            e="Success comment"
+        except Exception as e:
+            # print(e)
+            return e
+            pass
+        return e
+
+    def phoneVerification(self, apiKey):
+        if self.driver.current_url==api.accountAccess:
+            try:
+                # self.driver.find_element(by=by.XPATH,"//")
+                # number,_id=pv.getNumber
+                pass
+
+            except Exception as e:
+                pass
+            finally:
+                pass
+
+    def getRandomName(self):
+        '''获取随机昵称'''
+        return json.loads(self.sess.get(api.getNickName).text)["name"]
+
+    def run(self):
+        # 下载驱动
+        self.chooseBrowser()
+        self.signup(apkKey="xx",url="",text="xx")
+
+
+    def chooseBrowser(self):
+        browserType=input("if you installed \r\n Chrome input 1,\r\n Edge input 2,\r\n Firefox iniput 3:\r\n")
+           # self.driver= webdriver.Chrome(executable_path=chrome_path,options=options)
+        # chrome = Chrome()
+        # self.driver=chrome.getWebdriver(proxy_address=proxy)
+        if browserType=="1":
+            self.driver=Chrome().getWebdriver()
+        elif browserType=="2":
+            self.driver=Edge().getWebdriver(proxy_address='127.0.0.1:1080')
+        elif browserType=="3":
+            self.driver=Firefox().getWebdriver()
+        
+    def getArgs(self):
+        '''获取参数'''
+        self.parser = argparse.ArgumentParser(description="desc help")
+        self.parser.add_argument(
+            "--proxy", type=str, default="127.0.0.1:1080", help="input local proxy")
+        self.parser.add_argument(
+            "--pwd", type=str, default="123456", help="input password")
+        return self.parser.parse_args()

+ 0 - 0
twitter_account_creator/utils/__init__.py


+ 78 - 0
twitter_account_creator/utils/browser.py

@@ -0,0 +1,78 @@
+from genericpath import exists
+from importlib.resources import path
+import os,sys,re,logging
+from selenium import webdriver
+from selenium.webdriver.chrome.options import Options
+import requests
+from selenium.webdriver.chrome.service import Service
+
+class Browser(object):
+    '''浏览器基类,Edge,Chrome,Firefox'''
+    
+    def __init__(self):
+        os.makedirs("data") if not os.path.exists("data") else False
+        os.makedirs("data/driver") if not os.path.exists("data/driver") else False
+        os.makedirs("data/browser-profiles") if not os.path.exists("data/browser-profiles") else False
+
+        # 下载驱动
+        self.sess=requests.Session()
+        self.downloadDriver()
+
+    def downloadDriver(self):
+        '''需要之类实现'''
+        pass
+
+    def getWebdriver(self):
+        pass
+
+    def close(self,driver:webdriver.Chrome):
+        driver.close()
+
+    def options(self, i=None, proxy=False, headless=False, browser_profile=None, proxy_address=None):
+        '''配置'''
+        chrome_options = Options()
+        if proxy_address is not None and len(proxy_address.split(":")) == 2:
+            chrome_options.add_argument("--proxy-server="+proxy_address)
+        if proxy_address is not None and len(proxy_address.split(":")) == 4:
+            i=random.randint(1000, 9999999)
+            proxy = Proxy(*proxy_address.split(":"), i); time.sleep(1.5)
+            chrome_options.add_extension(proxy)
+            # chrome_options.add_argument(f'--load-extension='+proxy)
+        if browser_profile is not None:
+            os.makedirs("data/browser-profiles") if not os.path.exists("data/browser-profiles") else False
+            # user_data_dir = user_data_dir = f'data/browser-profiles/{random.randint(1000, 9999)}-{"".join(random.choice(string.ascii_letters) for i in range(8))}'
+            user_data_dir = f'data/browser-profiles/{browser_profile}'
+            os.makedirs(user_data_dir) if not os.path.exists(user_data_dir) else False
+            self.user_dir = user_data_dir
+            chrome_options.add_argument("--user-data-dir=%s" % user_data_dir)
+        # 增加扩展
+        # if not headless:
+        #     chrome_options.add_extension(os.path.abspath("creator/src/chrome/extensions/always_active.zip"))
+        #     chrome_options.add_extension(os.path.abspath("creator/src/chrome/extensions/fingerprint_defender.zip"))
+        #     chrome_options.add_extension(os.path.abspath("creator/src/chrome/extensions/spoof_timezone.zip"))
+        #     chrome_options.add_extension(os.path.abspath("creator/src/chrome/extensions/webrtc_control.zip"))
+        chrome_options.add_argument('--mute-audio')
+        chrome_options.add_argument("--start-maximized")
+        chrome_options.add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'})
+        chrome_options.add_argument('Content-Type="text/html"')
+        if headless:
+            chrome_options.add_argument("--headless")
+        chrome_options.add_argument('chartset=utf-8')
+        chrome_options.add_argument("--no-sandbox")
+        chrome_options.add_argument("--disable-gpu")
+        chrome_options.add_argument("--disable-crash-reporter")
+        chrome_options.add_argument("--disable-in-process-stack-traces")
+        chrome_options.add_argument("--disable-logging")
+        chrome_options.add_argument("--disable-dev-shm-usage")
+        chrome_options.add_argument("--log-level=3")
+        chrome_options.add_argument("--output=/dev/null")
+        if proxy!=False and i!=None:
+            chrome_options.add_extension(f"data/extension/proxy_auth_plugin_{i}.zip")
+        chrome_options.add_experimental_option("excludeSwitches", ["enable-automation", "enable-logging"])
+        chrome_options.add_experimental_option('useAutomationExtension', False)
+        chrome_options.add_experimental_option('prefs', {'intl.accept_languages': 'en_US,en'})
+        chrome_options.add_argument('--disable-features=UserAgentClientHint')
+        webdriver.DesiredCapabilities.CHROME['loggingPrefs'] = {'driver': 'OFF', 'server': 'OFF', 'browser': 'OFF'}
+        webdriver.DesiredCapabilities.CHROME['acceptSslCerts']=True
+        return chrome_options
+

+ 200 - 0
twitter_account_creator/utils/chrome.py

@@ -0,0 +1,200 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@Contact :   liuyuqi.gov@msn.cn
+@Time    :   2022/11/27 13:17:27
+@License :   Copyright © 2017-2022 liuyuqi. All Rights Reserved.
+@Desc    :   
+'''
+from importlib.resources import path
+import random, string, io, os, shutil, platform, subprocess, sys, zipfile, time
+from selenium import webdriver
+from selenium.webdriver.chrome.options import Options
+import undetected_chromedriver.v2 as uc
+from webdriver_manager.chrome import ChromeDriverManager
+
+class Chrome():
+    driverPath = None
+    user_dir = None
+
+    def __init__(self):
+        os.makedirs("data") if not os.path.exists("data") else False
+        os.makedirs("data/driver") if not os.path.exists("data/driver") else False
+        os.makedirs("data/browser-profiles") if not os.path.exists("data/browser-profiles") else False
+
+        download_driver()
+        self.driverPath = ChromeDriverManager(path="data/driver").install()
+
+        # if sys.platform == "win32":
+        #     # shutil.move("chromedriver.exe", "data/driver")
+        #     cd = os.path.abspath("data/driver/chromedriver.exe")
+        # else:
+        #     # shutil.move("chromedriver", "data/driver")
+        #     time.sleep(2.5)
+        #     #cd = os.path.abspath(path)
+        # Patcher(executable_path=cd).patch_exe()
+    
+    @staticmethod
+    def gen_random_cdc():
+        '''随机生成字符串'''
+        cdc = random.choices(string.ascii_lowercase, k=26)
+        cdc[-6:-4] = map(str.upper, cdc[-6:-4])
+        cdc[2] = cdc[0]
+        cdc[3] = "_"
+        return "".join(cdc).encode()
+
+    def monkey_patch_exe(self):
+        '''添加补丁'''
+        linect = 0
+        replacement = self.gen_random_cdc()
+        replacement = f"  var key = '${replacement.decode()}_';\n".encode()
+        with io.open(self.driverPath, "r+b") as fh:
+            for line in iter(lambda: fh.readline(), b""):
+                if b"var key = " in line:
+                    fh.seek(-len(line), 1)
+                    fh.write(replacement)
+                    linect += 1
+            return linect
+    
+    def getWebdriver(self, i=None, proxy=False, headless=False, browser_profile=None, proxy_address=None):
+        '''
+        get webdriver
+        
+        :param i: i
+        :param proxy: 代理
+        :param headless: 是否无头模式
+        :param browser_profile: i
+        :param proxy_address: i
+        :returns: webdriver
+        '''
+        options = self.options(i=i, proxy=proxy, headless=headless, browser_profile=browser_profile, proxy_address=proxy_address)
+        return webdriver.Chrome(executable_path=self.driverPath, options=options)
+
+def setup_useragent(driver :webdriver.Chrome):
+    # driver.execute_cdp_cmd("Network.setUserAgentOverride", {"userAgent": f"{random_user_agent}"})
+    pass
+
+def Proxy(PROXY_HOST, PROXY_PORT, PROXY_USER, PROXY_PASS, i):
+	try:
+		manifest_json = """
+		{
+			"manifest_version": 2,
+			"name": "Proxy Manager",
+			"version": "3.0.11",
+			"permissions": [
+				"proxy",
+				"tabs",
+				"unlimitedStorage",
+				"storage",
+				"<all_urls>",
+				"webRequest",
+				"webRequestBlocking"
+			],
+			"background": {
+				"scripts": ["background.js"]
+			},
+			"minimum_chrome_version":"22.0.0"
+		}
+		"""
+
+		background_js = string.Template(
+		"""
+		var config = {
+				mode: "fixed_servers",
+				rules: {
+				singleProxy: {
+					scheme: "http",
+					host: "${PROXY_HOST}",
+					port: parseInt(${PROXY_PORT})
+				},
+				bypassList: ["foobar.com"]
+				}
+			};
+		chrome.proxy.settings.set({value: config, scope: "regular"}, function() {});
+		function callbackFn(details) {
+			return {
+				authCredentials: {
+					username: "${PROXY_USER}",
+					password: "${PROXY_PASS}"
+				}
+			};
+		}
+		chrome.webRequest.onAuthRequired.addListener(
+					callbackFn,
+					{urls: ["<all_urls>"]},
+					['blocking']
+		);
+		"""
+		).substitute(
+			PROXY_HOST=PROXY_HOST,
+			PROXY_PORT=PROXY_PORT,
+			PROXY_USER=PROXY_USER,
+			PROXY_PASS=PROXY_PASS)
+        
+		if not os.path.exists("data/extension"):
+			os.makedirs("data/extension")
+
+		with zipfile.ZipFile(f'data/extension/proxy_auth_plugin_{i}.zip', 'w', zipfile.ZIP_DEFLATED, False) as zp:
+			zp.writestr('manifest.json', manifest_json)
+			zp.writestr('background.js', background_js)
+		return f"data/extension/proxy_auth_plugin_{i}.zip"
+	except Exception as e:
+		return False
+		now = datetime.now().strftime('%H:%M:%S')
+		print(f'[{now}] - {e}')
+
+class bcolors:
+    HEADER = '\033[95m'
+    OKBLUE = '\033[94m'
+    OKCYAN = '\033[96m'
+    OKGREEN = '\033[92m'
+    WARNING = '\033[93m'
+    FAIL = '\033[91m'
+    ENDC = '\033[0m'
+    BOLD = '\033[1m'
+    UNDERLINE = '\033[4m'
+
+CHROME = ['{8A69D345-D564-463c-AFF1-A69D9E530F96}',
+          '{8237E44A-0054-442C-B6B6-EA0509993955}',
+          '{401C381F-E0DE-4B85-8BD8-3F3F14FBDA57}',
+          '{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}']
+
+def download_driver():
+    '''根据系统安装的chrome版本,下载指定版本的 chrome-driver 驱动'''
+    OSNAME = platform.system()
+    print(bcolors.WARNING + 'Getting Chrome Driver...' + bcolors.ENDC)
+    if OSNAME == 'Linux':
+        OSNAME = 'lin'
+        EXE_NAME = ""
+        with subprocess.Popen(['google-chrome', '--version'], stdout=subprocess.PIPE) as proc:
+            version = proc.stdout.read().decode('utf-8').replace('Google Chrome', '').strip()
+    elif OSNAME == 'Darwin':
+        OSNAME = 'mac'
+        EXE_NAME = ""
+        process = subprocess.Popen(['/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', '--version'], stdout=subprocess.PIPE)
+        version = process.communicate()[0].decode('UTF-8').replace('Google Chrome', '').strip()
+    elif OSNAME == 'Windows':
+        OSNAME = 'win'
+        EXE_NAME = ".exe"
+        version = None
+        try:
+            process = subprocess.Popen(['reg', 'query', 'HKEY_CURRENT_USER\\Software\\Google\\Chrome\\BLBeacon', '/v', 'version'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)
+            version = process.communicate()[0].decode(
+                'UTF-8').strip().split()[-1]
+        except:
+            for i in CHROME:
+                for j in ['opv', 'pv']:
+                    try:
+                        command = ['reg', 'query', f'HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\Clients\\{i}', '/v', f'{j}', '/reg:32']
+                        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)
+                        version = process.communicate()[0].decode('UTF-8').strip().split()[-1]
+                    except:
+                        pass
+        if not version:
+            print(bcolors.WARNING + "Couldn't find your Google Chrome version automatically!" + bcolors.ENDC)
+            version = input(bcolors.WARNING + 'Please input your google chrome version (ex: 91.0.4472.114) : ' + bcolors.ENDC)
+    else:
+        print('{} OS is not supported.'.format(OSNAME))
+        sys.exit()
+    # uc.install()
+

+ 39 - 0
twitter_account_creator/utils/download_progress.py

@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+'''
+下载进度
+@Auther :liuyuqi.gov@msn.cn
+@date :2019/4/8
+'''
+__author__ = "liuyuqi"
+
+
+class DownloadProgress(object):
+    def __init__(self, title, count=0.0, run_status=None, fin_status=None, total=100.0, unit='', sep='/',
+                 chunk_size=1.0):
+        super(DownloadProgress, self).__init__()
+        self.info = "[%s] %s %.2f %s %s %.2f %s"
+        self.title = title
+        self.total = total
+        self.count = count
+        self.chunk_size = chunk_size
+        self.status = run_status or ""
+        self.fin_status = fin_status or " " * len(self.status)
+        self.unit = unit
+        self.seq = sep
+
+    def __get_info(self):
+        # 【名称】状态 进度 单位 分割线 总数 单位
+        _info = self.info % (
+            self.title, self.status, self.count / self.chunk_size, self.unit, self.seq, self.total / self.chunk_size,
+            self.unit)
+        return _info
+
+    def refresh(self, count=1, status=None):
+        self.count += count
+        # if status is not None:
+        self.status = status or self.status
+        end_str = "\r"
+        if self.count >= self.total:
+            end_str = '\n'
+            self.status = status or self.fin_status
+        print(self.__get_info(), end=end_str)

+ 23 - 0
twitter_account_creator/utils/edge.py

@@ -0,0 +1,23 @@
+from twitter_account_creator.utils.browser import Browser
+import undetected_chromedriver as uc
+from webdriver_manager.microsoft import EdgeChromiumDriverManager
+from selenium import webdriver
+import undetected_chromedriver as uc
+from selenium.webdriver.chrome.service import Service
+
+class Edge(Browser):
+    '''
+    Edge+selenium
+    '''
+    # https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
+    
+    def __init__(self):
+        super().__init__()
+
+    def getWebdriver(self, i=None, proxy=False, headless=False, browser_profile=None, proxy_address=None):
+        super().getWebdriver()
+        options = self.options(i=i, proxy=proxy, headless=headless, browser_profile=browser_profile, proxy_address=proxy_address)
+        # EdgeChromiumDriverManager下载驱动
+        # driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))
+        return    webdriver.Edge(service=Service(EdgeChromiumDriverManager(path="data/driver").install()))
+        # return webdriver.Chrome(service=Service(EdgeChromiumDriverManager(path="data/driver").install()), options=options)

+ 9 - 0
twitter_account_creator/utils/firefox.py

@@ -0,0 +1,9 @@
+import os,sys,re
+from twitter_account_creator.utils.browser import Browser
+
+class Firefox(Browser):
+    
+    def __init__(self):
+        super.__init__()
+
+