Хобрук: Ваш путь к мастерству в программировании

Как просканировать веб-сайт (или страницу) на предмет информации и добавить ее в мою программу?

Ну, я в значительной степени пытаюсь понять, как извлечь информацию с веб-страницы и перенести ее в свою программу (на Java).

Например, если я знаю точную страницу, с которой мне нужна информация, для простоты страницы с наиболее выгодной покупкой, как я могу получить соответствующую информацию с этой страницы? Нравится название, цена, описание?

Как бы вообще назвать этот процесс? Я понятия не имел, что нужно было даже начать исследовать это.

Изменить: Хорошо, я запускаю тест для JSoup (тот, который опубликован BalusC), но я продолжаю получать эту ошибку:

Exception in thread "main" java.lang.NoSuchMethodError: java.util.LinkedList.peekFirst()Ljava/lang/Object;
at org.jsoup.parser.TokenQueue.consumeWord(TokenQueue.java:209)
at org.jsoup.parser.Parser.parseStartTag(Parser.java:117)
at org.jsoup.parser.Parser.parse(Parser.java:76)
at org.jsoup.parser.Parser.parse(Parser.java:51)
at org.jsoup.Jsoup.parse(Jsoup.java:28)
at org.jsoup.Jsoup.parse(Jsoup.java:56)
at test.main(test.java:12)

У меня есть Apache Commons


  • У вас проблема с LinkedList, потому что LinkedList.peekFirst появился в java 1.6, и вы, похоже, используете более раннюю версию 10.08.2011
  • Этот процесс обычно называется очисткой экрана и используется, когда API (например, SOAP) недоступен, но есть веб-интерфейс. Это предполагает, что ваше приложение имитирует веб-браузер и анализирует HTML-страницы (более или менее) вручную. Я предлагаю вам рассмотреть один из перечисленных ниже API, который автоматизирует большую часть синтаксического анализа. 19.09.2011

Ответы:


1

Используйте парсер HTML, например Jsoup. Это мое предпочтение выше другого HTML. синтаксические анализаторы, доступные на Java, поскольку он поддерживает jQuery, например CSS-селекторы. Кроме того, его класс, представляющий список узлов, Elements, реализует _ 2_, чтобы можно было перебирать его в улучшен для цикла (так что не нужно беспокоиться с подробными Node и NodeList подобными классами в среднем парсере Java DOM).

Вот базовый пример запуска (просто поместите последний JAR-файл Jsoup в путь к классам):

package com.stackoverflow.q2835505;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Test {

    public static void main(String[] args) throws Exception {
        String url = "https://stackoverflow.com/questions/2835505";
        Document document = Jsoup.connect(url).get();

        String question = document.select("#question .post-text").text();
        System.out.println("Question: " + question);

        Elements answerers = document.select("#answers .user-details a");
        for (Element answerer : answerers) {
            System.out.println("Answerer: " + answerer.text());
        }
    }

}

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

