1
+ from selenium import webdriver
2
+ from selenium .webdriver .common .by import By
3
+ from selenium .webdriver .support .wait import WebDriverWait
4
+ from selenium .webdriver .support import expected_conditions as EC
5
+ from selenium .webdriver .common .action_chains import ActionChains
6
+ import os
7
+ from twocaptcha import TwoCaptcha
8
+
9
+
10
+ # CONFIGURATION
11
+
12
+ url = "https://2captcha.com/demo/clickcaptcha"
13
+ apikey = os .getenv ('APIKEY_2CAPTCHA' )
14
+
15
+
16
+ # LOCATORS
17
+
18
+ img_locator_captcha_for_get = "._widgetForm_1f3oo_26 img"
19
+ img_locator_captcha_for_click = "//div[@class='_widget_s7q0j_5']//img"
20
+ submit_button_captcha_locator = "//button[@type='submit']"
21
+ success_message_locator = "//p[@class='_successMessage_s7q0j_1']"
22
+
23
+
24
+ # GETTERS
25
+
26
+ def get_element (locator ):
27
+ """Waits for an element to be clickable and returns it"""
28
+ return WebDriverWait (browser , 30 ).until (EC .element_to_be_clickable ((By .XPATH , locator )))
29
+
30
+
31
+ # ACTIONS
32
+
33
+ def solver_captcha (image , apikey ):
34
+ """
35
+ Solves a captcha using the 2Captcha service and returns the solution code
36
+
37
+ Args:
38
+ image (str): Path to the captcha image
39
+ apikey (str): API key to access the 2Captcha service
40
+ Returns:
41
+ str: Captcha solution code, if successful, otherwise None
42
+ """
43
+ solver = TwoCaptcha (apikey )
44
+ try :
45
+ result = solver .coordinates (image )
46
+ print (f"Captcha solved. Coordinates received" )
47
+ return result ['code' ]
48
+ except Exception as e :
49
+ print (f"An error occurred: { e } " )
50
+ return None
51
+
52
+ def get_image_canvas (locator ):
53
+ """
54
+ Gets the Base64 representation of an image displayed on a web page using canvas
55
+
56
+ Args:
57
+ locator (str): CSS selector for locating an image on a page
58
+ Returns:
59
+ str: Base64 image string
60
+ """
61
+
62
+ # JavaScript code to create a canvas, draw an image to the canvas and get its Base64 representation
63
+ canvas_script = """
64
+ function getBase64Image(imgElement) {
65
+ let canvas = document.createElement('canvas');
66
+ canvas.width = imgElement.width;
67
+ canvas.height = imgElement.height;
68
+ let ctx = canvas.getContext('2d');
69
+ ctx.drawImage(imgElement, 0, 0);
70
+ let base64Image = canvas.toDataURL();
71
+ return base64Image;
72
+ }
73
+ return getBase64Image(document.querySelector(arguments[0]));
74
+ """
75
+ base63_image = browser .execute_script (canvas_script , locator )
76
+ return base63_image
77
+
78
+ def pars_coordinates (answer_to_captcha ):
79
+ """
80
+ Parses the coordinates from the captcha solution string.
81
+
82
+ Args:
83
+ answer_to_captcha (str): Captcha solution string containing coordinates.
84
+ Returns:
85
+ list: List of dictionaries with 'x' and 'y' coordinates.
86
+ """
87
+ # We remove the "coordinates:" prefix and split the line at the ";" symbol.
88
+ coordinate_pairs = answer_to_captcha .replace ("coordinates:" , "" ).split (";" )
89
+ # Creating a list of dictionaries
90
+ coordinates_list = []
91
+
92
+ for pair in coordinate_pairs :
93
+ # We split each pair of coordinates by a comma and then by the "=" sign.
94
+ coords = pair .split ("," )
95
+ coord_dict = {
96
+ "x" : int (coords [0 ].split ("=" )[1 ]),
97
+ "y" : int (coords [1 ].split ("=" )[1 ])
98
+ }
99
+ coordinates_list .append (coord_dict )
100
+
101
+ print ("The received response is converted into a list of coordinates" )
102
+ return coordinates_list
103
+
104
+ def clicks_on_coordinates (coordinates_list , img_locator_captcha ):
105
+ """
106
+ Clicks on the specified coordinates within the image element using ActionChains.
107
+
108
+ Args:
109
+ coordinates_list (list): List of dictionaries with 'x' and 'y' coordinates.
110
+ img_locator_captcha (str): XPath locator of the image element.
111
+ """
112
+ action = ActionChains (browser )
113
+
114
+ img_element = get_element (img_locator_captcha )
115
+
116
+ # Getting the initial coordinates of the image element
117
+ location = img_element .location
118
+ img_x = location ['x' ]
119
+ img_y = location ['y' ]
120
+
121
+ for coord in coordinates_list :
122
+
123
+ # Calculate absolute coordinates on the page
124
+ x_offset = img_x + coord ['x' ]
125
+ y_offset = img_y + coord ['y' ]
126
+
127
+ # Click on the calculated coordinates
128
+ action .move_by_offset (x_offset , y_offset ).click ().perform ()
129
+
130
+ # We return the cursor back so as not to move the next clicks
131
+ action .move_by_offset (- x_offset , - y_offset )
132
+
133
+ print ('The coordinates are marked on the image' )
134
+
135
+ def click_check_button (locator ):
136
+ """
137
+ Clicks the check button on a web page
138
+ Args:
139
+ locator (str): XPATH locator of the captcha verification button
140
+ """
141
+ button = get_element (locator )
142
+ button .click ()
143
+ print ("Pressed the Check button" )
144
+
145
+ def final_message (locator ):
146
+ """
147
+ Retrieves and prints the final success message.
148
+
149
+ Args:
150
+ locator (str): The XPath locator of the success message.
151
+ """
152
+ message = get_element (locator ).text
153
+ print (message )
154
+
155
+ # MAIN LOGIC
156
+
157
+ # Automatically closes the browser after block execution completes
158
+ with webdriver .Chrome () as browser :
159
+ # Go to page with captcha
160
+ browser .get (url )
161
+ print ("Started" )
162
+
163
+ # Getting captcha image in base64 format
164
+ image_base64 = get_image_canvas (img_locator_captcha_for_get )
165
+
166
+ answer_to_captcha = solver_captcha (image_base64 , apikey )
167
+
168
+ if answer_to_captcha :
169
+
170
+ coordinates_list = pars_coordinates (answer_to_captcha )
171
+
172
+ clicks_on_coordinates (coordinates_list , img_locator_captcha_for_click )
173
+
174
+ click_check_button (submit_button_captcha_locator )
175
+
176
+ final_message (success_message_locator )
177
+
178
+ browser .implicitly_wait (5 )
179
+ print ("Finished" )
180
+ else :
181
+ print ("Failed to solve captcha" )
0 commit comments