Как собрать информацию с Контур.Закупки с помощью Selenium

  • Tutorial
Всем привет.

Я занимаюсь автоматизацией участия в государственных тендерах.

История эта случилась из-за экономии. При покупке платного аккаунта Контур.Закупки мы не обратили внимание на то, сколько полезного даёт тариф Эксперт.

Ах, если бы мы обратили на это внимание, то мне не пришлось бы осваивать Selenium и основы Java.

Как-то раз возникла маркетинговая задача — собрать контакты закупщиков в компаниях по нашей тематике.

Ищу все конкурсы, подходящие по ключевым словам и в нужных регионах. За все прошлые годы, завершенные и текущие.

В выгрузке на тарифе Стандарт вот такие данные:



Есть только название компании. Контактных данных закупщика нет.

Теперь, чтобы не собирать вручную контактные данные закупщика, принимаю решение писать скрипт.

Так как у Контур.Закупок вся страничка загружается javascript-ом, то простым парсингом тут не отделаешься. Придётся писать скрипт на Selenium.

Для начала подготовим исходные данные — сохраняем в CSV номер конкурса (он же параметр в URL), а также название компании, чтобы не парсить её. Всё это в файл kontur_getContacts_src.csv



Далее, скрипт на Java с комментариями

import org.openqa.selenium.By;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.*;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.io.*;
import java.nio.file.*;


public class kontur_getContacts{

	public static void main(String args[]) throws Exception{
		//Запускаем коннектор к FireFox
		System.setProperty("webdriver.gecko.driver", "geckodriver.exe");
	
		
		FirefoxDriver driver = new FirefoxDriver();// Create a Firefox browser instance
		
		driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
		
		
		// Логинимся в Контур.Закупки		
		
		driver.get("https://auth.kontur.ru/login.aspx?authmode=certlogin&back=https%3A%2F%2Fzakupki.kontur.ru%2FLogin%2FCallback%3FReturnUrl%3Dhttps%253A%252F%252Fzakupki.kontur.ru%252F%253Fevent-login%253D1&customize=zakupki"); //Открываем страничку логина
		
		Thread.sleep(2*1000);
		
		WebElement login_field = driver.findElement(By.cssSelector(".loginPassword__login input")); // Ищем поле логин
		login_field.sendKeys("sales@mycomp.ru");//Посылаем текст элементу логин
		WebElement pass_field = driver.findElement(By.cssSelector("input.input__realInput")); //Ищем поле Пароль
		pass_field.sendKeys("password");//Посылаем текст элементу пароль
		Thread.sleep(1*1000); //Жду
		driver.findElement(By.cssSelector("input.button__input")).click(); // Ставлю галочку Оставаться в системе
		Thread.sleep(1*1000); //Жду
		driver.findElement(By.cssSelector(".loginPassword__submit .button__input")).click(); //Отправляю форму
		Thread.sleep(2*1000); //Жду
		
		String sourceFilePath = "C:/Users/user/selenium/kontur_getContacts_src.csv";//Файл, откуда брать исходную информацию
		String resultFilePath = "C:/Users/user/selenium/kontur_getContacts_result.csv";//Файл, куда писать результаты
		String delimeter = ";"; // Разделитель в файле с исходной информацией
		//Объявляем переменные
		String name; String text; 
		Integer flag_hasName=0;
		Integer flag_oneVar=0;
		
		try{
			//Откроем файл с проектами
			FileInputStream fstream = new FileInputStream(sourceFilePath);
			BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
			String strLine;//Объявляем переменные
			String[] subStr;//Объявляем переменные
			//Очищаем результирующий файл
			byte[] myBytes = "".getBytes(); 
			Files.write(Paths.get(resultFilePath), myBytes);
		 
			
			while ((strLine = br.readLine()) != null){ //Читаем файл с исходными данными построчно
				System.out.println(strLine); //Смотрим в консоли текущуб строку
			  
			  	//Делим текущую строку по делимитеру	 
				subStr = strLine.split(delimeter);
				System.out.println("Found order_id "+subStr[0]+" and Organization is "+subStr[1]);
				//Открываем страничку с этой закупкой
				driver.get("https://zakupki.kontur.ru/"+subStr[0]);

				/* Находим первую ссылочку на контакт закупщика */
				name =""; //Очищаем переменную, в кот будет имя заказчика
				text =""; //Очищаем переменную, в кот будут результаты работы скрипта
				
				List<WebElement> tenderField_data_in=driver.findElements(By.cssSelector(".popup__mainContacts .tenderField__s div.tenderField_data_in")); //Находим первую ссылку
				if(tenderField_data_in.size()>0){ 
				
					
					WebElement man = driver.findElement(By.cssSelector(".popup__mainContacts .tenderField__s div.tenderField_data_in"));//Находим поле имя
				
					System.out.println("FOUND is "+man.getAttribute("textContent")); //Смотрим имя в консоли
					
					name = man.getAttribute("textContent").trim(); //Присваиваем имя переменной name
				
				}
				
				// Ищем ссылки с данными заказчика
				List<WebElement> elements = driver.findElements(By.cssSelector(".tenderField .tenderField_data_in a"));
				
				System.out.println("Count elements in array is "+elements.size()); //Смотрим в консоли количество найденных элементов данных
				
				if(elements.size()>0){ //Есть линки на странице
				
					WebElement email = driver.findElement(By.cssSelector(".tenderField .tenderField_data_in a")); //Выделяем емейл
				
					text=subStr[1]+delimeter+email.getAttribute("href")+delimeter+name+"\r\n"; // Формируем строку для записи в файл с результатами
						
					Files.write(Paths.get(resultFilePath), text.getBytes(), StandardOpenOption.APPEND); //Дописываем в файл

					
				} 
				
		   }
		}catch (IOException e){
		   System.out.println("Error opening or processing file with finished purchases");
		}
		
		// Close the browser instance
		driver.quit();

	}
}