14.05.2010
  • Вау, это здорово! У меня есть вопрос, я просто скопировал и вставил это, чтобы выполнить тестовый запуск, но я продолжаю получать эту ошибку (см. Отредактированный OP) 15.05.2010
  • @James: Для этого требуется как минимум Java 1.6 (которая уже выпущена более трех лет назад). Упомянутый _1 _ Метод был представлен в Java 1.6. Обновите JVM (JDK) или настройте IDE (Eclipse?) В режим соответствия Java 6. 15.05.2010
  • Если кому-то из .NET-программистов интересно, я портировал jsoup на .NET: nsoup.codeplex.com. Надеюсь, это кому-нибудь поможет. 31.05.2010
  • @BalusC, Вот пример, который вы привели: Made My Day !!! не знал об этой удивительной библиотеке !!! Я сходил с ума от URL FETCH ... Jsoup - это то, что я должен был искать ... Огромное спасибо! 14.04.2012
  • @ user2602807: Jsoup - это анализатор HTML, а не клиент HTML. Просто используйте клиентскую библиотеку HTML. См. Также stackoverflow.com/questions/3152138/ 16.09.2014
  • добавить зависимости gradle: implementation 'org.jsoup:jsoup:1.13.1' 13.07.2020
  • JSoup нам отличное решение. Однако это (относительно) занимает много времени, потому что сначала нужно прочитать веб-страницу. Есть ли более быстрое решение? 18.02.2021
  • @CardinalSystem: Да, это именно то, о чем спрашивал ОП. Однако Jsoup просто поддерживает использование HTML-кода в переменной String, как в Document document = Jsoup.parse(html);. См. Также его документацию. 18.02.2021

  • 2

    Это называется очисткой экрана. В Википедии есть эта статья о более конкретном веб-скрапинге. Это может быть серьезной проблемой, потому что существует какой-то уродливый, беспорядочный, сломанный HTML-код, если не для браузера, так что удачи.

    14.05.2010

    3

    Я бы использовал JTidy - он похож на JSoup, но я плохо знаю JSoup. JTidy обрабатывает сломанный HTML и возвращает документ w3c, поэтому вы можете использовать его в качестве источника для XSLT для извлечения действительно интересующего контента. Если вы не знаете XSLT, то вы можете также использовать JSoup, как документ Модель приятнее работать, чем w3c.

    РЕДАКТИРОВАТЬ: быстрый просмотр веб-сайта JSoup показывает, что JSoup действительно может быть лучшим выбором. Кажется, он поддерживает селекторы CSS для извлечения материалов из документа. С этим может быть намного проще работать, чем с XSLT.

    14.05.2010

    4

    Вы можете использовать синтаксический анализатор html (здесь много полезных ссылок: java html parser).

    Этот процесс называется «захват содержимого веб-сайта». Выполните поиск по запросу "захватить содержимое веб-сайта java" для дальнейшей инвертигации.

    14.05.2010


    6

    Вы, вероятно, захотите взглянуть на HTML, чтобы увидеть, можете ли вы найти строки, которые уникальны и близки к вашему тексту, тогда вы можете использовать line / char-offsets для доступа к данным.

    Было бы неудобно в Java, если бы не было никаких классов XML, подобных тем, которые находятся в System.XML.Linq в C #.

    14.05.2010

    7

    Вы также можете попробовать jARVEST.

    Он основан на JRuby DSL поверх чистого Java-движка, позволяющего «паук» преобразовывать веб-сайты.

    Пример:

    Найдите все ссылки на веб-странице (wget и xpath являются конструкциями языка jARVEST):

    wget | xpath('//a/@href')
    

    Внутри программы на Java:

    Jarvest jarvest = new Jarvest();
      String[] results = jarvest.exec(
        "wget | xpath('//a/@href')", //robot! 
        "http://www.google.com" //inputs
      );
      for (String s : results){
        System.out.println(s);
      }
    
    11.07.2012

    8

    Мой ответ, вероятно, не будет полезен для автора этого вопроса (я опаздываю на 8 месяцев, поэтому я думаю, не в нужный момент), но я думаю, что он, вероятно, будет полезен для многих других разработчиков, которые могут столкнуться с этим ответом.

    Сегодня я только что выпустил (от имени своей компании) полную структуру HTML для POJO, которую вы можете использовать для сопоставления HTML с любым классом POJO с простыми аннотациями. Сама библиотека довольно удобна и имеет много других функций, при этом ее можно легко подключить. Вы можете посмотреть на него прямо здесь: https://github.com/whimtrip/jwht-htmltopojo < / а>

    Как использовать: Основы

    Представьте, что нам нужно проанализировать следующую html-страницу:

    <html>
        <head>
            <title>A Simple HTML Document</title>
        </head>
        <body>
            <div class="restaurant">
                <h1>A la bonne Franquette</h1>
                <p>French cuisine restaurant for gourmet of fellow french people</p>
                <div class="location">
                    <p>in <span>London</span></p>
                </div>
                <p>Restaurant n*18,190. Ranked 113 out of 1,550 restaurants</p>  
                <div class="meals">
                    <div class="meal">
                        <p>Veal Cutlet</p>
                        <p rating-color="green">4.5/5 stars</p>
                        <p>Chef Mr. Frenchie</p>
                    </div>
    
                    <div class="meal">
                        <p>Ratatouille</p>
                        <p rating-color="orange">3.6/5 stars</p>
                        <p>Chef Mr. Frenchie and Mme. French-Cuisine</p>
                    </div>
    
                </div> 
            </div>    
        </body>
    </html>
    

    Давайте создадим POJO, с которыми мы хотим его сопоставить:

    public class Restaurant {
    
        @Selector( value = "div.restaurant > h1")
        private String name;
    
        @Selector( value = "div.restaurant > p:nth-child(2)")
        private String description;
    
        @Selector( value = "div.restaurant > div:nth-child(3) > p > span")    
        private String location;    
    
        @Selector( 
            value = "div.restaurant > p:nth-child(4)"
            format = "^Restaurant n\*([0-9,]+). Ranked ([0-9,]+) out of ([0-9,]+) restaurants$",
            indexForRegexPattern = 1,
            useDeserializer = true,
            deserializer = ReplacerDeserializer.class,
            preConvert = true,
            postConvert = false
        )
        // so that the number becomes a valid number as they are shown in this format : 18,190
        @ReplaceWith(value = ",", with = "")
        private Long id;
    
        @Selector( 
            value = "div.restaurant > p:nth-child(4)"
            format = "^Restaurant n\*([0-9,]+). Ranked ([0-9,]+) out of ([0-9,]+) restaurants$",
            // This time, we want the second regex group and not the first one anymore
            indexForRegexPattern = 2,
            useDeserializer = true,
            deserializer = ReplacerDeserializer.class,
            preConvert = true,
            postConvert = false
        )
        // so that the number becomes a valid number as they are shown in this format : 18,190
        @ReplaceWith(value = ",", with = "")
        private Integer rank;
    
        @Selector(value = ".meal")    
        private List<Meal> meals;
    
        // getters and setters
    
    }
    

    А теперь еще и класс Meal:

    public class Meal {
    
        @Selector(value = "p:nth-child(1)")
        private String name;
    
        @Selector(
            value = "p:nth-child(2)",
            format = "^([0-9.]+)\/5 stars$",
            indexForRegexPattern = 1
        )
        private Float stars;
    
        @Selector(
            value = "p:nth-child(2)",
            // rating-color custom attribute can be used as well
            attr = "rating-color"
        )
        private String ratingColor;
    
        @Selector(
            value = "p:nth-child(3)"
        )
        private String chefs;
    
        // getters and setters.
    }
    

    Мы предоставили еще несколько пояснений к приведенному выше коду на нашей странице github.

    А пока давайте посмотрим, как это выбросить.

    private static final String MY_HTML_FILE = "my-html-file.html";
    
    public static void main(String[] args) {
    
    
        HtmlToPojoEngine htmlToPojoEngine = HtmlToPojoEngine.create();
    
        HtmlAdapter<Restaurant> adapter = htmlToPojoEngine.adapter(Restaurant.class);
    
        // If they were several restaurants in the same page, 
        // you would need to create a parent POJO containing
        // a list of Restaurants as shown with the meals here
        Restaurant restaurant = adapter.fromHtml(getHtmlBody());
    
        // That's it, do some magic now!
    
    }
    
    
    private static String getHtmlBody() throws IOException {
        byte[] encoded = Files.readAllBytes(Paths.get(MY_HTML_FILE));
        return new String(encoded, Charset.forName("UTF-8"));
    
    }
    

    Другой короткий пример можно найти здесь

    Надеюсь, это кому-то поможет!

    26.07.2018

    9

    Решение JSoup отличное, но если вам нужно извлечь что-то действительно простое, может быть проще использовать регулярное выражение или String.indexOf

    Как уже упоминалось другими, этот процесс называется очисткой.

    14.05.2010
  • Почему было бы проще использовать регулярное выражение? Я пробовал регулярное выражение, и он действительно не может обрабатывать реальный html и, возможно, опасно использовать синтаксический анализ html. Jsoup - это готовое решение, всего несколько строковых кодов, и вы делаете все, что вам нужно, со своим html .. 28.05.2010
  • Упрощенный пример. Представьте, что все, что вам нужно, - это извлечь дату создания страницы. Итак, вы проверяете html и видите что-то вроде <span id='date'>07/07/07</span>. Что ж, тогда я бы использовал String.indexOf или некоторые из моих собственных утилит, например textBetween (‹span id = 'date'›, ‹/span›). Дополнительным преимуществом является то, что вам не нужно разбирать весь html. Мне удалось извлечь данные из html с помощью собственного класса StringScanner с такими методами, как moveBefore (String what), moveAfter (String what), getTextUpTo (String what), ... Все зависит от сложности вашей проблемы. 29.05.2010

  • 10

    Загляните в библиотеку cURL. Я никогда не использовал его в Java, но уверен, что для него должны быть привязки. По сути, вы должны отправить запрос cURL на любую страницу, которую хотите «очистить». Запрос вернет на страницу строку с исходным кодом. Оттуда вы будете использовать регулярное выражение для анализа любых данных из исходного кода. Как правило, вы собираетесь это делать.

    14.05.2010
    Новые материалы

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

    Генерация ваших собственных удивительных QR-кодов с использованием Python
    QR-код (код быстрого ответа) — это разновидность матричных штрих-кодов (или двумерных штрих-кодов), изобретенных в 1994 году японской автомобильной компанией Denso Wave . Штрих-код —..

    Прогресс в технологии Трансформеров часть 3
    Многомасштабный управляющий сигнальный преобразователь для бесфазного синтеза движения (arXiv) Автор: Линтао Ван , Кун Ху , Лей Бай , Юй Дин , Ваньли Оуян , Чжиюн Ван . Аннотация:..

    Представляем поддержку компонентов Vue.js. Мгновенный HMR и многое другое.
    Хотя у FuseBox уже был плагин Vue, он был базовым и не имел многих функций, которые делали работу с Vue.js такой приятной. Однако с этим выпуском мы рады сообщить, что в FuseBox..

    Приключения в Javascript, часть 1
    Я продолжаю думать о том, чтобы писать больше, но чем больше я думаю об этом, тем меньше я это делаю. Итак, сегодня я перестал думать и начал писать. Отсюда можно только спускаться… В..

    Понимание дженериков в TypeScript: подробное руководство
    Введение TypeScript, строго типизированный надмножество JavaScript, хорошо известен своей способностью улучшать масштабируемость, удобочитаемость и ремонтопригодность приложений. Одной из..

    Учебные заметки JavaScript Object Oriented Labs
    Вот моя седьмая неделя обучения программированию. После ruby ​​и его фреймворка rails я начал изучать самый популярный язык интерфейса — javascript. В отличие от ruby, javascript — это более..