эмуляция браузера на php
How can I emulate a get request exactly like a web browser?
There are websites that when I open specific ajax request on browser, I get the resulted page. But when I try to load them with curl, I receive an error from the server.
How can I properly emulate a get request to the server that will simulate a browser?
That is what I am doing:
2 Answers 2
Are you sure the curl module honors ini_set(‘user_agent’. )? There is an option CURLOPT_USERAGENT described at http://docs.php.net/function.curl-setopt.
Could there also be a cookie tested by the server? That you can handle by using CURLOPT_COOKIE, CURLOPT_COOKIEFILE and/or CURLOPT_COOKIEJAR.
edit: Since the request uses https there might also be error in verifying the certificate, see CURLOPT_SSL_VERIFYPEER.
now hitting http://127.0.0.1:9999 in firefox, i get:
now let us compare that with this simple script:
there are several missing headers here, they can all be added with the CURLOPT_HTTPHEADER option of curl_setopt, but the User-Agent specifically should be set with CURLOPT_USERAGENT instead (it will be persistent across multiple calls to curl_exec() and if you use CURLOPT_FOLLOWLOCATION then it will persist across http redirections as well), and the Accept-Encoding header should be set with CURLOPT_ENCODING instead (if they’re set with CURLOPT_ENCODING then curl will automatically decompress the response if the server choose to compress it, but if you set it via CURLOPT_HTTPHEADER then you must manually detect and decompress the content yourself, which is a pain in the ass and completely unnecessary, generally speaking) so adding those we get:
now running that code, our netcat server gets:
and voila! our php-emulated browser GET request should now be indistinguishable from the real firefox GET request 🙂
this next part is just nitpicking, but if you look very closely, you’ll see that the headers are stacked in the wrong order, firefox put the Accept-Encoding header in line 6, and our emulated GET request puts it in line 3.. to fix this, we can manually put the Accept-Encoding header in the right line,
running that, our netcat server gets:
problem solved, now the headers is even in the correct order, and the request seems to be COMPLETELY INDISTINGUISHABLE from the real firefox request 🙂 (i don’t actually recommend this last step, it’s a maintenance burden to keep CURLOPT_ENCODING in sync with the custom Accept-Encoding header, and i’ve never experienced a situation where the order of the headers are significant)
Пишем бота регистрации аккаунта на PHP, эмулируя AJAX-запросы на CURL
Пока вышла горячая статейка с основными приёмами при работе с cURL в PHP, я решил написать скрипт простого бота, работающего с AJAX, чтобы закрепить материал на реальном примере. В этой статье будут упускаться многие очевидные вещи, эта статья будет более ориентирована на демонстрацию подхода при написании ботов для любого сайта. Я, для текущего примера решил выбрать сайт webparse.ru, для которого мы напишем скрипт заполнения почты и регистрации нового аккаунта.
Забегу наперёд, и скажу, что для написания бота для этого сайта, необходимо будет эмулировать AJAX запросы из PHP, и обрабатывать JSON ответ от сервера.
Перед тем, как приступить к изучению этой статьи, советую сначала разобраться с основами PHP cURL, и основыми функциями по работе с ним. После чего, продолжите изучение этой.
Потому, для начала, переходим по ссылке webparse.ru, и сразу видим форму с вводом email адреса для регистрации:
Для того, чтобы понять, какие параметры нужно отправлять, и на какой URL-адрес, нужно:
И после клика по кнопке регистрации, будет отправлен AJAX-запрос, который мы увидим в открытой панеле. И уже из информации на этой панеле, мы можем изучить все данные, которые нам необходимо будет сэмулировать PHP-скриптом.
Однако, здесь есть один тонкий момент. Для того, чтобы полностью сэмулировать работу браузера, реального пользователя, нужно передать так же заголовки, которые помогут нам не выдать себя за бота.
Я выделил основные заголовки, которые в большей мере котируются сервером, которые желательно отправлять. Сейчас, кратко рассмотрим их назначение:
Теперь, когда мы изучили основные параметры для написания собственного бота, объединим всю полученную информацию, и напишем скрипт на PHP.
И вот, что мы имеем при успешном запросе:
Получив всю нужную информацию, напишем скрипт, который будет отправлять данные, полученные в шаге 1, и обрабатывая ответ, исходя из изученного примера во втором шаге.
В результате чего, выполнив написанный скрипт, регистрация будет выполнена успешно, и на указанную почту будет отправлена ссылка для входа в личный кабинет.
Резюме
Subscribe to Блог php программиста: статьи по PHP, JavaScript, MySql
Get the latest posts delivered right to your inbox
Эмуляция браузера на PHP
Добра, ЛОР. Подскажите, пожалуйста, как можно эмулировать браузер на PHP.
Или есть какие-либо другие методы для того, чтобы Яндекс не ругался на бота?
Искать по запросу headless browser.
Парсишь поисковую выдачу? Браузер не поможет.
И это никак не обойти? Задержку какую-нибудь добавить, имитацию пользователя?
This. Посмотри, какие запросы делает браузер к Яндексу, имитируй их на пыхе.
Задержку какую-нибудь добавить, имитацию пользователя
Ты много знаешь пользователей, которые сутками сидят и долбят поиск?
но, скорее всего, платно
На пхп не знаю, но настоятельно советую puppeteer. Ты в джаваскрипт умеешь? Если да, то это идеальный вариант. Но тебя всё равно вычислят и набьют еб.
А разве такое вообще бывает? Кое-что, к примеру DOM, можно строить и изменять с помощью соответствующих либ(их иногда для сложных случаев парсинга юзают), но полностью эмулировать браузер на php не реально. Тут вам нужен Headless Chrome c remote-debugging, Selenium, phantomjs или что-то вроде того.
Нет такого нормального, все написано для node.js
Премного благодарю за инструмент. Немного прочитал и это мощно. Будем пытаться завести
В любом случае вы придёте к тому, что после N запросов будет каптча тупо потому что живой человек обычно не делает 24/7 монотонно запросы. Так что либо периодически менять IP (со сбросом кук, разумеется), либо подключать сервисы платного разгадывания каптчи (на них тысячи индусов за копейки в прямом смысле разгадывают каптчи, которые ты им суёшь через API). Либо и то, и другое.
Парсинг 24/7 не нужен. Он всего лишь должен будет единожды собирать данные по указанным ключам
Спасибо за ссылку, интересный проект этот Puppeteer. Нужно будет пощупать его в деле как нибудь.
если для тестов, то ничего нет лучше cypress. а то, просто запускается браузер без графического интерфейса headless, запускается веб-сокет сервер и безголовому браузеру отдаем приказы по веб-сокетам. есть еще питоновская версия (требует опыта работы с asyncio), но на js кошернее
Эмуляция браузера на серверной стороне
Ситуация следующая: У меня есть веб-форма которую заполняет пользователь(к примеру логин и емейл). Эти данные отправляются на десяток других левых форм курлом. Беда в том, что другие формы периодически меняются(добавляются поля, в том числе скрытые, меняются пути к экшенам форм и т.д.). Причем логика работы этих форм описана на js.
Если такое происходит, то логику отправки данных на данную форму приходится полностью переписывать, т.е. включать сниффер и смотреть что изменилось. На исправление уходит как правило пара дней, поскольку приходится гадать на кофейной гуще. Форм много, поэтому все время уходит на поддержку всей этой беды.
Собственно, нужна эмуляция браузера на стороне сервера. Если меняются пути, скрытые поля и т.д., то это никак не должно повлиять на отправку данных.
Я даже не знаю по какому запросу гуглить и какие инструменты для этого подойдут. Может кто-то решал подобную задачу и может помочь?
2 ответа 2
Как то пару лет назад пытался сделать автоматизированую систему постинга обьявлений на доски. Тоже столкнулся с проблемой изменения количества полей в форме и имён. С статическими формами (которые сразу выдаются в браузер) вопрос решался просто. php код брал кусок html кода между тегами и с помощью регулярок выискивал все поля. Сравнивал список найденых полей (тип,имя) со списком в БД. Если находились несоответствия отправка данных не производилась и мне приходило уведомление какие поля в форме на каком именно сайте изменились. Внесение изменений в код отправки занимало от нескольких минут до получаса максимум, так как знал что и где искать. С формами в которые подгружались поля через js с динамическим добавлением новых полей было сложнее. Начал рыть в сторону node.js, так как этот фреймворк может выполнятся на стороне сервера. Но нагрузили по основной работе и проект забросил.
Управляем браузером с помощью PHP и Selenium
Интро
Всем привет! Сегодня я расскажу вам о том, как с помощью PHP можно работать с Selenium.
Чаще всего это бывает необходимо, когда перед вами стоит задача написать автотесты для web интерфейса или свой парсер/краулер.
Мы рассмотрим следующие нюансы:
1. Готовим Behat и Mink
Behat это php фреймворк, который изначально был создан для поведенческого тестирования (BDD). Он является официальной PHP реализацией более известного продукта Cucumber, который часто используется в других языках программирования.
Сам по себе работать с Selenium он не умеет и предназначен больше для написания функциональных тестов без использования браузера.
Устанавливается как обычный пакет:
Чтобы научить behat работать с браузером, нам понадобится его расширение Mink, а также бридж для работы с конкретным вендором (в нашем случае это Selenium). Полный список вендоров вы сможете найти на страничке Mink. С учетом версий, ваш composer.json должен выглядеть примерно так:
Завершающей фазой является конфигурация
Файлы сценариев или (*.feature файлы) — yml файлы, написанные на псевдо-языке Gherkin, содержат, по сути, набор пошаговых инструкций, которые выполнит ваш браузер в ходе исполнения конкретного сьюта. Подробнее о синтаксисе вы можете узнать, перейдя по ссылке выше.
Каждая такая «инструкция» в свою очередь матчится на методы класса «контекста» с помощью регулярных выражений, указанных в аннотациях класса. Behat\MinkExtension\Context\MinkContext
Имена самих методов роли не играют, хотя хорошим тоном будет придерживаться аналогичного аннотациям именования в CamelCase.
Если вам не хватает доступных по умолчанию конструкций Gherkin, вы можете расширить функционал в классах наследниках MinkContext правильно указав аннотации. Эту роль и выполняют «контекстные» классы.
2. Установка и настройка окружения
Запуск Selenium в Docker немного сложнее. Во-первых вам понадобятся Иксы в контейнере, во-вторых – вам захочется увидеть, что же происходит внутри контейнера.
Ребята из Selenium уже обо всём позаботились и собирать свой контейнер вам не придется. Контейнер со Standalone сервером на борту будет сразу доступен по 5900 порту, куда можно постучаться с любого VNC клиента (например с этого). Внутри контейнера вас встретит приветливый интерфейс Fluxbox с предустановленным Chrome. В моем случае это выглядит так:
Чтобы прийти к успеху, вы можете запустить докер контейнер, согласно инструкции на сайте:
Важный момент, без шаред волюма /dev/shm хрому не хватит памяти и он не сможет запуститься, поэтому не забываем его указать.
В моем случае используется docker-compose, и YAML файл будет выглядеть следующим образом:
Я хочу, чтобы мои тесты заходили на Facebook через VPN, включенный на хост-машине, поэтому важно указать network_mode.
Чтобы запустить контейнер, используя compose, выполним следующую команду:
Теперь пробуем подсоединиться по VNC на localhost:5900 и открыть браузер внутри контейнера. Если вам это удалось и вы видите что-то похожее на скриншот выше — вы прошли этот уровень.
3. От теории к практике. Автоматизируем
В примере, приведенном ниже, я буду доставать всех пользователей Facebook по переданным фамилии и имени. Сценарий будет выглядеть следующим образом:
И соответственно Context класс (констуктор и нэймспейсы опущены)
Часто возникает необходимость в кастомных методах типа FacebookContext::pressFacebookButton, т.к по умолчанию все селекторы в mink умеют искать только по name|value|id|alt|title.
Если вам нужна выборка по другому атрибуту, придется писать свой метод. Кнопка Login у фейсбука имеет атрибут id, но меняет его значение периодически по какой-то своей логике. Поэтому мне и пришлось перепривязаться к data-testid, который, пока что, остается статичным.
Теперь, чтобы всё это завелось, необходимо убедиться, что Selenium запущен и слушает указанный порт.
После чего выполним:
Внутри контейнера должен запуститься инстанс браузера и пойти выполнять указанные инструкции.
4. Кастомизация behat. Расширения
В Behat фреймворк встроен прекрасный механизм расширения через behat.yml. Обратите внимание, что многие классы фреймворка объявлены как final, чтобы умерить соблазн просто их наследовать.
Расширение позволяет дополнять функционал behat, объявлять новые консольные аргументы и опции, модифицировать поведение других расширений и др. Оно состоит из класса имплементирующего
Behat\Testwork\ServiceContainer\Extension интерфейс (он же указывается в behat.yml) и вспомогательных классов, если нужно.
Я хочу научить behat принимать ФИО искомого человека через новый входящий аргумент —search-by-fullname, чтобы в последствие использовать эти данные внутри сьюта.
Ниже привожу код, выполняющий необходимые операции:
В методе SearchExntesion::load пробрасывается Сервис SearchController, отвечающий непосредственно за объявление параметров и их прием/обработку.
Если всё объявлено правильно, то список доступных команд behat дополнится новым аргументом —search-by-fullname:
Получив входные данные внутри SearchController, они могут быть переданы в Context классы напрямую, либо сохранены в базе данных и т.д В примере выше я для этого использую Registry паттерн. Подход вполне рабочий, но если вы знаете, как это сделать по-другому, пожалуйста, расскажите в комментариях.