Запускаем скрипт Selenium

C:\Users\user\selenium>"C:\Program Files\Java\jdk-10.0.1\bin\javac" -cp selenium-server-standalone-3.13.0.jar; kontur_getContacts.java
* C:\Users\user\selenium>"C:\Program Files\Java\jre-10.0.1\bin\java" -cp selenium-server-standalone-3.13.0.jar; kontur_getContacts


Результатом будет вот такой файл с контактами, который можно использовать в маркетинговых целях.

Share post

Similar posts

Comments 14

    +1
    Thread.sleep(2*1000); //Жду

    image
    Есть же wait for!
    WebDriverWait wait = new WebDriverWait(webDriver, timeoutInSeconds);
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.id<locator>));

      +1
      Это мой первый скрипт на Java. Я вообще то PHP-шник. А Java я гуглю и пишу. Соответственно, что первое попалось, то и пишу.
        0
        Я вообще то PHP-шник.

        Понял.
        $driver->wait()->until(
            function () use ($driver) {
                $elements = $driver->findElements(WebDriverBy::cssSelector('li.foo'));
        
                return count($elements) > 5;
            },
            'Error locating more than five elements'
        );

        Заголовок спойлера
        Если Вы не поняли моего предыдущего сообщения, то я объясню: сначала нужно изучить инструмент, потом использовать, и только потом пилить на Хабр статью. Умолчу, что Вашу задачу можно было решить 1000 и 1 способом и совсем без selenium-а
          +1
          Решить то можно и без Seleniuma. Ну я решил вот так сделать, и, может быть, это кому то будет полезным готовым скриптом по работе с Контуром.

          А по поводу «Thread.sleep(2*1000);» — я руководствовался тем, что не знаю систему безопасности в Контуре, поэтому, чтобы не забанили аккаунт, притворялся простым юзером, который вводит данные с паузами. Паузу оно делает, поэтому задачу свою выполняет. Если что-то не нравится в написании, тут каждый может что-то добавить, что-то убрать.
          0
        0
        Зачем такие сложности. Посмотреть в devtools ajax запрос и повторить его. Если защиты нет то это 10 минут работы.
          +1
          1. Я не нашёл, где они в ajax-запросах. Может быть плохо искал, но…
          2. К тому же там ещё сложность в посылке логина системе. Страничка логина не простая, а защищённая. Вот из-за него и пришлось работать из браузера.
            0
            Страничка логина не простая, а защищённая.

            Самая обычная

            Заголовок спойлера
            Использовать нужно request типа Session, который хранит всю мета-информацию, от запроса к запросу
              0
              Ну да, вижу, что у Вас получилось отловить этот ajax.
                0
                В dev-tool браузера, на вкладке Network, есть волшебная галочка Preserve Log.
                  +1
                  Я тоже теперь вижу этот запрос. Спасибо, полезно!
          +3
          aRomanyuk, привет! Я из Контура. Классно, что ты разобрался, как у нас всё устроено в Закупках, потрогал Java и Selenium. Читали пост всей командой, гордились тобой :)

          Давай подарим тебе доступ к Закупкам на тарифе Эксперт? Во-первых, будет удобней работать — можно будет выгрузить информацию через интерфейс. Во-вторых, не нужно было поддерживать скрипт из поста. А ещё подарим книжку по Java — следующий скрипт писать будет легче :)

          Напишешь мне в личку?
            +1
            С удовольствием приму этот щедрый подарок
            –1
            Спасибо, Владимир Анатольевич, порадовали весь Контур! :-)

            Only users with full accounts can post comments. Log in, please.