Извлечение данных из HTML и форматирование вывода - PullRequest
0 голосов
/ 14 декабря 2018

Введение

В настоящее время я изучаю WebScrapping самостоятельно как личный проект для приобретения новых трюков и чистого хобби.

Пока я смог извлекать данные с веб-сайта (немного изучив структуру), используя этот код, который я создал с помощью библиотек Java и Jsoup .

//To input the html file
   File inputFile = new File("test2.html");
   Document doc = Jsoup.parse(inputFile, "Unicode");

   //To grab the part we are working with (knowing the website for sure)
   Element content = doc.getElementById("mainContent");
   Elements tds = doc.select("[class=nowrap]");
   System.out.println(tds.text());


    (Note that I am working from a HTML file)

Пока все хорошо, я получил этот "желаемый" вывод

 <td align="right" class="nowrap"> <a href="website" onclick="return 
 doWindow(this, 700, 500);" class="popup">0</a> </td>
 <td align="right" class="nowrap"><a href="website" 
 onclick="doWindow(this.href, '1024', '768'); return false;">10 000</a> [10 
 000]</td>
 <td align="right" class="nowrap">10 000</td>
 <td align="right" class="nowrap">20.48</td>
 <td align="right" class="nowrap">0.00</td>
 <td align="right" class="nowrap">$28.65</td>
 <td align="right" class="nowrap">0.00 %</td>
 <td align="right" class="nowrap">$894.69</td>
 <td align="right" class="nowrap">10.11</td>
 <td align="right" class="nowrap">0.21</td>
 <td align="right" class="nowrap"> <a href="website" onclick="return 
  doWindow(this, 700, 500);" class="popup">0</a> </td>
 <td align="right" class="nowrap"><a href="website" 
  onclick="doWindow(this.href, '1024', '768'); return false;">10 000</a> [10 
  000]</td>
  <td align="right" class="nowrap">10 000</td>
  <td align="right" class="nowrap">46.21</td>
  <td align="right" class="nowrap">0.00</td>
  <td align="right" class="nowrap">$53.82</td>
  <td align="right" class="nowrap">0.00 %</td>
  <td align="right" class="nowrap">$1 151.78</td>
  <td align="right" class="nowrap">8.01</td>
  <td align="right" class="nowrap">0.00</td>
  <td align="right" class="nowrap"> <a href="website" onclick="return 
 doWindow(this, 700, 500);" class="popup">0</a> </td>
 <td align="right" class="nowrap"><a href="website" 
  onclick="doWindow(this.href, '1024', '768'); return false;">5 000</a> [5 
  000]</td>
  <td align="right" class="nowrap">5 000</td>
  <td align="right" class="nowrap">22.51</td>
  <td align="right" class="nowrap">0.00</td>
  <td align="right" class="nowrap">$222.53</td>
  <td align="right" class="nowrap">0.00 %</td>
  <td align="right" class="nowrap">$2 399.92</td>
  <td align="right" class="nowrap">5.94</td>
  <td align="right" class="nowrap">0.01</td>

Задача

Я больше заинтересован в тексте , который содержит (точные числа (Strings)), чтобы потом немного подсчитать.

Поэтому я продолжил читать Документацию о Jsoup и обнаружил, что могу использовать .text(), чтобы избавиться от HTML-кода, получая длинную строкучисел из файла HTML как таковых:

0 10 000 [10 000] 10 000 20.48 0.00 $28.65 0.00 % $894.69 10.11 0.21 0 10 
000 [10 000] 10 000 46.21 0.00 $53.82 0.00 % $1 151.78 8.01 0.00 0 5 000 [5 
000] 5 000 22.51 0.00 $222.53 0.00 % $2 399.92 5.94 0.01

Как разделить его на 3 строки и использовать числа?

Один подход можетбыть RegEx, как я видел в других вопросах, но все еще не могу получить желаемый результат.

РЕДАКТИРОВАТЬ: Некоторый прогресс достигнут

После некоторых исследований я нашел способ преобразовать в текст и получить доступ к данным Я хотел сделать:

tds.get(key).text(); 

Где ключ - это целое число, относящееся к позиции в последней полученной строке.

Это решило часть моего вопроса, поскольку в HTML есть один атрибут, который мне не удалось получить.

<td align="center">
        <input type="text" tabindex="2" name="productData[price]       
        [{33013477}]" size="10" value="3000.00">    
</td>

Где нужное мне значение находится в значении атрибута = "3000.0"

Спасибо за интерес к этому вопросу.

1 Ответ

0 голосов
/ 16 декабря 2018

