Як використовувати Java для скрейпінгу даних в Мережі

Зміст:
- Огляд інструментів від сайту проксі сервера
- Основи CSS-селекторів для тих, кого цікавить оренда проксі від Dexodata
- Покроковий гайд по створенню Java-скрейпера
- Тонкощі запитів
- Висновок
Dexodata, сайт проксі сервер, що пропонує оренду проксі за ціною від 3.65 доларів за 1 Гб, працює з користувачами, яким потрібно регулярно збирати дані в інтернеті. Наша команда набула в цій сфері експертного досвіду. І ми знаємо, що Java — не єдиний варіант мови програмування для скриптів дата-харвестингу.
З цими цілями люди звертаються і до PHP, і до Node.js, і до C#, і до Python. І все ж Java особливо популярна. У цьому матеріалі наша команда розповість про потенціал цієї мови на практичних прикладах. У подальшому читачі зможуть звернутися до цього гайду, щоб застосувати ці знання на практиці, спробувавши проксі безкоштовно або купивши приватні проксі Dexodata.
Огляд інструментів від сайту проксі сервера
Коли йдеться про парсинг за допомогою Java, часто згадуються ці інструменти: JSoup і HtmlUnit.
JSoup працює як ефективна і при цьому відносно проста бібліотека, здатна працювати з деформованими документами HTML. Її тому і називають «JSoup», адже позначення «tag soup» застосовується якраз до безсистемних блоків даних.
Що стосується HtmlUnit, то його можна описати як headless-браузер (т. е. браузер без графічного інтерфейсу), пристосований для інструментів на основі Java. Він здатний імітувати дії, характерні для браузера і, як випливає з назви, застосовується для юніт-тестування. Тобто, він «симулює» дії браузера в рамках тестового сценарію.
У цьому статусі він здатний виділяти фрагменти, заповнювати форми, клікати по елементах і т.д. Для автоматизованого збору інформації в інтернеті через проксі подібні здібності — в самий раз. HtmlUnit насправді спрощує взаємодію зі сторінкою. Це ми підтверджуємо з точки зору сайту проксі сервера для оренди проксі з пулів адрес з геотаргетингом і ротацією (з нами можна не тільки купити приватні проксі, але й спробувати проксі безкоштовно).
Додатковий аргумент на користь HtmlUnit стосовно перегляду веб-сторінок і збору даних: користувачу потрібно лише одна рядок коду, щоб деактивувати як JS, так і CSS.
Важливо: Цей гайд передбачає, що читачі вже в якійсь мірі освоїли Java, а також на достатньому рівні знають Maven. В додаток до основам Java вони повинні мати уявлення про те, як функціонують веб-сторінки з точки зору HTML. Знайомство з селекторами XPath або CSS також бажане.
Основи CSS-селекторів для тих, кого цікавить оренда проксі від Dexodata
Зупинимося на секунду, щоб освіжити в пам'яті релевантні CSS-селектори:
- #firstname — бере кожен елемент, id якого відповідає «firstname»;
- .blue — бере кожен елемент, клас якого має відношення до «.blue»;
- p — бере кожен тег <p>;
- div#firstname — бере базові елементи <div>, id яких відповідає «firstname»;
- p.link.new — зверніть увагу на відсутність пробілів. Ця частина відповідальна за вибір <p class="link new">;
- p.link .new — а от тут пробіл є. Ця частина відповідальна за вибір кожного компонента, що відноситься до класу «new», який можна знайти всередині <p class="link">.
Покроковий гайд по створенню Java-скрейпера
На базі досвіду, який ми набули в якості сайту проксі сервера, Dexodata починає процес розробки Java-скрейпера. Робити це ми будемо за допомогою Maven, JSoup і HtmlUnit.
Результат наших зусиль, власне скрейпер, краще використовувати в комбінації з орендованими проксі з ротацією IP. У нових користувачів, на додаток до можливості купити приватні проксі, є право запросити пробний період і спробувати проксі безкоштовно.
1. Для початку добудемо бібліотеки.
Тут допоможе Maven. Якщо вона з якоїсь причини не підходить, то пройдіть на цю веб-сторінку, тут є альтернативи. Ми ж працюємо з Maven, скачати його можна тут.
Як тільки установка закінчена, запустіть там новий проект за допомогою команди:
mvn archetype:generate -DgroupId=com.mycompany.parser -DartifactId=java-parser -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
Поступивши так, користувачі створять нову проектну папку під назвою «java-parser». Це надасть в їх розпорядження всі потрібні файли Maven і базову структуру.
2. Тепер додамо залежності до файлу pom.xml.
У файлі pom.xml («pom» означає «Project Object Model») треба додати новий розділ для роботи з залежностями в рамках JSoup. Ідемо до папки «java-parser» і відкриваємо файл pom.xml. Включаємо залежності під тегом <dependencies>:
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.14.3</version>
</dependency>
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.56.0</version>
</dependency>
Зберігаємо pom.xml і продовжуємо наш маршрут з Dexodata, сайтом проксі сервером і сьогоднішнім інструктором по створенню скрейперів.
3. Генеруємо новий клас Java.
У папці src/main/java/com/mycompany/parser створюємо новий файл Java під назвою «HtmlParser.java». Цей елемент послужить точкою збору і входу для майбутнього парсера.

