разбор Html

Тема в разделе "Lotus - Программирование", создана пользователем Gor, 24 сен 2009.

  1. Gor

    Gor Well-Known Member

    Регистрация:
    7 июн 2005
    Сообщения:
    517
    Симпатии:
    2
    Всем доброго время суток.

    Есть такая задача:
    локально лежат html файлы. Из каждого html-а надо вытащить большую таблицу и сохранить к примеру в csv.
    т.е. по сути дела мне надо в этом html файле найти нужную таблицу, перегнать все данные в массив ну а далее в csv.

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

    Нашёл курс валют как получить из интернета вроде бы похожая задача, но там надо всего получить 2 значения, а у меня всё таки большая таблица.

    Попробовал получить html таким образом:
    Код (Text):
                    Set xml = CreateObject("Microsoft.XMLHTTP")
    Call xml.open("GET", "\\SERVER\UDV10031\123JIO\Desktop\Templates\Doc_1.html",False)

    Call xml.send()
    HtmlText$= xml.responseText
    Ругается - Object automation Error
    В общем Нид Хелп) Если будет какой нибудь пример разбора Html буду очень признателен.
     
  2. Omh

    Omh Lotus team
    Lotus team

    Регистрация:
    4 июл 2007
    Сообщения:
    2.210
    Симпатии:
    0
    А что-то вроде открыть файл NotesStream'ом и распарсить содеожимое, не?
     
  3. Gor

    Gor Well-Known Member

    Регистрация:
    7 июн 2005
    Сообщения:
    517
    Симпатии:
    2
    Уже да :) Видимо мне хотелось моральной поддержки)

    А разбор html таблицы вести тупо в цикле где будут описаны вхождения в строки с тегами?
     
  4. K-Fire

    K-Fire Гость

    Для таких задач надо использовать XSLT
     
  5. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.373
    Симпатии:
    2
    либо, чтобы не париться с самим XSL, пройтись по потоку с пом SAX парсера (NotesSax...)
     
  6. Gor

    Gor Well-Known Member

    Регистрация:
    7 июн 2005
    Сообщения:
    517
    Симпатии:
    2
    to: Akupaka
    А есть какой нибудь пример с использованием NotesSaxParser?
    Как считывать значения, вести поиск нужного итд?
    Никогда с ним не работал, а в хелпе всё не так очевидно...
     
  7. Omh

    Omh Lotus team
    Lotus team

    Регистрация:
    4 июл 2007
    Сообщения:
    2.210
    Симпатии:
    0
    Кстати, я тоже с колько уже с лотусом работаю, ни разу не использовал SAXParser.
    Всё как-то через DOMParser.
    Насколько я помню, SAX при больших объёмах быстрее гораздо был.
     
  8. turumbay

    Регистрация:
    13 мар 2009
    Сообщения:
    625
    Симпатии:
    2
    С большой вероятностью технологии, связанные с XML, не прокатят.
    Валидные html встречаются нечасто - незакрытые параграфы, объявления аттрибутов несовместимые с xml и т.п. Плюс кодировка...
    Допишите в начало html файла <?xml version="1.0"?> и убедитесь, что файл корректно открывается браузером и строится дерево.
    И если он таки открылся - можно начинать думать про xml. Чем пользоваться для парсинга - вопрос религии, я лично предпочитаю xslt.

    Да, SAX шустрее, т.к. не строит дерево. А dom parser использует sax parser.
     
  9. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.373
    Симпатии:
    2
    я по хелпу учился :) там достаточно муторно, но разобраться можно...
    примера у меня с собой нет, а писать чесгря лениво.
    вкратце, есть два парсера XML: DOM, SAX.
    DOM - строит дерево объектов, и чтобы найти нужный нужно пройти от корня до искомого объекта. как HTML DOM.
    если структура у всех доков одинаковая, то можно сделать прямой код поиска объекта.
    пример,
    Код (Text):
    <XML>
    <doc>
    <text1>
    This this hard code!
    </text1>
    </doc>
    тогда определение нужного объекта с пом DOM будет выглядеть приблизительно так (куски кода вырваны из хелпа и сгенерены в уме без проверки):

    Код (Text):
    To access the document node for an existing DOM tree, use the Process method to generate the DOM tree. Then use the Document property to access the document node. For example:

    Dim domparser As NotesDOMParser
    Dim domdoc As NotesDOMDocumentNode
    dim domtext1 as notesDOMNode
    dim text1 as string

    Set domParser = session.CreateDOMParser(inputStream, outputStream) ' получили поток из какого-то ресурса inputStream, см NotesStream

    Call domParser.Process ' получили DOM
    Set domdoc = domparser.Document ' получаем, по-идее, doc
    Set domtext1 = notesDOMNode.FirstChild ' получаем, по-идее, text1
    text1 = domtext1.FirstChild.NodeValue ' по-идее, текст, который находится в сущности <text1> является объектом типа NotesDOMTextNode, у которого мы смело берем значение NodeValue
    если же документ может иметь первый вид, а может и другой:
    Код (Text):
    <XML>
    <doc>
    <text2>
    This this hard code TEXT2!
    </text2>
    <text1>
    This this hard code!
    </text1>
    </doc>
    то первый вариант кода нам вернет не то, что нам надо... и тут уже надо обходить дерево для поиска необходимой сущности по имени тега.
    пример кода смотри в справке, там многа писать :) (ищи Examples: ParentNode property)


    в свою очередь SAX работает как бы событийно. т.е. фактически он сам запускает проход по всем! сущностям дока, а ты лишь дописываешь обработчик событий, а что, если тег (сущность) такой-то.
    по САКСу один большой пример в справке Examples: NotesSAXParser class, по нему немного и скажу.
    в твоем случае, тебя интересует обработчик
    Код (Text):
    On Event SAX_StartElement From saxParser Call SAXStartElement
    т.е. этот обработчик срабатывает тогда, когда парсер натыкается на тег, например <text2>, <text1>...
    еще тебя будет интересовать обработчик события когда парсер натыкается на окончание тега
    Код (Text):
    On Event SAX_EndElement From saxParser Call SAXEndElement
    я в свое время обходился этими двумя :)
    еще пригодится могут события SAX_Error и SAX_FatalError.
    оу... забыл главное :)
    Код (Text):
    On Event SAX_Characters From saxParser Call SAXCharacters
    этот обработчик будет читать значения текстовых узлов

    теперь как же нам поставить корректно обработку с пом САКС. я делал с помощью флагов.
    приблизительно поиск значения узла в <text1> по второму фрагменту должен быть приблизительно таким

    Код (Text):
    globals
    dim bText1 as boolean

    Sub SAXCharacters (Source As Notessaxparser, Byval Characters As String, _
    Count As Long)

    if bText1 then
    Messagebox "TEXT1 Characters found: " Characters
    end if
    End Sub

    Sub SAXStartElement (Source As Notessaxparser,_
    Byval elementname As String, Attributes As NotesSaxAttributeList)

    if elementname = "text1" then
    bText1 = true
    end if

    End Sub

    Sub SAXEndElement (Source As Notessaxparser, Byval ElementName As String)
    if elementname = "text1" then
    bText1 = false
    end if
    End Sub
    в твоем конечном случае это будет не такой простой и маленький код ;)
    а если хочешь все быстрее и красивее, твой путь лежит через тернии XSLT :)

    по-идее, можно использовать валидатор объектов нотеса, только дописывать <?xml придется все-равно, но, вроде, можно это вписать в поток, и руци не марать :)
     
  10. turumbay

    Регистрация:
    13 мар 2009
    Сообщения:
    625
    Симпатии:
    2
    Да я не саму задачу валидации имел в виду, а то, что возможно использование технологий xml неприменимо к данной задаче...
    А простой способ понять - использовать XML или нет - просто открыть док браузером как xml.


    З.Ы. Старожилы закидают камнями за такой вариант, но все же:
    Судя по коду, на машине windows. А ёксель там часом не установлен? OLE: Открыть файл екселем, save as csv. Финиш.
     
  11. Yakov

    Yakov Гость

    Не надо много писать и обходить ничего не надо. См. notesDOMDocument.GetElementsByTagName( elementName ).

    По теме ищите в гугле java html parser. Кроме всего прочего найдете http://java.sun.com/j2se/1.4.2/docs/api/ja...ge-summary.html, то есть, задачу можно сделать без дополнительных библиотек начиная с версии 7.0 Лотуса.
     
  12. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.373
    Симпатии:
    2
    где ты был, когда я этому учился?! :)
     
  13. Yakov

    Yakov Гость

    Akupaka, я этому учился на Java, там справка (javadoc) удобней.
     
  14. Gor

    Gor Well-Known Member

    Регистрация:
    7 июн 2005
    Сообщения:
    517
    Симпатии:
    2
    to Akupaka:

    Спасибо, более менее понятно.
    НО т.к. у меня html, попробовал пользоваться Start и EndElement. Но по сути дела это не принесёт особого результата.

    html у меня достаточно большой и по имени тега по сути дела искать практически бесполезно. (тегов с одинаковыми названиями ооочень уж много)
    Чтобы брать значения из определённых ячеек мне надо каждый раз при попадании в элемент проверять содержит ли он такую фразу?
    т.е. в событии
    Sub SAXCharacters (Source As Notessaxparser, Byval Characters As String, _
    Count As Long)

    Делать проверку каждого элемента? - наподобии if @Contains(Character,"блаблабла") Then ....?

    на примере предположим есть вот такая часть файла

    Код (Text):
    <tr>

    <td rowspan="3" style="vertical-align:top; text-align:left; font-size:9pt; border-width: 1;border-style: solid;border-color: Black; height:3.7cm;padding:0.1cm;"><strong>Кому:</strong> ЦЦЦЦЦЦЦ<br>Иванов Иван Иванович<br><strong>Куда:</strong> ЧЧЧ ул,ЧЧЧЧ <br><strong>127473</strong><br><strong>Лицевой счет: </strong>277340553057 (ГенД)<br>7:1:900-15<br></td>

    <td style="font-size:10pt; vertical-align:middle; text-align:center">от 31.08.2009<br>за услуги предприятия<br>Открытое акционерное общество "Мобильные ТелеСистемы" / ОАО "МТС"<br>за период с 01.08.2009 по 31.08.2009<br>Оплатить до: 24.09.2009</td>

    </tr>
    <tr>
    <td style="font-weight: bold; font-size: 14pt; text-align:center;">Лицевой счет абонента № 277340553057</td>
    </tr>
    </table>
    мне отсюда надо вытащить лицевой счёт абонента, а этот кусок в середине файла зашит.
    т.е. получается если я использую SAXParser надо проверять Character каждого элемента на содержание в нём фразы Лицевой счёт абонента ????
     
  15. amigolinx

    amigolinx Гость

    если данных по лицевым счетам много, то можно так:
    1. зачитать содержимое файла в NotesStream
    2. сделать Split по фразе например "Лицевой счёт абонента"
    3. на выходе - массив, в котором каждый элемент начиная с 1, будет содержать номер счета
    4. потом можно обращаться к элементу и обрезать уже сам номер при помощи ф-ий типа StrLeft/StrRight

    если он один на весь файл, то и еще проще - без Split можно обойтись...
     
  16. Gor

    Gor Well-Known Member

    Регистрация:
    7 июн 2005
    Сообщения:
    517
    Симпатии:
    2
    Вытащить на самом деле из файла надо данные в 5-6 местах по ключевым фразам. + большую таблицу вида:

    Код (Text):
    ..............
    <tr style="font-weight: normal; font-size: 7pt;">

    <td>17.08.2009</td>

    <td>13:32:01</td>

    <td align="left">&lt;--+79037011111</td>

    <td align="left"></td>

    <td align="left"></td>

    <td align="left">sms i</td>

    <td></td>

    <td align="right">1</td>

    <td align="right">0.0000</td>

    </tr>

    <tr style="font-weight: normal; font-size: 7pt;">

    <td>17.08.2009</td>

    <td>13:45:12</td>

    <td align="left">+79627068276</td>

    <td align="left"></td>

    <td align="left"></td>

    <td align="left">sms o</td>

    <td></td>

    <td align="right">1</td>

    <td align="right">1.6525</td>

    </tr>

    <tr style="font-weight: normal; font-size: 7pt;">

    <td>17.08.2009</td>

    <td>13:45:33</td>

    <td align="left">&lt;--+79037011111</td>

    <td align="left"></td>

    <td align="left"></td>

    <td align="left">sms i</td>

    <td></td>

    <td align="right">1</td>

    <td align="right">0.0000</td>

    </tr>
    ........................
    перегнать в массив
     
  17. amigolinx

    amigolinx Гость

    если я правильно понимаю задачу, то исключая всякие клинические случаи, эти ключевые фразы всегда ж одного четко заданного вида? поэтому я бы делал жесткий поиск по ним и забирал бы идущее за ними значение по определенным ориентирам с использованием LS2J (там есть реализация регекспов) или тупо по паттернам в лотусовых стринговых функциях. а вот таблицу имхо не в массив лучче пихать, а в List (проще с ListTag потом будет работать)
    и кстати, LS2J а именно JakartaOroWrapper ой как харашо вписывается сюда - там даже в примерах использования либы есть обработка строк с html-тегами (вытащить значения между тегов и т.п.)
     
  18. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.373
    Симпатии:
    2
    Gor
    что я могу сказать... есть золотое правило разработки: отделяй данные от представления этих самых данных!
    работать с данными в виде для представления - себе дороже. нет ли возможности получать всю ту инфу в виде нормальной структуры (XML) или хотя бы с идентификаторами элементов в представлении?..
     
  19. Gor

    Gor Well-Known Member

    Регистрация:
    7 июн 2005
    Сообщения:
    517
    Симпатии:
    2
    Код (Text):
    нет ли возможности получать всю ту инфу в виде нормальной структуры (XML) или хотя бы с идентификаторами элементов в представлении?..
    Нет. Есть только html-ник. Структура то у него определённая есть, но работать с ней всё равно достаточно тяжело.

    Ещё назрел такой вопрос - Предположим я хочу свой поток разделить на части (чтобы с какой то частью потока работать как со строкой, а с другой табличной частью парсером)
    Поток определяется:
    Код (Text):
        Set stream = session.CreateStream
    If Not stream.Open("\\Имя файла","UTF-8") Then
    Msgbox "Cannot open Имя файла.html", , "Error"
    Exit Sub
    End If
    If stream.Bytes = 0 Then
    Msgbox "File did not exist or was empty", , FileName$
    Exit Sub
    End If
    Я хочу получить два потока:
    Один - от начала файла до заглавия страницы БлаБлаБла, второй после заглавия страницы БлаБлаБла

    Как это можно сделать?
     
  20. amigolinx

    amigolinx Гость

    Код (Text):
    var1 = Strleft(stream.ReadText, {до заглавия страницы БлаБлаБла}) & {до заглавия страницы БлаБлаБла}  ' это если заглавие тоже нужно
    var2 = {после заглавия страницы БлаБлаБла} & StrRight(stream.ReadText, {после заглавия страницы БлаБлаБла})
     
Загрузка...

Поделиться этой страницей