Для извлечения данных из источника HTML я использую небольшой метод с именем getBetween () , чтобы выполнить задачу.Конечно, данные, которые я лично хочу, кажется, всегда находятся между какими-то строками:

<code>/**
 * Retrieves any string data located between the supplied string leftString
 * parameter and the supplied string rightString parameter.<br><br>
 * <p>
 * <p>
 * This method will return all instances of a substring located between the
 * supplied Left String and the supplied Right String which may be found
 * within the supplied Input String.<br>
 *
 * @param inputString (String) The string to look for substring(s) in.
 *
 * @param leftString  (String) What may be to the Left side of the substring
 *                    we want within the main input string. Sometimes the
 *                    substring you want may be contained at the very
 *                    beginning of a string and therefore there is no
 *                    Left-String available. In this case you would simply
 *                    pass a Null String ("") to this parameter which
 *                    basically informs the method of this fact. Null can
 *                    not be supplied and will ultimately generate a
 *                    NullPointerException.
 *
 * @param rightString (String) What may be to the Right side of the
 *                    substring we want within the main input string.
 *                    Sometimes the substring you want may be contained at
 *                    the very end of a string and therefore there is no
 *                    Right-String available. In this case you would simply
 *                    pass a Null String ("") to this parameter which
 *                    basically informs the method of this fact. Null can
 *                    not be supplied and will ultimately generate a
 *                    NullPointerException.
 *
 * @param options     (Optional - Boolean - 2 Parameters):<pre>
 *
 *      ignoreLetterCase    - Default is false. This option works against the
 *                            string supplied within the leftString parameter
 *                            and the string supplied within the rightString
 *                            parameter. If set to true then letter case is
 *                            ignored when searching for strings supplied in
 *                            these two parameters. If left at default false
 *                            then letter case is not ignored.
 *
 *      trimFound           - Default is true. By default this method will trim
 *                            off leading and trailing white-spaces from found
 *                            sub-string items. General sentences which obviously
 *                            contain spaces will almost always give you a white-
 *                            space within an extracted sub-string. By setting
 *                            this parameter to false, leading and trailing white-
 *                            spaces are not trimmed off before they are placed
 *                            into the returned Array.
* * @return (1D String Array) Возвращает одномерный массив строк *, содержащий все подстроки, найденные в предоставленном Input* Строка, которая находится между предоставленной левой строкой и поставляемой * правой строкой.Вы можете немного сократить этот метод, * возвращая ArrayList List и удаляя код преобразования 'List * to 1D Array' в конце этого метода.Этот * метод изначально сохраняет свои результаты в объекте List * в любом случае.* / public String [] getBetween (String inputString, String leftString, String rightString, boolean ... options) {// Ничего не вернуть, если ничего не было предоставлено.if (inputString.equals ("") || (leftString.equals ("") && rightString.equals (""))) {return null;} // Готовим необязательные параметры, если таковые имеются.// Если ничего не указано, используйте Defaults ... boolean ignoreCase = false;// По умолчанию.логическое trimFound = true;// По умолчанию.if (options.length> 0) {if (options.length> = 1) {ignoreCase = options [0];} if (options.length> = 2) {trimFound = options [1];}} // Удаляем любые управляющие символы ASCII из // предоставленной строки (если они существуют).String modString = inputString.replaceAll ("\\ p {Cntrl}", "");// Установить объект массива List String для хранения // найденных подстрок между предоставленной левой // строкой и предоставленной правой строкой.List list = new ArrayList <> ();// Используем Pattern Matching, чтобы найти наши возможные подстроки в предоставленной Input String.Строка regEx = Pattern.quote (leftString) + (! RightString.equals ("")? "(. *?)": "(. *)?") + Pattern.quote (rightString);if (ignoreCase) {regEx = "(? i)" + regEx;} Pattern pattern = Pattern.compile (regEx);Matcher matcher = pattern.matcher (modString);while (matcher.find ()) {// Добавить найденные подстроки в список.Строка найдена = matcher.group (1);if (trimFound) {found = found.trim ();} list.add (найдено);} String [] res;// Преобразование ArrayList в 1D String Array.// Если список содержит что-то, тогда преобразуем if (list.size ()> 0) {res = new String [list.size ()];res = list.toArray (res);} // В противном случае вернуть Null.else {res = null;} // Возвращаем String Array.вернуть Res;}

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

Источник HTML:

 <td align="right" class="nowrap"> <a href="website" onclick="return 
 doWindow(this, 700, 500);" class="popup">0</a> </td>
 <td align="right" class="nowrap"><a href="website" 
 onclick="doWindow(this.href, '1024', '768'); return false;">10 000</a> [10 
 000]</td>
 <td align="right" class="nowrap">10 000</td>
 <td align="right" class="nowrap">20.48</td>
 <td align="right" class="nowrap">0.00</td>
 <td align="right" class="nowrap">$28.65</td>
 <td align="right" class="nowrap">0.00 %</td>
 <td align="right" class="nowrap">$894.69</td>
 <td align="right" class="nowrap">10.11</td>
 <td align="right" class="nowrap">0.21</td>
 <td align="right" class="nowrap"> <a href="website" onclick="return 
  doWindow(this, 700, 500);" class="popup">0</a> </td>
 <td align="right" class="nowrap"><a href="website" 
 onclick="doWindow(this.href, '1024', '768'); return false;">10 000</a> [10 
 000]</td>
 <td align="right" class="nowrap">10 000</td>
 <td align="right" class="nowrap">46.21</td>
 <td align="right" class="nowrap">0.00</td>
 <td align="right" class="nowrap">$53.82</td>
 <td align="right" class="nowrap">0.00 %</td>
 <td align="right" class="nowrap">$1 151.78</td>
 <td align="right" class="nowrap">8.01</td>
 <td align="right" class="nowrap">0.00</td>
 <td align="right" class="nowrap"> <a href="website" onclick="return 
 doWindow(this, 700, 500);" class="popup">0</a> </td>
 <td align="right" class="nowrap"><a href="website" 
 onclick="doWindow(this.href, '1024', '768'); return false;">5 000</a> [5 
 000]</td>
 <td align="right" class="nowrap">5 000</td>
 <td align="right" class="nowrap">22.51</td>
 <td align="right" class="nowrap">0.00</td>
 <td align="right" class="nowrap">$222.53</td>
 <td align="right" class="nowrap">0.00 %</td>
 <td align="right" class="nowrap">$2 399.92</td>
 <td align="right" class="nowrap">5.94</td>
 <td align="right" class="nowrap">0.01</td>
 <td align="right" class="nowrap"> <a href="website" onclick="return
 <td align="center">
     <input type="text" tabindex="2" name="productData[price]       
     [{33013477}]" size="10" value="3000.00">    
 </td> 

Я бы использовал getBetween () метод примерно такой:

// Let's assume the "desired output" you acquired 
// is contained within a Text file named "HtmlData.txt".

// Hold our scraped data in a 2D List inteface.
List<List<String>> list = new ArrayList<>();

// Read File using BufferedReader in a Try With Resources block...
try (BufferedReader reader = new BufferedReader(new FileReader("HtmlData.txt"))) {
    String line;
    List<String> numbers = null;
    while ((line = reader.readLine()) != null) {
        numbers = new ArrayList<>();
        line = line.trim();
        if (line.equals("")) {
            continue;
        }
        if (line.startsWith("onclick=\"doWindow(this.href,")) {
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (line.endsWith("return")) {
                    list.add(numbers);
                    break;
                }
                if (line.equals("")) {
                    continue;
                }
                if (line.startsWith("<td align=\"right\" class=\"nowrap\">")) {
                    numbers.add(getBetween(line, "<td align=\"right\" class=\"nowrap\">", "</td>", true, true)[0]);
                }
            }
        }
        if (line.contains("name=\"productData[price]")) {
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (line.equals("")) {
                    continue;
                }
                if (line.startsWith("[{33013477}]")) {
                    numbers.add("Product Price: " + getBetween(line, "value=\"", "\">", true, true)[0]);
                    list.add(numbers);
                    break;  // DONE
                }
            }
        }
    }
    if (numbers != null && !numbers.isEmpty()) {
        list.add(numbers);
    }
}
catch (IOException ex) {
    ex.printStackTrace();
}

// Display our findings to the Console Window in a 
// table style format:
for (int i = 0; i < list.size(); i++) {
    for (int j = 0; j < list.get(i).size(); j++) {
        System.out.printf("%-10s ", list.get(i).get(j));
    }
    System.out.println("");
}

Если вы не заметили, другая часть, которую вы хотите из строк:

<td align="center">
    <input type="text" tabindex="2" name="productData[price]       
    [{33013477}]" size="10" value="3000.00">    
</td>

, также содержалась внутриданные файла.Когда код будет запущен, вы увидите следующее окно консоли:

10 000     20.48      0.00       $28.65     0.00 %     $894.69    10.11      0.21       
10 000     46.21      0.00       $53.82     0.00 %     $1 151.78  8.01       0.00       
5 000      22.51      0.00       $222.53    0.00 %     $2 399.92  5.94       0.01       
Product Price: 3000.00 
...