4. Імпортуємо потрібні бібліотеки в «HtmlParser.java».
Відкриємо файл у текстовому редакторі або ж у вибраній середовищі розробки, а потім проставимо ці рядки на самому початку файлу «HtmlParser.java»:
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
Ми вже пройшли немалий шлях, продовжуємо слідувати за заданим маршрутом з нашим сайтом проксі сервером.
5. Запустіть об'єкт «WebClient» і деактивуйте JS і CSS.
Всередині класу «HtmlParser» задайте методи для створення об'єкта «WebClient», витягування HTML за допомогою HtmlUnit, аналізу вмісту HTML за допомогою JSoup і збору вузько визначених даних (таких, як заголовок, опис і зображення) у потрібній послідовності.
public class HtmlParser {
private static WebClient createWebClient() {
WebClient webClient = new WebClient();
webClient.getOptions().setJavaScriptEnabled(false);
webClient.getOptions().setCssEnabled(false);
return webClient;
}
}
6. Створюємо метод для витягування HTML за допомогою HtmlUnit:
public static HtmlPage fetchHtmlPage(String url) {
try (WebClient webClient = createWebClient()) {
return webClient.getPage(url);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
7. Створюємо метод для парсингу HTML-контенту з JSoup:
public static Document parseHtmlContent(String htmlContent) {
return Jsoup.parse(htmlContent);
}
8. Продовжуємо працювати з HTML:
public static void extractInformation(Document document) {
// Витягнути інформацію з проаналізованого HTML-документа за допомогою методів JSoup
// наприклад, document.select("a[href]"), document.select("img[src$=.png]")
// Для більш детальної інформації зверніться до документації JSoup: https://jsoup.org/cookbook/
}
9. Створюємо метод для «витягування» інформації з HTML:
public static void main(String[] args) {
String url = "https://www.example.com";
HtmlPage htmlPage = fetchHtmlPage(url);
if (htmlPage != null) {
String htmlContent = htmlPage.asXml();
Як видно, всі ці кроки — зовсім не біном Ньютона. Принаймні, якщо покластися на досвід сайту проксі сервера Dexodata з пулом адрес для оренди проксі по всьому світу.
Попередня частина охоплювала підготовчі заходи загального порядку: витягненню HTML-вмісту за допомогою HtmlUnit і роботі з ним за допомогою JSoup.
Тепер зосередимося на «витягуванні» більш конкретних і специфічних даних, наприклад, заголовків, описів і зображень. Щоб це зробити, треба спочатку ідентифікувати HTML-теги і атрибути, пов'язані з цими компонентами. Тобто, необхідно скористатися інструментами розробника, що містяться в веб-браузерах, і «просканувати» вихідний HTML на предмет розташування і оформлення таких компонентів.

10. Уявімо типову ситуацію з веб-магазином. Після того як ідентифіковані всі потрібні компоненти HTML, приходить час використовувати розширені можливості JSoup для отримання таких даних.
Припустимо, що заголовок знаходиться в тегу <h1>, опис — в тегу <div> з класом «product-description», а зображення — в тегу <img> з класом «product-image». Проставте ці атрибути в коді, як зроблено у фрагменті нижче. Як видно, застосовується метод extractInformation():
public static void extractInformation(Document document) {
// Витягнути заголовок
String title = document.select("h1").text();
System.out.println("Title: " + title);
// Витягнути опис
String description = document.select("div.product-description").text();
System.out.println("Description: " + description);
// Витягнути URL зображення
String imageUrl = document.select("img.product-image").attr("src");
System.out.println("Image URL: " + imageUrl);
}
11. Якщо сайт, з яким відбувається робота, зав'язаний на JavaScript для динамічної завантаження контенту, треба активувати в HtmlUnit підтримку JS. Зробити це можна за рахунок ось такої маніпуляції з методом «createWebClient()»:
private static WebClient createWebClient() {
WebClient webClient = new WebClient();
webClient.getOptions().setJavaScriptEnabled(true);
webClient.getOptions().setCssEnabled(false);
webClient.getOptions().setThrowExceptionOnScriptError(false);
webClient.waitForBackgroundJavaScript(5000); // Чекати, поки JavaScript закінчить завантаження
return webClient;
}
Зверніть увагу: включення JavaScript може збільшити час завантаження і створити ризик помилок. Dexodata, як сайт проксі сервер, в курсі регулярних скарг користувачів на проблеми через JS, однак подібні ситуації неминучі при роботі з динамічними сторінками.
12. Після отримання заголовків, описів і зображень може виникнути потреба зберегти цю інформацію для подальшого аналізу або обробки.
Поширеним методом є зберігання зібраної інформації у файлах CSV, JSON або XML. У цьому сценарії команда сайту проксі сервера Dexodata збереже інформацію в файлі CSV. Це відбувається наступним чином.
Створюємо метод трансформації в CSV:
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public static void writeToCSV(String title, String description, String imageUrl, String outputFilePath) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFilePath, true))) {
String csvLine = String.join(",", "\"" + title.replace("\"", "\"\"") + "\"",
"\"" + description.replace("\"", "\"\"") + "\"",
"\"" + imageUrl.replace("\"", "\"\"") + "\"");
writer.write(csvLine);
writer.newLine();
} catch (IOException e) {
e.printStackTrace();
}
}
Цей підхід використовує заголовок, опис, imageUrl, а також outputFilePath в якості вхідних параметрів.
13. Оновіть «extractInformation()», щоб викликати метод «writeToCSV()» для роботи з витягнутою раніше інформацією:
public static void extractInformation(Document document, String outputFilePath) {
// Витягнути заголовок, опис і URL зображення, як і раніше
// Записати витягнуті дані у файл CSV
writeToCSV(title, description, imageUrl, outputFilePath);
}
14. Також модифікуйте основний метод, щоб охопити шлях до вихідного файлу і передати його «extractInformation()»:
public static void main(String[] args) {
String url = "https://www.example.com";
String outputFilePath = "output.csv";
HtmlPage htmlPage = fetchHtmlPage(url);
if (htmlPage != null) {
String htmlContent = htmlPage.asXml();
Document document = parseHtmlContent(htmlContent);
extractInformation(document, outputFilePath);
}
}
Тепер при запуску парсер бере заголовок, опис і URL-адресу зображення зі сторінки інтернет-магазину і записує дані в вказаний CSV-файл. Є також можливість додатково налаштувати формат виходу файлу, додати підзаголовки або ж зберегти інформацію в JSON або XML.
Протестуйте свій парсер, застосувавши головний метод на URL-адреси інтернет-магазину. Обов'язково налаштуйте селектори JSoup відповідно до реальної структури його сторінок. Парсер завжди можна проапгрейдити, щоб витягти додаткову інформацію: ціни, специфікації або відгуки користувачів.
Аналіз бізнес-даних у сфері e-commerce є одним з ключових сценаріїв для оренди проксі з геотаргетингом від сайту проксі сервера Dexodata. Тож наша команда знає, наскільки корисним може бути такий інструмент.
Тонкощі запитів
Надсилати запити на витяг інформації — базова мета скрейпінгових програм на Java. Щодо бібліотеки JSoup, існує кілька способів отримання цікавих нам компонентів. Ці методи включають getElementByID або getElementsByTag. З їх допомогою серйозно спрощується робота на базі DOM-методів.
Наш сценарій дозволяє використовувати як getElementByID, так і getElementsByClass. Зверніть увагу на важливу відмінність. У той час як getElementByID (в однині) призначений для видачі одного об'єкта Element, то з getElementsByClass (число вже множинне) буде видано Array-список, що містить всі підходящі об'єкти Element.
Зручно, що в JSoup є клас Elements. Завдяки йому, Array-список <Element> може бути розширений. В результаті код стане акуратнішим і чистішим і забезпечить додаткові функції.
Так, уривок, показаний нижче, застосує техніку first() для видачі першого компонента в Array-список. Як тільки цей крок зроблено, метод text() витягне для нас з нього потрібний текстовий контент.
Element firstHeading = document.getElementsByClass("firstHeading").first();
System.out.println(firstHeading.text());
Паралельно, не варто також скидати з рахунків метод selectFirst(), який видасть нам перше ж співпадіння:
Element firstHeading= document.selectFirst(".firstHeading");
Висновок
Результативність автоматизованого збору онлайн-даних — основний критерій процедури, до якої час від часу вдається кожна компанія. Мати необхідний рівень знань для створення парсерів на основі Java — серйозне перевага в конкурентній боротьбі. І як можуть бачити читачі, нічого надскладного в написанні коду немає.
Наприкінці підкреслимо, що створений Java-парсер краще використовувати в комбінації з сайтом проксі сервером, що пропонує адекватний пул адрес для оренди проксі. З командою Dexodata користувачі можуть купити приватні проксі для збору даних, ну а новачкам доступна можливість спробувати проксі безкоштовно завдяки пробному періоду. Наша екосистема пропонує всі типи IP-адрес проксі: серверні, резидентні та мобільні.