cloudflare_bypass_for_scraping.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import time
  2. from DrissionPage import ChromiumPage
  3. class CloudflareBypasser:
  4. def __init__(self, driver: ChromiumPage, log=True):
  5. self.driver = driver
  6. self.log = log
  7. def log_message(self, message):
  8. if self.log:
  9. print(message)
  10. def search_recursively_shadow_root_with_iframe(self, ele, depth=0, max_depth=3):
  11. if depth > max_depth:
  12. self.log_message(f"Max depth {max_depth} reached during iframe search.")
  13. return None
  14. try:
  15. if ele.shadow_root:
  16. child = ele.shadow_root.child()
  17. if child and child.tag == "iframe":
  18. return child
  19. else:
  20. for child in ele.children():
  21. result = self.search_recursively_shadow_root_with_iframe(child, depth + 1, max_depth)
  22. if result:
  23. return result
  24. except Exception as e:
  25. pass
  26. return None
  27. def search_recursively_shadow_root_with_cf_input(self,ele):
  28. if ele.shadow_root:
  29. if ele.shadow_root.ele("tag:input"):
  30. return ele.shadow_root.ele("tag:input")
  31. else:
  32. for child in ele.children():
  33. result = self.search_recursively_shadow_root_with_cf_input(child)
  34. if result:
  35. return result
  36. return None
  37. def locate_cf_button(self, dfs=False):
  38. try:
  39. button = None
  40. eles = self.driver.eles("tag:input")
  41. for ele in eles:
  42. attrs = ele.attrs
  43. if "name" in attrs and "type" in attrs:
  44. if "turnstile" in attrs["name"] and attrs["type"] == "hidden":
  45. if ele.parent() and ele.parent().shadow_root:
  46. button = ele.parent().shadow_root.child()("tag:body").shadow_root("tag:input")
  47. break
  48. if button:
  49. return button
  50. else:
  51. if dfs:
  52. self.log_message("Basic search failed. Searching for button recursively.")
  53. ele = self.driver.ele("tag:body")
  54. iframe = self.search_recursively_shadow_root_with_iframe(ele)
  55. if iframe:
  56. return self.search_recursively_shadow_root_with_cf_input(iframe("tag:body"))
  57. else:
  58. self.log_message("Iframe not found. Button search failed.")
  59. return None
  60. except Exception as e:
  61. self.log_message(f"Error locating verification button: {e}")
  62. return None
  63. def click_verification_button(self, is_dfs):
  64. try:
  65. button = self.locate_cf_button(dfs=is_dfs)
  66. if button:
  67. self.log_message("Verification button found. Attempting to click.")
  68. if button.states.is_displayed and button.states.is_enabled:
  69. button.click()
  70. time.sleep(1)
  71. else:
  72. self.log_message("Button is not clickable.")
  73. else:
  74. self.log_message("Verification button not found.")
  75. except Exception as e:
  76. self.log_message(f"Error clicking verification button: {e}")
  77. def is_bypassed(self):
  78. try:
  79. title = self.driver.title.lower()
  80. return "just a moment" not in title and "请稍候" not in title
  81. except Exception as e:
  82. self.log_message(f"Error checking page title: {e}")
  83. return False
  84. def bypass(self, max_retry=5):
  85. for i in range(max_retry):
  86. if self.is_bypassed():
  87. return True
  88. self.log_message(f"Verification page detected. Trying to bypass times={i}...")
  89. self.click_verification_button(False)
  90. time.sleep(2)
  91. return self.is_bypassed()
  92. def handle_waiting_room(self):
  93. wait_start = time.time()
  94. while True:
  95. try:
  96. html = self.driver.html.lower()
  97. if "cloudflare" not in html:
  98. break
  99. if "file d'attente" in html or "waiting room" in html:
  100. if time.time() - wait_start > 60 * 60:
  101. self.log_message("Waiting room timeout (1h).")
  102. break
  103. self.log_message("In Waiting Room... Waiting for auto-refresh.")
  104. time.sleep(10)
  105. else:
  106. break
  107. except Exception as e:
  108. self.log_message(f"Error checking html: {e}")