2011-12-20 4 views
1

Я соскабливаю веб-сайт для определенных фрагментов информации. Кусок HTML, что я ищу является следующее:Скребок HTML с XPath за один проход

1. <div class="data"> 
2. <a class="anchor" name="123"></a> 
3. <a class="image_link" id="image_id" href="http:/link1"> 
4.  <img class="mainimg" id="456" src="http://link2" alt="description" title="title" > 
5. </a> 
6. </div> 

Веб-страница имеет, конечно, много этих <div class="data">, и я хочу, чтобы очистить все из них следующую информацию:

  • имя = 123 (от линии 2)
  • HREF = link1 (от линии 3)
  • SRC = HTTP: // ссылка2, альт = описание (от линии 4)

Я могу это сделать, но с использованием 3-х различных выражений XPath, например, так:

Object[] o1 = node.evaluateXPath("//div[@class='data']/a/img"); 
Object[] o2 = node.evaluateXPath("//div[@class='data']/a[@class='image_link']"); 
Object[] o3 = node.evaluateXPath("//div[@class='data']/a[@class='anchor']"); 

, а затем получить каждый атрибут, как, например:

((TagNode)o1[i]).getAttributeByName("src"); 

Это работает, но я 3 раза и через три различные и отдельные структуры данных с необходимой мне информацией.

Как я могу оптимизировать это только с 1 выражением xpath? Благодарю.

ответ

0

Возьмите объединение двух выражений:

//div[@class='data']/a/img/@*[name()='src' or name()='alt'] | 
//div[@class='data']/a/@*[(parent::*/@class='image_link' and name()='href') or 
          (parent::*/@class='anchor' and name()='name')] 

Вы также могли бы избежать уродства parent::* разделив второе выражение в двух:

//div[@class='data']/a/img/@*[name()='src' or name()='alt'] | 
//div[@class='data']/a[@class='image_link']/@href | 
//div[@class='data']/a[@class='anchor']/@name 

Любой из этих возвращает набор узлов, содержащий только узлы атрибутов. Вам все равно придется перебирать эти узлы. Выполните XPath в Java, как это (где expression является либо из вышеупомянутых двух):

NodeList node = (NodeList) xpath.evaluate(expression, doc, 
     XPathConstants.NODESET); 
for (int i = 0; i < node.getLength(); i++) { 
    Node attr = node.item(i); 
    System.out.println(attr.getNodeName() + ": " + attr.getNodeValue()); 
} 

Выход:

name: 123 
href: http:/link1 
alt: description 
src: http://link2 

Edit: Я просто заметил, что ваш пример кода ссылки TagNode, так Я подозреваю, что вы действительно можете использовать HTMLCleaner. Вы можете попытаться оценить XPath с помощью встроенных методов HTMLCleaner, но это (по-видимому) не совместимый процессор XPath, поэтому результат непредсказуем. См this post для того, как первая очередь результат HTMLCleaner в W3C DOM Document и оценки XPath с помощью стандартных методов Java:

+0

Объединение двух или более выражений, начиная с '' // скорее всего, потребует двух или более полных обходов дерева XML. Я считаю, что OP спрашивает, есть ли способ выбрать все узлы всего за один проход над деревом XML. –

+0

@DimitreNovatchev - Согласовано. Я думаю, что у ОП есть три проблемы: 1) необходимы множественные выражения; 2) создаются и должны быть проверены несколько структур данных; 3) требуется несколько проходов документа. Мое решение адресовано # 1 и # 2; Я не уверен, что №3 можно решить в одном выражении. –

+0

Прежде всего, спасибо за ответ.Моя главная задача - оптимизировать мой текущий код, так как он занимает около 3 секунд, чтобы проанализировать весь документ с моим текущим подходом. Я попытаюсь использовать объединение выражений, а не использовать HTMLCleaner, чтобы увидеть, есть ли улучшения в производительности. – Henrique

Смежные вопросы