Гугл рекапча (reCaptcha v2) перестала быть проблемой для наших пользователей. Мы внедрили интеграцию с популярным сервисов по обходу капчи Death By Captcha и теперь ваши скраперы могут легко обходить самые современные капчи.
Давайте посмотрим, как выглядит reCaptcha v2:
Если вы видите именно такую капчу на сайте. который вам нужно отпарсить, то эта статья вам обязательно поможет. Мы постараемя дать вам исчерпывающее руководство на реальном примере, так, чтобы вы смогли легко внедрить подобное решение для вашего сайта. Мы же будем парсить следующий сайт: http://www.receita.fazenda.gov.br/PessoaJuridica/CNPJ/cnpjreva/Cnpjreva_Solicitacao2.asp.
Для того, чтобы пользовать этим функционалом вам нужно иметь собственный аккаунт в службе Death by Captcha. Их услуги не бесплатны, стоимость решения 100 капч составляет примерно 2.89$ (цена актуальна на 28.02.2018).
Решение капчи происходит автоматически, вам нужно лишь загрузить страницу с капчей в ваш скрапер и вызвать специальную команду captcha_resolve с определенными параметрами:
prodiver: провайдер решений для капчи, нужно установить значение deathbycaptcha.com
type: тип капчи, нужно установить значение nocaptchav2
username: имя пользователя вашего аккаунта в системе death by captcha
password: пароль вашего аккаунта в системе death by captcha
ВНИМАНИЕ!!! Для того чтобы капча этого типа была успешно решена, люди, которые будут вручную решать вашу капчу должны будут это делать под тем же IP адресом, что использует ваш парсер. Поэтому, единственный вариант этого достичь — использовать ВАШ СОБСТВЕННЫЙ ПРОКСИ СЕРВЕР в конфигурации вашего диггера. Наши штатные прокси сервера не могут быть доступны с IP адресов, вне нашей основной сети, поэтому штатные прокси просто не будут работать в этом случае. В дальнейшем мы внедрим специальный пул прокси серверов для этой задачи, но пока вы должны будете использовать свой прокси.
Базовый код нашего парсера будет таким:
---
config:
debug: 2
agent: Firefox
proxy: ВАШ ПРОКСИ НУЖНО ВСТАВИТЬ СЮДА
do:
# Мы будем повторять неудавшийся запрос, поэтому пропишем значение переменной,
# которую будет использовать опция repeat
- variable_set:
field: repeat
value: "yes"
# Загружаем страницу с капчей
- walk:
to: http://www.receita.fazenda.gov.br/PessoaJuridica/CNPJ/cnpjreva/cnpjreva_solicitacao2.asp
repeat: <%repeat%>
do:
# Решаем капчу
- captcha_resolve:
provider: deathbycaptcha.com
type: nocaptchav2
username: ВАШЕ ИМЯ ПОЛЬЗОВАТЕЛЯ В СЛУЖБЕ DBC
password: ВАШ ПАРОЛЬ В СЛУЖБЕ DBC
Пока не запускайте ваш парсер, просто изучите код. Если капча решена успешно, токен будет сохранен в переменной captcha. Поэтому, первым делом после решения капчи мы должны проверить наличие токена в переменной. Если токен есть, мы отключим опцию repeat и передадим токен на сервер вместе с другими параметрами нашего запроса. Если токена нет, запрос будет повторен, поскольку опция repeat установлена в «yes».
---
config:
debug: 2
agent: Firefox
proxy: ВАШ ПРОКСИ НУЖНО ВСТАВИТЬ СЮДА
do:
# Мы будем повторять неудавшийся запрос, поэтому пропишем значение переменной,
# которую будет использовать опция repeat
- variable_set:
field: repeat
value: "yes"
# Загружаем страницу с капчей
- walk:
to: http://www.receita.fazenda.gov.br/PessoaJuridica/CNPJ/cnpjreva/cnpjreva_solicitacao2.asp
repeat: <%repeat%>
do:
# Решаем капчу
- captcha_resolve:
provider: deathbycaptcha.com
type: nocaptchav2
username: ВАШЕ ИМЯ ПОЛЬЗОВАТЕЛЯ В СЛУЖБЕ DBC
password: ВАШ ПАРОЛЬ В СЛУЖБЕ DBC
# Переходим в блок body
- find:
path: body
do:
# Читаем значение переменной captcha в регистр
- variable_get: captcha
# Проверяем, не пустой ли у нас регистр
- if:
match: \w+
do:
# Если не пустой, отключаем repeat
- variable_set:
field: repeat
value: "no"
# Передаем токен и другие параметры на сайт с которого мы собираем информацию.
# В данном случае мы пытаемся получить данные о компании по его ИНН (CNPJ)
- walk:
to:
post: http://www.receita.fazenda.gov.br/PessoaJuridica/CNPJ/cnpjreva/valida_recaptcha.asp
data:
origem: comprovante
cnpj: 05754558000186
g-recaptcha-response: <%captcha%>
submit1: Consultar
search_type: cnpj
do:
- find:
path: 'div#principal'
do:
- object_new: item
- find:
path: td:haschild(font:contains('NÚMERO DE INSCRIÇÃO')) b
slice: 0
do:
- parse
- space_dedupe
- trim
- object_field_set:
object: item
field: registration_number
- find:
path: td:haschild(font:contains('DATA DE ABERTURA')) b
slice: 0
do:
- parse
- space_dedupe
- trim
- object_field_set:
object: item
field: registration_date
- find:
path: td:haschild(font:contains('NOME EMPRESARIAL')) b
slice: 0
do:
- parse
- space_dedupe
- trim
- object_field_set:
object: item
field: company_name
- find:
path: td:haschild(font:contains('CÓDIGO E DESCRIÇÃO DA ATIVIDADE ECONÔMICA PRINCIPAL')) b
slice: 0
do:
- parse
- space_dedupe
- trim
- object_field_set:
object: item
field: primary_code
- find:
path: td:haschild(font:contains('CÓDIGO E DESCRIÇÃO DAS ATIVIDADES ECONÔMICAS SECUNDÁRIAS')) b
do:
- parse
- space_dedupe
- trim
- object_field_push:
object: item
field: secondary_codes
- find:
path: td:haschild(font:contains('CÓDIGO E DESCRIÇÃO DA NATUREZA JURÍDICA')) b
slice: 0
do:
- parse
- space_dedupe
- trim
- object_field_set:
object: item
field: legal_code
- find:
path: td:haschild(font:contains('LOGRADOURO')) b
slice: 0
do:
- parse
- space_dedupe
- trim
- object_field_set:
object: item
field: street
- find:
path: td:haschild(font:contains('BAIRRO/DISTRITO')) b
slice: 0
do:
- parse
- space_dedupe
- trim
- object_field_set:
object: item
field: district
- find:
path: td:haschild(font:contains('MUNICÍPIO')) b
slice: 0
do:
- parse
- space_dedupe
- trim
- object_field_set:
object: item
field: municipal
- find:
path: td:haschild(font:contains('TELEFONE')) b
slice: 0
do:
- parse
- space_dedupe
- trim
- object_field_set:
object: item
field: phone
- find:
path: td:haschild(font:contains('E-MAIL')) b
slice: 0
do:
- parse
- space_dedupe
- trim
- object_field_set:
object: item
field: email
- object_save:
name: item
Если вы запустите этот парсер вы получите следующий датасет
[{
"item": {
"company_name": "LIST - LOGISTICA INTEGRADA, SERVICOS E TRANSPORTES LTDA",
"district": "COROADO",
"legal_code": "206-2 - Sociedade Empresária Limitada",
"municipal": "MANAUS",
"phone": "(92) 3622-7885",
"primary_code": "52.12-5-00 - Carga e descarga",
"registration_date": "26/06/2003",
"registration_number": "05.754.558/0001-86",
"secondary_codes": [
"49.30-2-02 - Transporte rodoviário de carga, exceto produtos perigosos e mudanças, intermunicipal, interestadual e internacional",
"77.39-0-99 - Aluguel de outras máquinas e equipamentos comerciais e industriais não especificados anteriormente, sem operador",
"77.19-5-99 - Locação de outros meios de transporte não especificados anteriormente, sem condutor",
"52.29-0-99 - Outras atividades auxiliares dos transportes terrestres não especificadas anteriormente",
"49.30-2-01 - Transporte rodoviário de carga, exceto produtos perigosos e mudanças, municipal",
"52.50-8-03 - Agenciamento de cargas, exceto para o transporte marítimo"
],
"street": "R PROFESSORA RAYMUNDA MAGALHAES"
}
}]
Подобные решения часто используются в сценариях типа «Данные по требованию». Когда пользователь на вашем сайте вводит номер, ваш сайт принимает ввод от пользователя и делает запрос на API платформы Diggernaut. Этот запрос запускает диггер с переданным параметром и возвращает собранные данные обратно на ваш сервер в режиме реального времени. А ваш сервер показывает их вашему пользователю. Однако примите во внимание, что процесс решения капчи может занимать продолжительное время, например решение reCaptcha v2 может занимать более 1 минуты. Это нужно учитывать при проектировании вашего приложения.
В любом случае, мы надеемся, что статья была вам полезна и поможет вам внедрить это решение для вашего парсера. Мы планируем добавлять решения для других видов капчи, следите за обновлениями.
variant3
Пока нет решения для ReCaptcha v3, как только оно появится, мы оповестим всех через блог и сделаем изменения в документации
Появилось решение для ReCaptcha V3. Его предоставляет сервис RuCaptcha/2Captcha. Интеграция с ними была выпущена вчера. Больше информации можно найти в документации
А почему использовали DeathByCaptcha, а не наш RuCaptcha?
У нас в данный момент есть интеграции с DeathByCaptcha и Anti-Captcha. Посмотрим в сторону RuCaptcha, если у них все нормально с API, добавим и их.
Сделали интеграцию с RuCaptcha и 2Captcha, подробности в документации