├── README.md ├── drivers ├── chromedriver.exe └── geckodriver.exe ├── extensions ├── 127.0.0.1_8118.zip └── 127.0.0.1_8118 │ ├── manifest.json │ └── background.js ├── 02-helloworld-firefox.py ├── 01-helloworld-chrome.py ├── 07-proxy-without-password.py ├── 04-wait.py ├── 09-request-block.py ├── 10-request-intercept.py ├── 11-request-har.py ├── easing.py ├── 03-input-output.py ├── 05-execute-js.py ├── 06-request-intercept.py ├── 08-proxy-with-password.py └── 12-slider-captcha.py /README.md: -------------------------------------------------------------------------------- 1 | # selenium-test 2 | test cases for learning selenium 3 | -------------------------------------------------------------------------------- /drivers/chromedriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aneasystone/selenium-test/master/drivers/chromedriver.exe -------------------------------------------------------------------------------- /drivers/geckodriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aneasystone/selenium-test/master/drivers/geckodriver.exe -------------------------------------------------------------------------------- /extensions/127.0.0.1_8118.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aneasystone/selenium-test/master/extensions/127.0.0.1_8118.zip -------------------------------------------------------------------------------- /02-helloworld-firefox.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/2/13 4 | from selenium import webdriver 5 | 6 | # geckodriver can downloaded from: https://github.com/mozilla/geckodriver/releases 7 | browser = webdriver.Firefox(executable_path="./drivers/geckodriver.exe") 8 | browser.get('https://www.baidu.com') -------------------------------------------------------------------------------- /01-helloworld-chrome.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/2/13 4 | from selenium import webdriver 5 | 6 | # chromedriver can downloaded from: https://sites.google.com/a/chromium.org/chromedriver/ 7 | browser = webdriver.Chrome(executable_path="./drivers/chromedriver.exe") 8 | browser.get('https://www.baidu.com') -------------------------------------------------------------------------------- /07-proxy-without-password.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/2/28 4 | from selenium import webdriver 5 | 6 | chrome_options = webdriver.ChromeOptions() 7 | chrome_options.add_argument('--proxy-server=127.0.0.1:8118') 8 | 9 | browser = webdriver.Chrome( 10 | executable_path="./drivers/chromedriver.exe", 11 | chrome_options=chrome_options 12 | ) 13 | browser.get('http://ip138.com') -------------------------------------------------------------------------------- /extensions/127.0.0.1_8118/manifest.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "version": "1.0.0", 4 | "manifest_version": 2, 5 | "name": "Chrome Proxy", 6 | "permissions": [ 7 | "proxy", 8 | "tabs", 9 | "unlimitedStorage", 10 | "storage", 11 | "", 12 | "webRequest", 13 | "webRequestBlocking" 14 | ], 15 | "background": { 16 | "scripts": ["background.js"] 17 | }, 18 | "minimum_chrome_version":"22.0.0" 19 | } 20 | -------------------------------------------------------------------------------- /04-wait.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/2/13 4 | from selenium import webdriver 5 | from selenium.webdriver.common.by import By 6 | from selenium.webdriver.support.ui import WebDriverWait as Wait 7 | from selenium.webdriver.support import expected_conditions as Expect 8 | 9 | browser = webdriver.Chrome(executable_path="./drivers/chromedriver.exe") 10 | browser.get('http://www.tuniu.com/flight/intel/sha-sel') 11 | Wait(browser, 60).until( 12 | Expect.text_to_be_present_in_element((By.ID, "loadingStatus"), u"共搜索") 13 | ) 14 | 15 | flight_items = browser.find_elements_by_class_name("flight-item") 16 | for flight_item in flight_items: 17 | flight_price_row = flight_item.find_element_by_class_name("flight-price-row") 18 | print(flight_price_row.get_attribute("data-no")) -------------------------------------------------------------------------------- /extensions/127.0.0.1_8118/background.js: -------------------------------------------------------------------------------- 1 | 2 | chrome.proxy.settings.set({ 3 | value: { 4 | mode: "fixed_servers", 5 | rules: { 6 | singleProxy: { 7 | scheme: "http", 8 | host: "127.0.0.1", 9 | port: 8118 10 | }, 11 | bypassList: ["foobar.com"] 12 | } 13 | }, 14 | scope: "regular" 15 | }, function() {}); 16 | 17 | chrome.webRequest.onAuthRequired.addListener( 18 | function (details) { 19 | return { 20 | authCredentials: { 21 | username: "", 22 | password: "" 23 | } 24 | }; 25 | }, 26 | { urls: [""] }, 27 | [ 'blocking' ] 28 | ); 29 | -------------------------------------------------------------------------------- /09-request-block.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/3/1 4 | from selenium import webdriver 5 | from browsermobproxy import Server 6 | 7 | # bmp can downloaded from: https://github.com/lightbody/browsermob-proxy/releases 8 | server = Server("D:/browsermob-proxy-2.1.4/bin/browsermob-proxy") 9 | server.start() 10 | proxy = server.create_proxy() 11 | 12 | proxy.blacklist(".*google-analytics.*", 404) 13 | proxy.blacklist(".*google.*", 404) 14 | proxy.blacklist(".*yahoo.*", 404) 15 | proxy.blacklist(".*facebook.*", 404) 16 | proxy.blacklist(".*twitter.*", 404) 17 | # proxy.blacklist(".*flypeach.*", 404) 18 | 19 | chrome_options = webdriver.ChromeOptions() 20 | chrome_options.add_argument("--proxy-server={0}".format(proxy.proxy)) 21 | browser = webdriver.Chrome( 22 | executable_path="./drivers/chromedriver.exe", 23 | chrome_options = chrome_options 24 | ) 25 | browser.get('http://www.flypeach.com/pc/hk') 26 | 27 | server.stop() 28 | browser.quit() 29 | -------------------------------------------------------------------------------- /10-request-intercept.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/3/1 4 | from selenium import webdriver 5 | from browsermobproxy import Server 6 | 7 | # bmp can downloaded from: https://github.com/lightbody/browsermob-proxy/releases 8 | server = Server("D:/browsermob-proxy-2.1.4/bin/browsermob-proxy") 9 | server.start() 10 | proxy = server.create_proxy() 11 | 12 | request_js = ( 13 | ''' 14 | request.headers().remove('User-Agent'); 15 | request.headers().add('User-Agent', 'My-Custom-User-Agent-String 1.0'); 16 | ''' 17 | ) 18 | response_js = ( 19 | ''' 20 | if (messageInfo.getOriginalUrl().contains("remote/searchFlights")) { 21 | contents.setTextContents('Hello World'); 22 | } 23 | ''' 24 | ) 25 | proxy.request_interceptor(request_js) 26 | proxy.response_interceptor(response_js) 27 | 28 | chrome_options = webdriver.ChromeOptions() 29 | chrome_options.add_argument("--proxy-server={0}".format(proxy.proxy)) 30 | browser = webdriver.Chrome( 31 | executable_path="./drivers/chromedriver.exe", 32 | chrome_options = chrome_options 33 | ) 34 | browser.get('http://www.tuniu.com/flight/intel/sha-bkk') 35 | 36 | server.stop() 37 | # browser.quit() -------------------------------------------------------------------------------- /11-request-har.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/3/1 4 | import json 5 | from selenium import webdriver 6 | from browsermobproxy import Server 7 | from selenium.webdriver.common.by import By 8 | from selenium.webdriver.support.ui import WebDriverWait as Wait 9 | from selenium.webdriver.support import expected_conditions as Expect 10 | 11 | # bmp can downloaded from: https://github.com/lightbody/browsermob-proxy/releases 12 | server = Server("D:/browsermob-proxy-2.1.4/bin/browsermob-proxy") 13 | server.start() 14 | proxy = server.create_proxy() 15 | 16 | proxy.blacklist(".*gov.cn.*", 404) 17 | proxy.new_har(options={ 18 | 'captureContent': True 19 | }) 20 | 21 | chrome_options = webdriver.ChromeOptions() 22 | chrome_options.add_argument("--proxy-server={0}".format(proxy.proxy)) 23 | browser = webdriver.Chrome( 24 | executable_path="./drivers/chromedriver.exe", 25 | chrome_options=chrome_options 26 | ) 27 | browser.get('http://www.tuniu.com/flight/intel/sha-bkk') 28 | Wait(browser, 60).until( 29 | Expect.text_to_be_present_in_element((By.ID, "loadingStatus"), u"共搜索") 30 | ) 31 | 32 | for entry in proxy.har['log']['entries']: 33 | if 'remote/searchFlights' in entry['request']['url']: 34 | result = json.loads(entry['response']['content']['text']) 35 | for key, item in result['data']['flightInfo'].items(): 36 | print(key) 37 | 38 | server.stop() 39 | browser.quit() -------------------------------------------------------------------------------- /easing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/3/14 4 | import numpy as np 5 | import math 6 | 7 | 8 | # https://github.com/gdsmith/jquery.easing/blob/master/jquery.easing.js 9 | def ease_in_quad(x): 10 | return x * x 11 | 12 | 13 | def ease_out_quad(x): 14 | return 1 - (1 - x) * (1 - x) 15 | 16 | 17 | def ease_out_quart(x): 18 | return 1 - pow(1 - x, 4) 19 | 20 | 21 | def ease_out_expo(x): 22 | if x == 1: 23 | return 1 24 | else: 25 | return 1 - pow(2, -10 * x) 26 | 27 | 28 | def ease_out_bounce(x): 29 | n1 = 7.5625 30 | d1 = 2.75 31 | if x < 1 / d1 : 32 | return n1 * x * x 33 | elif x < 2 / d1: 34 | x -= 1.5 / d1 35 | return n1 * x*x + 0.75 36 | elif x < 2.5 / d1: 37 | x -= 2.25 / d1 38 | return n1 * x*x + 0.9375 39 | else: 40 | x -= 2.625 / d1 41 | return n1 * x*x + 0.984375 42 | 43 | 44 | def ease_out_elastic(x): 45 | if x == 0: 46 | return 0 47 | elif x == 1: 48 | return 1 49 | else: 50 | c4 = (2 * math.pi) / 3 51 | return pow(2, -10 * x) * math.sin((x * 10 - 0.75) * c4) + 1 52 | 53 | 54 | def get_tracks(distance, seconds, ease_func): 55 | tracks = [0] 56 | offsets = [0] 57 | for t in np.arange(0.0, seconds, 0.1): 58 | ease = globals()[ease_func] 59 | offset = round(ease(t/seconds) * distance) 60 | tracks.append(offset - offsets[-1]) 61 | offsets.append(offset) 62 | return offsets, tracks 63 | -------------------------------------------------------------------------------- /03-input-output.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/2/13 4 | from selenium import webdriver 5 | from selenium.webdriver.common.keys import Keys 6 | import time 7 | 8 | # chromedriver can downloaded from: https://sites.google.com/a/chromium.org/chromedriver/ 9 | browser = webdriver.Chrome(executable_path="./drivers/chromedriver.exe") 10 | browser.get('https://www.baidu.com') 11 | 12 | kw = browser.find_element_by_id("kw") 13 | su = browser.find_element_by_id("su") 14 | 15 | # 16 | # input 17 | # 18 | 19 | # method 1, send keys with return 20 | # kw.send_keys("Selenium", Keys.RETURN) 21 | 22 | # method 2, send keys then click submit button 23 | # kw.send_keys("Selenium") 24 | # su.click() 25 | 26 | # method 3, send keys then submit form 27 | # kw.send_keys("Selenium") 28 | # kw.submit() 29 | 30 | # method 4, execute javascript 31 | browser.execute_script( 32 | ''' 33 | var kw = document.getElementById('kw'); 34 | var su = document.getElementById('su'); 35 | kw.value = 'Selenium'; 36 | su.click(); 37 | ''' 38 | ) 39 | 40 | time.sleep(3) 41 | 42 | # 43 | # output 44 | # 45 | 46 | # method 1, parse page_source 47 | # print(browser.page_source) 48 | 49 | # method 2, find elements 50 | results = browser.find_elements_by_css_selector("#content_left .c-container") 51 | for result in results: 52 | print(result.get_attribute("id")) 53 | # //h3/a searches the whole page for the XPath expression. 54 | # .//h3/a takes the specified element as root 55 | link = result.find_element_by_xpath(".//h3/a") 56 | print(link.text) -------------------------------------------------------------------------------- /05-execute-js.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/2/13 4 | from selenium import webdriver 5 | from selenium.webdriver.common.keys import Keys 6 | from selenium.webdriver.common.by import By 7 | from selenium.webdriver.support.ui import WebDriverWait as Wait 8 | from selenium.webdriver.support import expected_conditions as Expect 9 | from selenium.webdriver.support.select import Select 10 | 11 | browser = webdriver.Chrome(executable_path="./drivers/chromedriver.exe") 12 | browser.get('http://www.tuniu.com/flight_intel/') 13 | 14 | # method 1 totally simulate human action 15 | depart = browser.find_element_by_name("departCityName") 16 | depart.click() 17 | depart.send_keys("BJS") 18 | Wait(browser, 10).until( 19 | Expect.presence_of_element_located((By.CLASS_NAME, "tn-city-node")) 20 | ) 21 | depart.send_keys(Keys.RETURN) 22 | 23 | dest = browser.find_element_by_name("destCityName") 24 | dest.click() 25 | dest.send_keys("SEL") 26 | Wait(browser, 10).until( 27 | Expect.presence_of_element_located((By.CLASS_NAME, "tn-city-node")) 28 | ) 29 | dest.send_keys(Keys.RETURN) 30 | 31 | # method 2 execute javascript 32 | browser.execute_script("$('input[name=departCityName]').val('CAN')") 33 | browser.execute_script("$('input[name=destCityName]').val('MFM')") 34 | browser.execute_script("$('input[name=departDate]').val('2018-10-01')") 35 | browser.execute_script("$('input[name=destDate]').val('2018-10-05')") 36 | browser.execute_script("$('select[name=adultQuantity]').setValue(2)") 37 | 38 | adultQuantity = browser.find_element_by_name("adultQuantity") 39 | Select(adultQuantity).select_by_value("4") 40 | 41 | browser.execute_script("arguments[0].click();", browser.find_element_by_xpath("//div[@data-name='typeSelect']/span[1]")) 42 | # browser.execute_script("arguments[0].click();", browser.find_element_by_id("searchIntl")) -------------------------------------------------------------------------------- /06-request-intercept.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/2/13 4 | from selenium import webdriver 5 | from browsermobproxy import Server 6 | 7 | # bmp can downloaded from: https://github.com/lightbody/browsermob-proxy/releases 8 | server = Server("D:/browsermob-proxy-2.1.4/bin/browsermob-proxy") 9 | server.start() 10 | proxy = server.create_proxy() 11 | 12 | 13 | ''' 拦截请求,对请求参数进行修改,或者直接返回伪造响应 14 | proxyServer.addRequestFilter(new RequestFilter() { 15 | @Override 16 | public io.netty.handler.codec.http.HttpResponse filterRequest( 17 | io.netty.handler.codec.http.HttpRequest request, 18 | net.lightbody.bmp.util.HttpMessageContents contents, 19 | net.lightbody.bmp.util.HttpMessageInfo messageInfo) { 20 | String url = messageInfo.getOriginalUrl(); 21 | if (url.contains("twitter.com") || url.contains("google.com") || url.contains("doubleclick.net")) { 22 | HttpResponse response = new io.netty.handler.codec.http.DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND); 23 | HttpHeaders.setContentLength(response, 0L); 24 | return response; 25 | } 26 | return null; 27 | } 28 | }); 29 | ''' 30 | 31 | # request_js = ( 32 | # ''' 33 | # var url = messageInfo.getOriginalUrl(); 34 | # if (url.contains("google") || url.contains("yahoo") || url.contains("twitter") || url.contains("facebook")) { 35 | # //return new io.netty.handler.codec.http.DefaultFullHttpResponse( 36 | # // io.netty.handler.codec.http.HttpVersion.HTTP_1_1, 37 | # // io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND 38 | # //); 39 | # } 40 | # ''' 41 | # ) 42 | # proxy.request_interceptor(request_js) 43 | 44 | proxy.blacklist(".*google-analytics.*", 404) 45 | proxy.blacklist(".*google.*", 404) 46 | proxy.blacklist(".*yahoo.*", 404) 47 | proxy.blacklist(".*facebook.*", 404) 48 | proxy.blacklist(".*twitter.*", 404) 49 | # proxy.blacklist(".*flypeach.*", 404) 50 | 51 | # webdriver.Proxy(proxy.proxy) # not work 52 | 53 | profile = webdriver.FirefoxProfile() 54 | profile.set_proxy(proxy.selenium_proxy()) # deprecated, but works 55 | 56 | browser = webdriver.Firefox( 57 | executable_path="./drivers/geckodriver.exe", 58 | firefox_profile=profile, 59 | # proxy=proxy.selenium_proxy() # not work 60 | ) 61 | browser.get('http://www.flypeach.com/pc/hk') 62 | 63 | server.stop() 64 | browser.quit() 65 | 66 | # chrome_options = webdriver.ChromeOptions() 67 | # chrome_options.add_argument("--proxy-server={0}".format(proxy.proxy)) 68 | # browser = webdriver.Chrome(chrome_options = chrome_options) -------------------------------------------------------------------------------- /08-proxy-with-password.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/2/28 4 | import os, shutil 5 | import zipfile 6 | from selenium import webdriver 7 | 8 | extension_dir = './extensions' 9 | proxy = { 10 | 'schema': 'http', 11 | 'host': '127.0.0.1', 12 | 'port': '8118', 13 | 'username': '', 14 | 'password': '' 15 | } 16 | 17 | 18 | def get_manifest_content(): 19 | return ''' 20 | { 21 | "version": "1.0.0", 22 | "manifest_version": 2, 23 | "name": "Chrome Proxy", 24 | "permissions": [ 25 | "proxy", 26 | "tabs", 27 | "unlimitedStorage", 28 | "storage", 29 | "", 30 | "webRequest", 31 | "webRequestBlocking" 32 | ], 33 | "background": { 34 | "scripts": ["background.js"] 35 | }, 36 | "minimum_chrome_version":"22.0.0" 37 | } 38 | ''' 39 | 40 | 41 | def get_background_content(): 42 | return ''' 43 | chrome.proxy.settings.set({{ 44 | value: {{ 45 | mode: "fixed_servers", 46 | rules: {{ 47 | singleProxy: {{ 48 | scheme: "{0}", 49 | host: "{1}", 50 | port: {2} 51 | }}, 52 | bypassList: ["foobar.com"] 53 | }} 54 | }}, 55 | scope: "regular" 56 | }}, function() {{}}); 57 | 58 | chrome.webRequest.onAuthRequired.addListener( 59 | function (details) {{ 60 | return {{ 61 | authCredentials: {{ 62 | username: "{3}", 63 | password: "{4}" 64 | }} 65 | }}; 66 | }}, 67 | {{ urls: [""] }}, 68 | [ 'blocking' ] 69 | ); 70 | '''.format(proxy['schema'], proxy['host'], proxy['port'], proxy['username'], proxy['password']) 71 | 72 | 73 | def get_extension_file_path(): 74 | path = "{0}/{1}_{2}.zip".format(extension_dir, proxy['host'], proxy['port']) 75 | if os.path.exists(path): 76 | os.remove(path) 77 | 78 | zf = zipfile.ZipFile(path, mode='w') 79 | zf.writestr('manifest.json', get_manifest_content()) 80 | zf.writestr('background.js', get_background_content()) 81 | zf.close() 82 | return os.path.abspath(path) 83 | 84 | 85 | def get_extension_dir_path(): 86 | path = "{0}/{1}_{2}".format(extension_dir, proxy['host'], proxy['port']) 87 | if os.path.exists(path): 88 | shutil.rmtree(path) 89 | os.makedirs(path) 90 | 91 | with open(path + '/manifest.json', 'w') as f: 92 | f.write(get_manifest_content()) 93 | with open(path + '/background.js', 'w') as f: 94 | f.write(get_background_content()) 95 | return os.path.abspath(path) 96 | 97 | chrome_options = webdriver.ChromeOptions() 98 | # chrome_options.add_extension(get_extension_file_path()) 99 | chrome_options.add_argument('--load-extension={0}'.format(get_extension_dir_path())) 100 | 101 | browser = webdriver.Chrome( 102 | executable_path="./drivers/chromedriver.exe", 103 | chrome_options=chrome_options 104 | ) 105 | browser.get('http://ip138.com') -------------------------------------------------------------------------------- /12-slider-captcha.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created by aneasystone on 2018/3/2 4 | import random 5 | 6 | from PIL import Image, ImageChops 7 | from numpy import array 8 | from selenium import webdriver 9 | from selenium.webdriver.common.by import By 10 | from selenium.webdriver.common.action_chains import ActionChains 11 | from selenium.webdriver.support.ui import WebDriverWait as Wait 12 | from selenium.webdriver.support import expected_conditions as Expect 13 | import requests, io, re 14 | import easing 15 | 16 | 17 | def convert_css_to_offset(px): 18 | ps = px.replace('px', '').split(' ') 19 | x = -int(ps[0]) 20 | y = -int(ps[1]) 21 | return x, y, x + 10, y + 58 22 | 23 | 24 | def convert_index_to_offset(index): 25 | row = int(index / 26) 26 | col = index % 26 27 | x = col * 10 28 | y = row * 58 29 | return x, y, x + 10, y + 58 30 | 31 | 32 | def get_slider_offset_from_diff_image(diff): 33 | im = array(diff) 34 | width, height = diff.size 35 | diff = [] 36 | for i in range(height): 37 | for j in range(width): 38 | # black is not only (0,0,0) 39 | if im[i, j, 0] > 15 or im[i, j, 1] > 15 or im[i, j, 1] > 15: 40 | diff.append(j) 41 | break 42 | return min(diff) 43 | 44 | 45 | def get_slider_offset(image_url, image_url_bg, css): 46 | image_file = io.BytesIO(requests.get(image_url).content) 47 | im = Image.open(image_file) 48 | image_file_bg = io.BytesIO(requests.get(image_url_bg).content) 49 | im_bg = Image.open(image_file_bg) 50 | # im.show() 51 | # im_bg.show() 52 | 53 | # 10*58 26/row => background image size = 260*116 54 | captcha = Image.new('RGB', (260, 116)) 55 | captcha_bg = Image.new('RGB', (260, 116)) 56 | for i, px in enumerate(css): 57 | offset = convert_css_to_offset(px) 58 | region = im.crop(offset) 59 | region_bg = im_bg.crop(offset) 60 | offset = convert_index_to_offset(i) 61 | captcha.paste(region, offset) 62 | captcha_bg.paste(region_bg, offset) 63 | diff = ImageChops.difference(captcha, captcha_bg) 64 | # captcha.show() 65 | # captcha_bg.show() 66 | # diff.show() 67 | diff.save('D:/diff.png') 68 | return get_slider_offset_from_diff_image(diff) 69 | 70 | 71 | def get_image_css(images): 72 | css = [] 73 | for image in images: 74 | position = get_image_position_from_style(image.get_attribute("style")) 75 | css.append(position) 76 | return css 77 | 78 | 79 | def get_image_url_from_style(style): 80 | match = re.match('background-image: url\("(.*?)"\); background-position: (.*?);', style) 81 | return match.group(1) 82 | 83 | 84 | def get_image_position_from_style(style): 85 | match = re.match('background-image: url\("(.*?)"\); background-position: (.*?);', style) 86 | return match.group(2) 87 | 88 | 89 | def get_slice_offset(slice): 90 | style = slice.get_attribute("style") 91 | match = re.search('background-image: url\("(.*?)"\);', style) 92 | url = match.group(1) 93 | image_file = io.BytesIO(requests.get(url).content) 94 | im = Image.open(image_file) 95 | im.save('D:/slice.png') 96 | return get_slider_offset_from_diff_image(im) 97 | 98 | 99 | # refer: https://ask.hellobi.com/blog/cuiqingcai/9796 100 | def get_track(distance): 101 | track = [] 102 | current = 0 103 | mid = distance * 4 / 5 104 | t = 0.2 105 | v = 0 106 | 107 | while current < distance: 108 | if current < mid: 109 | a = 2 110 | else: 111 | a = -3 112 | v0 = v 113 | v = v0 + a * t 114 | move = v0 * t + 1 / 2 * a * t * t 115 | current += move 116 | track.append(round(move)) 117 | return track 118 | 119 | 120 | def fake_drag(browser, knob, offset): 121 | # seconds = random.uniform(2, 6) 122 | # print(seconds) 123 | # samples = int(seconds*10) 124 | # diffs = sorted(random.sample(range(0, offset), samples-1)) 125 | # diffs.insert(0, 0) 126 | # diffs.append(offset) 127 | # ActionChains(browser).click_and_hold(knob).perform() 128 | # for i in range(samples): 129 | # ActionChains(browser).pause(seconds/samples).move_by_offset(diffs[i+1]-diffs[i], 0).perform() 130 | # ActionChains(browser).release().perform() 131 | 132 | # tracks = get_track(offset) 133 | offsets, tracks = easing.get_tracks(offset, 12, 'ease_out_expo') 134 | print(offsets) 135 | ActionChains(browser).click_and_hold(knob).perform() 136 | for x in tracks: 137 | ActionChains(browser).move_by_offset(x, 0).perform() 138 | ActionChains(browser).pause(0.5).release().perform() 139 | 140 | return 141 | 142 | 143 | def do_crack(browser): 144 | slice = browser.find_element_by_class_name("gt_slice") 145 | slice_offset = get_slice_offset(slice) 146 | print(slice_offset) 147 | 148 | images = browser.find_elements_by_class_name("gt_cut_fullbg_slice") 149 | images_bg = browser.find_elements_by_class_name("gt_cut_bg_slice") 150 | image_url = get_image_url_from_style(images[0].get_attribute("style")) 151 | image_url_bg = get_image_url_from_style(images_bg[0].get_attribute("style")) 152 | css = get_image_css(images) 153 | offset = get_slider_offset(image_url, image_url_bg, css) 154 | print(offset) 155 | 156 | knob = browser.find_element_by_class_name("gt_slider_knob") 157 | # ActionChains(browser).drag_and_drop_by_offset(knob, offset - slice_offset, 0).perform() 158 | fake_drag(browser, knob, offset - slice_offset) 159 | return 160 | 161 | chrome_options = webdriver.ChromeOptions() 162 | chrome_options.add_argument("--start-maximized") 163 | browser = webdriver.Chrome( 164 | executable_path="./drivers/chromedriver.exe", 165 | chrome_options=chrome_options 166 | ) 167 | browser.get('https://account.ch.com/NonRegistrations-Regist') 168 | Wait(browser, 60).until( 169 | Expect.visibility_of_element_located((By.CSS_SELECTOR, "div[data-target='account-login']")) 170 | ) 171 | email = browser.find_element_by_css_selector("div[data-target='account-login']") 172 | email.click() 173 | 174 | Wait(browser, 60).until( 175 | Expect.visibility_of_element_located((By.ID, "emailRegist")) 176 | ) 177 | register = browser.find_element_by_id("emailRegist") 178 | register.click() 179 | 180 | do_crack(browser) 181 | --------------------------------------------------------------------------------