Когда Casper.js недостаточно (Selenium)

17.11.2016 03:08

Если у Вас есть только одна попытка, и ни в коем случае нельзя спалиться что вы используете бота, то Вас спасёт Selenium. Это практически самый тяжелый калибр, дальше только sikuli.

Итак, задача. Есть сайт: bookface.ycombinator.com. Доступ к сайту закрыт, но у нас есть логин и пароль. Причём живой логин от настоящей компании и спалить его никак нельзя. Наша задача: собрать все открытые профили пользователей и компаний. Мы не знаем есть ли какая-то защита от ботов (скорее всего нет), но на кону стоит пара миллионов настоящих долларов.

Для начала нужно установить Selenium

Так как завести селениум в связке с нодой не получилось, будем использовать python версию.

pip install selenium

Готово, selenium установлен.

Нам не нужен selenium server, только клиентская часть. Но в дополнении нам нужен selenium webdriver для браузера chrome. Заходим на страницу: http://www.seleniumhq.org/download/ и скачиваем последнюю версию "Google Chrome Driver".

Создаём проект

Создаём папку с нашим проектом, в которой создаём файл "bookface.py", рядом с ним распаковываем chrome driver, а так же создаём папки "users" и "companies", в них мы сохраним сырые html страницы.

Далее, открываем bookface.py и пишем бота:

import time
import random
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

# Вспомогательные функции

def saveContent(fileName, content):
  ff = open(fileName, 'w')
  ff.write(content.encode('utf8'))
  ff.close()

def GoNext(curId):
  strr = 'https://bookface.ycombinator.com/user/' + str(curId)
  return strr

# основной скрипт
curId = 6253
outDir = 'users'

baseWebsite = 'https://bookface.ycombinator.com'
login = 'qwertyuiop'
passw = 'asdfghjkl'

loginSelector = 'input[name="acct"]'
passwSelector = 'input[name="pw"]'
submitSelector = 'input[value="login"]'

driver = webdriver.Chrome("/home/frfr/programms/afflight/bookface-python/chromedriver")
action = webdriver.ActionChains(driver)
wait = WebDriverWait(driver, 10)

# открываем базовый урл
driver.get(baseWebsite)
print('Website title: ' + driver.title)
time.sleep(5)

# Кликаем на кнопку "Login with YC HN"
driver.find_element_by_css_selector('body > div.container > div > section > div.row > div.col-md-7 > div > div > div.col-md-8 > div:nth-child(1) > div > a').click()
time.sleep(10)

# Вводим логин
print('Enter login')
loginElem = driver.find_element_by_css_selector(loginSelector)
action.move_to_element(loginElem).perform()
time.sleep(1)
loginElem.send_keys(login)
time.sleep(1)

# Вводим пароль
print('Enter passw')
passwElem = driver.find_element_by_css_selector(passwSelector)
passwElem.send_keys(passw)
time.sleep(1)

# Кликаем кнопку "submit"
print('Click submit')
driver.find_element_by_css_selector(submitSelector).click()
time.sleep(1)

time.sleep(random.randint(8, 15))

# Основной цикл программы
print('Pass thrue users...')
while True:
  nextM = GoNext(curId)
  print( nextM )
  
  time.sleep(random.randint(10, 20))
  
  # Загружаем страницу и ожидаем появление элемента
  driver.get(nextM)
  print('Message title: ' + driver.title)
  
  try:
    element = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR,'.page-header h1')))
    print('User: ' + element.text + ' ID: ' + str(curId) )
  
    fileName = outDir + '/' + str(curId) + '.html'
    # Сохраняем страницу
    saveContent(fileName, driver.page_source)
  except:
    print('Not exists')
    
  # curId = 0  # should be the last in this loop
  curId -= 1
  if curId <= 0:
    print "Finished!"
    break

Заранее извиняюсь перед всеми питонщиками, ибо это моя первая программа на нём.

Запуск бота:

python bookface.py

И немного пояснений к коду:

Опытным путём установлено, что всего на сайте 6253 пользователей. И мы можем просто пройтись по всем url'ам и сохранить страницы. Но некоторые из профилей будут либо недоступны, либо уже удалены, это мы должны учесть.

И конечно же авторизация. Мы будем использовать авторизацию на HackerNews, собсно как минимум половина кода посвящено ей.

На выходе мы будем иметь сохранённые html странички, которые уже сможем распарсить чем-нить более приличным (node+cheerio в моём случае).

Сам selenium очень простой, например, поиск элемента на странице по css селектору:

driver.find_element_by_css_selector('какой-нить селектор')

Отправка данных в инпут:

element.send_keys('какие-нить данные')

И так далее.

Ещё немного паранойи.

Чтобы уж наверняка не спалить контору, устанавливаем VPN клиент, и подключаемся с Калифорнийской ноды, а так же выставляем опцию "разрывать интернет-соединение при отключении ВПН".



Вам не нужен Gulp/Grunt/Webpack

Нам всего-лишь нужен npm. Я давно использую Gulp для управления моими задачами: конвертирование scss в css, конвертирование ES2015 js в ES5, минимизация js файлов, оптимизация изображений.

Пример использования Google-vision API

Появилась задача распознать текст на пачке картинок (~30k штук), при этом tesseract спасовал, выдавая очень нестабильный результат. По этому принял решение использовать всю мощь корпорации добра.


(0) Комментариев