2015-04-04 3 views
-2

я хочу, чтобы получить значение из HTML кода, как это:Grep/СЭД/AWK - извлечение подстроки из HTML кода

<div>Luftfeuchte: <span id="wob_hm">53%</span></div><div>Wind: 

В результате мне нужно только значение: «53»

Как может это можно сделать с помощью средств командной строки linux, таких как grep, awk или sed? Я хочу, чтобы использовать его на малиновом пи ... р

Попытка это не работает:

[email protected]:/home/pi# echo "<div>Luftfeuchte: <span id="wob_hm">53%</span></div><div>Wind:" >> test.txt 
[email protected]:/home/pi# grep -oP '<span id="wob_hm">\K[0-9]+(?=%</span>)' test.txt 
[email protected]:/home/pi# 
+2

Не могли бы вы найти решение, используя подходящий HTML-парсер? Это можно сделать с помощью регулярного выражения, но вам намного лучше научиться использовать что-то вроде perl/python для решения этих проблем. –

+2

Обязательный [не анализировать (x) html с регулярным выражением] (http://stackoverflow.com/a/1732454/7552). –

ответ

0

Поскольку HTML не является плоским текстовый формат, его обработки с плоским текстом инструментов, таких как grep, sed или awk нецелесообразно. Если формат HTML немного меняется (например: если узел span получает другой атрибут или вставляются новые строки), все, что вы построите таким образом, будет иметь тенденцию к разрыву.

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

#!/usr/bin/python3 

import html.parser 
import re 
import sys 

# html.parser.HTMLParser provides the parsing functionality. It tokenizes 
# the HTML into tags and what comes between them, and we handle them in the 
# order they appear. With XML we would have nicer facilities, but HTML is not 
# a very good format, so we're stuck with this. 
class my_parser(html.parser.HTMLParser): 
    def __init__(self): 
     super(my_parser, self).__init__(self) 
     self.data = '' 
     self.depth = 0 

    # handle opening tags. Start counting, assembling content when a 
    # span tag begins whose id is "wob_hm". A depth counter is maintained 
    # largely to handle nested span tags, which is not strictly necessary 
    # in your case (but will make this easier to adapt for other things and 
    # is not more complicated to implement than a flag) 
    def handle_starttag(self, tag, attrs): 
     if tag == 'span': 
      if ('id', 'wob_hm') in attrs: 
       self.data = '' 
       self.depth = 0 
      self.depth += 1 

    # handle end tags. Make sure the depth counter is only positive 
    # as long as we're in the span tag we want 
    def handle_endtag(self, tag): 
     if tag == 'span': 
      self.depth -= 1 

    # when data comes, assemble it in a string. Note that nested tags would 
    # not be recorded by this if they existed. It would be more work to 
    # implement that, and you don't need it for this. 
    def handle_data(self, data): 
     if self.depth > 0: 
      self.data += data 

# open the file whose name is the first command line argument. Do so as 
# binary to get bytes from f.read() instead of a string (which requires 
# the data to be UTF-8-encoded) 
with open(sys.argv[1], "rb") as f: 
    # instantiate our parser 
    p = my_parser() 

    # then feed it the file. If the file is not UTF-8, it is necessary to 
    # convert the file contents to UTF-8. I'm assuming latin1-encoded 
    # data here; since the example looks German, "latin9" might also be 
    # appropriate. Use the encoding in which your data is encoded. 
    p.feed(f.read().decode("latin1")) 

    # trim (in case of newlines/spaces around the data), remove % at the end, 
    # then print 
    print(re.compile('%$').sub('', p.data.strip())) 

Добавление: Вот портировать на Python 2, bulldozes прямо над проблемами кодирования. Для этого случая это, возможно, лучше, потому что кодирование не имеет значения для данных, которые мы хотим извлечь, и вам не нужно заранее знать кодировку входного файла. Изменения незначительны, и способ, которым он работает, точно такой же:

#!/usr/bin/python 

from HTMLParser import HTMLParser 
import re 
import sys 

class my_parser(HTMLParser): 
    def __init__(self): 
     HTMLParser.__init__(self) 
     self.data = '' 
     self.depth = 0 

    def handle_starttag(self, tag, attrs): 
     if tag == 'span': 
      if ('id', 'wob_hm') in attrs: 
       self.data = '' 
       self.depth = 0 
      self.depth += 1 

    def handle_endtag(self, tag): 
     if tag == 'span': 
      self.depth -= 1 

    def handle_data(self, data): 
     if self.depth > 0: 
      self.data += data 

with open(sys.argv[1], "r") as f: 
    p = my_parser() 
    p.feed(f.read()) 
    print(re.compile('%$').sub('', p.data.strip())) 
+0

Thx для ответа, но пытается это я получаю: корень @ raspberrypi:/дома/пи/Grep-Google всепогодный # ./test.py test.html Traceback (самый последний вызов последнего): Файл». /test.py ", строка 46, в p.feed (f.read()) Файл« /usr/lib/python3.2/codecs.py », строка 300, в декоде (результат, потребляется) = self._buffer_decode (data, self.errors, final) UnicodeDecodeError: кодек «utf-8» не может декодировать байт 0xfc в позиции 16022: недопустимый стартовый байт – fhammer

+0

iso8859-кодированные данные, а? См. Редактирование. Это небольшое изменение в конце, чтобы декодировать содержимое файла, прежде чем передавать их в html.parser.HTMLParser, который, по-видимому, требует UTF-8 в Python 3. Я могу вернуться, чтобы портировать его на Python 2 позже, что, я думаю, обрабатывает это больше изящно, но мне нужно спать до этого. – Wintermute

+0

Э-э, я сразу же сделал бэкпорт python 2. Оказалось, что почти не требуется никаких изменений, а python 2 'HTMLParser' имеет (для этого случая) приятное свойство не заботиться о кодировании. Я немного недоволен тем, что это было удалено без замены на python 3, если честно. – Wintermute

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