Парсинг сайтов с помощью 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 мы извлечем информацию с интернет-магазина. Соберем имена, цены, а также картинки и экспортируем их в формат JSON.

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

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:

Для парсинга страниц сайта есть несколько способов выбрать тег 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” был подготовлен дружной командой проекта Сайтостроение от А до Я.