Создаем парсер на Java

Многие компании используют парсинг сайтов, чтобы агрегировать информацию из конкурентных ресурсов. Ее можно получить из HTML-кода веб-страниц. Но только не ту, которая находится в картинках или другом медийном контенте. В этом руководстве мы научимся парсить данные с помощью Java.

Обязательные условия

  • Базовые знания Java;
  • Основы XPath.

Инструменты

Вам потребуется Java 8 и браузер HtmlUnit

<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.19</version>
</dependency>

Если вы используете Eclipse, советую изменить максимальную длину в окне подробностей (при нажатии на вкладку «Переменные»), чтобы можно было видеть весь HTML-код веб-страницы.

Инструменты

Парсер на java: пример-получим данные из интернет-магазина

В примере парсинга сайта Java мы извлечем информацию с интернет-магазина. Соберем имена, цены, а также картинки и экспортируем их в формат JSON.

Сначала посмотрим, что происходит при поиске товара в магазине. Для этого откройте «Инструменты разработчика» в Chrome и перейдите на вкладку «Network»:

Парсер на java: пример-получим данные из интернет-магазина

URL поиска:

https://newyork.craigslist.org/search/moa?is_paid=all&search_distance_type=mi&query=iphone+6s

Также можно использовать

https://newyork.craigslist.org/search/sss?sort=rel&query=iphone+6s

Теперь откройте среду разработки. Пришло время писать код. Для выполнения запроса в HtmlUnit нужен WebClient. Сначала нужно отключить JavaScript, так как в нашем примере он не нужен, и без него страница будет загружаться быстрее:

String searchQuery = "Iphone 6s" ;
WebClient client = new WebClient();
client.getOptions().setCssEnabled(false);
client.getOptions().setJavaScriptEnabled(false);
try {
String searchUrl = "https://newyork.craigslist.org/search/sss?sort=rel&query=" + URLEncoder.encode(searchQuery, "UTF-8");
HtmlPage page = client.getPage(searchUrl);
}catch(Exception e){
e.printStackTrace();
}
}

В объекте HtmlPage будет HTML-код, доступ к которому можно получить с помощью метода asXml(). Вытянем с сайта названия, изображения и цены. Для этого нужно внимательно просмотреть структуру DOM:

Парсер на java: пример-получим данные из интернет-магазина - 2

Для парсинга страниц сайта есть несколько способов выбрать тег HTML, используя HtmlUnit:

  • getHtmlElementById(String id);
  • getFirstByXPath(String Xpath)-getByXPath(String XPath), который возвращает список.

Поскольку мы не можем использовать ID, чтобы выбрать теги, нужно составить выражение Xpath.

XPath — это язык запросов для выбора элементов XML (в нашем случае HTML).

Сначала нужно выбрать все теги <p> с классом `result-info. Затем выполнить итерацию в списке, и для каждого предмета выбрать название, цену и URL, а также вывести на экран.

List<HtmlElement> items = (List<HtmlElement>) page.getByXPath("//p[@class='result-info']" ;
if(items.isEmpty()){
System.out.println("No items found !");
}else{
for(HtmlElement item : items){
HtmlAnchor itemAnchor =  ((HtmlAnchor) htmlItem.getFirstByXPath(".//a"));
String itemName = itemAnchor.asText();
String itemUrl = itemAnchor.getHrefAttribute() ;
HtmlElement spanPrice =((HtmlElement) htmlItem.getFirstByXPath(".//span[@class='result-price']")) ;
// Возможно, что для товара не установлена цена
String itemPrice = spanPrice == null ? "no price" : spanPrice.asText() ;
System.out.println( String.format("Name : %s Url : %s Price : %s", itemName, itemPrice, itemUrl));
}
}

Затем сохраним данные в формате JSON, используя библиотеку Jackson. Для представления элементов, полученных при парсинге email адресов с сайта, нам понадобится POJO (объект языка Java).

Item.java

public class Item {
private String title ;
private BigDecimal price ;
private String url ;
// геттеры и сеттеры
}

Затем добавим это в файл pom.xml:

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.0</version>
</dependency>

Теперь нужно создать элемент, задать атрибуты, конвертировать в строку или файл JSON и немного адаптировать предыдущий код парсинга данных с сайта:

for(HtmlElement htmlItem : items){
HtmlAnchor itemAnchor = ((HtmlAnchor) htmlItem.getFirstByXPath(".//span[@class='txt']/span[@class='pl']/a"));
HtmlElement spanPrice = ((HtmlElement) htmlItem.getFirstByXPath(".//span[@class='txt']/span[@class='l2']/span[@class='price']")) ;
// Возможно, для товара не установлена цена, в этом случае мы обозначаем ее как 0.0
String itemPrice = spanPrice == null ? "0.0" : spanPrice.asText() ;
Item item = new Item();
item.setTitle(itemAnchor.asText());
item.setUrl( baseUrl +
itemAnchor.getHrefAttribute());
item.setPrice(new BigDecimal(itemPrice.replace("$", "")));
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(item) ;
System.out.println(jsonString);
}

Не останавливайтесь

Этот пример парсинга другого сайта не идеален, многое можно улучшить:

  • Поиск по городам;
  • Обработка пагинации;
  • Поиск по нескольким критериям.

Код примера находится здесь.

СМСергей Марочканичавтор статьи «Introduction to Web scraping with Java»

Пожалуйста, оставляйте свои отзывы по текущей теме материала. За комментарии, дизлайки, лайки, подписки, отклики огромное вам спасибо!