В чем разница в доступе к веб-сайту Cloudflare с помощью ChromeDriver/Chrome в обычном / безголовом режиме через Selenium Python
У меня есть вопрос о --headless
режим в Python Selenium для Chrome.
Код
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
CHROME_DRIVER_DIR = "selenium/chromedriver"
chrome_options = webdriver.ChromeOptions()
caps = DesiredCapabilities().CHROME
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--remote-debugging-port=9222")
chrome_options.add_argument("--headless") # Runs Chrome in headless mode.
chrome_options.add_argument('--no-sandbox') # # Bypass OS security model
chrome_options.add_argument("--disable-extensions")
chrome_options.add_argument("--disable-gpu")
browser = webdriver.Chrome(desired_capabilities=caps, executable_path=CHROME_DRIVER_DIR, options=chrome_options)
browser.get("https://www.manta.com/c/mm2956g/mashuda-contractors")
print(browser.page_source)
browser.quit()
Когда я удаляю chrome_options.add_argument("--headless")
все работает хорошо, но с этим --headless*
получил следующий выпуск
Please enable cookies.
Error 1020 Ray ID: 53fd62b4087d8116 • 2019-12-04 11:19:28 UTC
Access denied
What happened?
This website is using a security service to protect itself from online attacks.
Cloudflare Ray ID: 53fd62b4087d8116 • Your IP: 168.81.117.111 • Performance & security by Cloudflare
В чем разница для нормального режима и --headless
?
5 ответов
Я взял ваш код, удалил необязательные аргументы и добавил несколько аргументов для выполнения теста следующим образом:
Блок кода:
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC options = webdriver.ChromeOptions() options.add_argument("start-maximized") options.add_argument("--headless") options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('useAutomationExtension', False) driver = webdriver.Chrome(options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe') driver.get("https://www.manta.com/c/mm2956g/mashuda-contractors") print(driver.page_source) driver.quit()
Консольный вывод:
<html class="js" lang="en-US" style="opacity: 1; visibility: visible;"><!--<![endif]--><head> <title>Access denied | www.manta.com used Cloudflare to restrict access</title> <meta charset="UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <meta name="robots" content="noindex, nofollow"> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"> <link rel="stylesheet" id="cf_styles-css" href="/cdn-cgi/styles/cf.errors.css" type="text/css" media="screen,projection"> <!--[if lt IE 9]><link rel="stylesheet" id='cf_styles-ie-css' href="/cdn-cgi/styles/cf.errors.ie.css" type="text/css" media="screen,projection" /><![endif]--> <style type="text/css">body{margin:0;padding:0}</style> <!--[if gte IE 10]><!--><script type="text/javascript" src="/cdn-cgi/scripts/zepto.min.js"></script><!--<![endif]--> <!--[if gte IE 10]><!--><script type="text/javascript" src="/cdn-cgi/scripts/cf.common.js"></script><!--<![endif]--> </head> <body> <div id="cf-wrapper"> <div class="cf-alert cf-alert-error cf-cookie-error" id="cookie-alert" data-translate="enable_cookies">Please enable cookies.</div> <div id="cf-error-details" class="cf-error-details-wrapper"> <div class="cf-wrapper cf-header cf-error-overview"> <h1> <span class="cf-error-type" data-translate="error">Error</span> <span class="cf-error-code">1020</span> <small class="heading-ray-id">Ray ID: 53fd7c2fca12d5fc • 2019-12-04 11:36:52 UTC</small> </h1> <h2 class="cf-subheadline">Access denied</h2> </div><!-- /.header --> <section></section><!-- spacer --> <div class="cf-section cf-wrapper"> <div class="cf-columns two"> <div class="cf-column"> <h2 data-translate="what_happened">What happened?</h2> <p>This website is using a security service to protect itself from online attacks.</p> </div> </div> </div><!-- /.section --> <div class="cf-error-footer cf-wrapper"> <p> <span class="cf-footer-item">Cloudflare Ray ID: <strong>53fd7c2fca12d5fc</strong></span> <span class="cf-footer-separator">•</span> <span class="cf-footer-item"><span>Your IP</span>: 123.201.54.43</span> <span class="cf-footer-separator">•</span> <span class="cf-footer-item"><span>Performance & security by</span> <a href="https://www.cloudflare.com/5xx-error-landing?utm_source=error_footer" id="brand_link" target="_blank">Cloudflare</a></span> </p> </div><!-- /.error-footer --> </div><!-- /#cf-error-details --> </div><!-- /#cf-wrapper --> <script type="text/javascript"> window._cf_translation = {}; </script> </body></html>
Анализ
Из извлеченного источника страницы довольно ясно, используя --headless
аргумент, который вы переходите на страницу с:
- Заголовок: Доступ запрещен | www.manta.com использовал Cloudflare для ограничения доступа.
- Некоторая информация: Что случилось?: Этот веб-сайт использует службу безопасности для защиты от сетевых атак.
Вывод
Просмотр контекст т.е. браузера Chrome сессии становится детектируются как СЭП и навигация блокируется.
Outro
Вы можете найти пару соответствующих обсуждений в:
Это HTTP
User-Agent
заголовок, который не нравится Cloudflare.
Чтобы обойти эту проблему, просто измените свой
user-agent
вариант chrome (код ниже для Selenium в Python):
option.add_argument('--headless')
option.add_argument("user-agent=Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36")
Я тестировал этот серверный скрипт:
<?php
echo "<pre><code>";
var_dump($_SERVER);
echo "</code></pre>";
?>
<script>
var el = document.getElementsByTagName('code')[0];
for(var prop in window.navigator){
var str = JSON.stringify(window.navigator[prop])
el.innerHTML = el.innerHTML + "window.navigator." + prop + " = " + str + "\n";
}
var skip_props = ['parent', 'top', 'frames', 'self', 'window'];
for(var prop in window){
if (skip_props.indexOf(prop) > -1) { continue; }
el.innerHTML = el.innerHTML + "window." + prop + " = ";
var str = JSON.stringify(window[prop])
el.innerHTML = el.innerHTML + str + "\n";
}
</script>
Я загрузил эту страницу с помощью ChromeDriver, с использованием и без использования --headless
, и распечатал результат, используя print(driver.find_element_by_tag_name('code').text)
. Затем я сравнил оба выхода.
Вот отличия, которые я обнаружил:
- HTTP
Accept-Language
заголовок:en-US,en;q=0.9
противen-US
- HTTP
User-Agent
заголовок:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36
противMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/83.0.4103.61 Safari/537.36
(Обратите вниманиеHeadlessChrome
упоминание во второй строке.) - Javascript
window.navigator.plugins
:{"0":{"0":{}},"1":{"0":{}},"2":{"0":{},"1":{}}}
против{}
- Javascript
window.navigator.mimeTypes
:{"0":{},"1":{},"2":{},"3":{}}
против{}
- Javascript
window.outerWidth
:1367
против0
- Javascript
window.outerHeight
:641
против0
Обратите внимание: в опубликованном вами скрипте Python вам не хватает нескольких строк, чтобы удалить window.webdriver
свойство (без этого сервер может легко определить, что вы используете WebDriver) [ ref]:
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""
})
Cloudflare нацелен на блокировку ботов. Они предполагают, что браузер без головы используется парсерами данных, поэтому они его блокируют. от Cloudflare Что такое парсинг данных?
* Headless-браузер - это тип веб-браузера, очень похожий на Chrome или Firefox, но у него по умолчанию нет визуального пользовательского интерфейса, что позволяет ему работать намного быстрее, чем обычный веб-браузер. По сути, работая на уровне командной строки, безголовый браузер может избежать рендеринга целых веб-приложений. Сканеры данных пишут ботов, которые используют безголовые браузеры для более быстрого запроса данных, поскольку никто не просматривает каждую очищаемую страницу.
При парсинге защищенного CloudFlare веб-сайта вот список вещей, которые вам нужно сделать:
- Убедитесь, что вы отправляете заголовки, идентичные (и в том же порядке) тому, что отправляет браузер
- Убедитесь, что вы используете диапазон IP-адресов, не относящихся к центру обработки данных.
- А если все равно не получится, как в моем случае...
Я столкнулся с той же проблемой при очистке одного веб-сайта электронной коммерции (предположим, точка com). Изменение порядка заголовков не помогло мне. Мои выводы: судя по всему, CloudFlare анализирует TLS-отпечаток запроса и выдает код 403 (1020), если отпечаток совпадает с node.js/python/curl, которые обычно используются для парсинга. Решение состоит в том, чтобы эмулировать отпечаток пальца какого-нибудь популярного браузера, и наиболее очевидным способом будет использование Puppeteer.js с дополнительным скрытым плагином puppeteer. И это сработало! Но.. поскольку Puppeteer был недостаточно быстрым для моего варианта использования (мягко говоря..https://rapidapi.com/restyler/api/scrapeninja
Узнайте больше о том, как CloudFlare анализирует TLS:https://blog.cloudflare.com/monsters-in-the-middleboxes/