Skip to content

Commit 49644df

Browse files
committed
- Added Cloudflare Challenge Page example
1 parent cf3948c commit 49644df

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import os
2+
import time
3+
import json
4+
import re
5+
from selenium import webdriver
6+
from selenium.webdriver.support.wait import WebDriverWait
7+
from selenium.webdriver.common.by import By
8+
from selenium.webdriver.support import expected_conditions as EC
9+
from selenium.webdriver.chrome.service import Service
10+
from selenium.webdriver.chrome.options import Options
11+
from twocaptcha import TwoCaptcha
12+
13+
14+
15+
# CONFIGURATION
16+
17+
url = "https://2captcha.com/demo/cloudflare-turnstile-challenge"
18+
apikey = os.getenv('APIKEY_2CAPTCHA')
19+
20+
21+
"""
22+
When a web page first loads, some JavaScript functions and objects (such as window.turnstile) may already be initialized
23+
and executed. If the interception script is launched too late, this may lead to the fact that the necessary parameters
24+
will already be lost, or the script simply will not have time to intercept the right moment. Refreshing the page ensures
25+
that everything starts from scratch and you trigger the interception at the right time.
26+
"""
27+
intercept_script = """
28+
console.clear = () => console.log('Console was cleared')
29+
const i = setInterval(()=>{
30+
if (window.turnstile)
31+
console.log('success!!')
32+
{clearInterval(i)
33+
window.turnstile.render = (a,b) => {
34+
let params = {
35+
sitekey: b.sitekey,
36+
pageurl: window.location.href,
37+
data: b.cData,
38+
pagedata: b.chlPageData,
39+
action: b.action,
40+
userAgent: navigator.userAgent,
41+
}
42+
console.log('intercepted-params:' + JSON.stringify(params))
43+
window.cfCallback = b.callback
44+
return }
45+
}
46+
},50)
47+
"""
48+
49+
# LOCATORS
50+
51+
success_message_locator = "//p[contains(@class,'successMessage')]"
52+
53+
54+
# GETTERS
55+
56+
def get_element(locator):
57+
"""Waits for an element to be clickable and returns it"""
58+
return WebDriverWait(browser, 30).until(EC.element_to_be_clickable((By.XPATH, locator)))
59+
60+
61+
# ACTIONS
62+
63+
def get_captcha_params(script):
64+
"""
65+
Refreshes the page, injects a JavaScript script to intercept Turnstile parameters, and retrieves them.
66+
67+
Args:
68+
script (str): The JavaScript code to be injected.
69+
70+
Returns:
71+
dict: The intercepted Turnstile parameters as a dictionary.
72+
"""
73+
browser.refresh() # Refresh the page to ensure the script is applied correctly
74+
75+
browser.execute_script(script) # Inject the interception script
76+
77+
time.sleep(5) # Allow some time for the script to execute
78+
79+
logs = browser.get_log("browser") # Retrieve the browser logs
80+
params = None
81+
for log in logs:
82+
if "intercepted-params:" in log['message']:
83+
log_entry = log['message'].encode('utf-8').decode('unicode_escape')
84+
match = re.search(r'intercepted-params:({.*?})', log_entry)
85+
if match:
86+
json_string = match.group(1)
87+
params = json.loads(json_string)
88+
break
89+
print("Parameters received")
90+
return params
91+
92+
def solver_captcha(apikey, params):
93+
"""
94+
Solves the Turnstile captcha using the 2Captcha service.
95+
96+
Args:
97+
apikey (str): The 2Captcha API key.
98+
params (dict): The intercepted Turnstile parameters.
99+
100+
Returns:
101+
str: The solved captcha token.
102+
"""
103+
solver = TwoCaptcha(apikey)
104+
try:
105+
result = solver.turnstile(sitekey=params["sitekey"],
106+
url=params["pageurl"],
107+
action=params["action"],
108+
data=params["data"],
109+
pagedata=params["pagedata"],
110+
useragent=params["userAgent"])
111+
print(f"Captcha solved")
112+
return result['code']
113+
except Exception as e:
114+
print(f"An error occurred: {e}")
115+
return None
116+
117+
def send_token_callback(token):
118+
"""
119+
Executes the callback function with the given token.
120+
121+
Args:
122+
token (str): The solved captcha token.
123+
"""
124+
script = f"cfCallback('{token}')"
125+
browser.execute_script(script)
126+
print("The token is sent to the callback function")
127+
128+
def final_message(locator):
129+
"""
130+
Retrieves and prints the final success message.
131+
132+
Args:
133+
locator (str): The XPath locator of the success message.
134+
"""
135+
message = get_element(locator).text
136+
print(message)
137+
138+
139+
# MAIN LOGIC
140+
141+
chrome_options = Options()
142+
chrome_options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
143+
"Chrome/126.0.0.0 Safari/537.36")
144+
# Set logging preferences to capture only console logs
145+
chrome_options.set_capability("goog:loggingPrefs", {"browser": "INFO"})
146+
147+
with webdriver.Chrome(service=Service(), options=chrome_options) as browser:
148+
browser.get(url)
149+
print("Started")
150+
151+
params = get_captcha_params(intercept_script)
152+
153+
if params:
154+
token = solver_captcha(apikey, params)
155+
156+
if token:
157+
send_token_callback(token)
158+
final_message(success_message_locator)
159+
time.sleep(5)
160+
print("Finished")
161+
else:
162+
print("Failed to solve captcha")
163+
else:
164+
print("Failed to intercept parameters")

0 commit comments

Comments
 (0)