Уведомления

Группа в Telegram: @pythonsu

#1 Май 20, 2017 15:24:44

grapefruit_ocean
Зарегистрирован: 2016-01-31
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг HTML

Здравствуйте! Помогите новичку, пожалуйста.
Предположим, есть html-код страницы вида:

<span> … <\span>
… (здесь могут быть любые другие теги)
<div> … <\div>
<table> … <\table>

<span> … <\span>
Мне нужно извлечь таблицу (или таблицы, если их несколько), которые находятся между двумя тегами <span>. Все теги находятся на одном уровне.
Подскажите, пожалуйста, как это сделать?

Офлайн

#2 Май 20, 2017 16:10:15

vic57
Зарегистрирован: 2015-07-07
Сообщения: 913
Репутация: +  127  -
Профиль  

Парсинг HTML

примерно так:

 from lxml import html, etree
 
def get_html(file_name,tag,subtag):
    tree = html.parse(file_name)
    nodes =  tree.xpath(tag)
    out = []
    for node in nodes:
        subnode = node.findall(subtag)
        tmp = []
        for sb in subnode:
            t = sb.text
            if t: tmp.append(t)
        if len(tmp):
            out.append(tmp)
    return out
out = get_html('0000.html','//tr','td')
for i in out:
    print ' '.join(i)
работает для
<table>
<tr><td></td>…</tr>
</table>

Отредактировано vic57 (Май 20, 2017 16:10:27)

Офлайн

#3 Май 20, 2017 16:52:48

grapefruit_ocean
Зарегистрирован: 2016-01-31
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг HTML

vic57
примерно так:
У вас теги вложены друг в друга, а у меня они все на одном уровне. Не смогла придумать, как адаптировать ваш код к моей задаче(

Допустим, мы нашли все <table> в документе. Тогда задачу можно переформулировать так: как узнать, находится ли конкретная <table> выше последнего <span> в коде? Если да, то извлекаем её, если нет - отбрасываем.

Отредактировано grapefruit_ocean (Май 20, 2017 16:57:17)

Офлайн

#4 Май 20, 2017 17:04:26

vic57
Зарегистрирован: 2015-07-07
Сообщения: 913
Репутация: +  127  -
Профиль  

Парсинг HTML

каким образом тэги могут быть на одном уровне?
между <table></table> у вас что?
http://tinman.cs.gsu.edu/~raj/8711/sp04/xpath/Output_rus/

Отредактировано vic57 (Май 20, 2017 17:14:05)

Офлайн

#5 Май 20, 2017 17:14:38

grapefruit_ocean
Зарегистрирован: 2016-01-31
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг HTML

vic57
каким образом тэги могут быть на одном уровне?между <table></table> у вас что?
<span> и <table> на одном уровне. В идеале мне нужно получить именно объект <table>

Офлайн

#6 Май 20, 2017 17:34:06

vic57
Зарегистрирован: 2015-07-07
Сообщения: 913
Репутация: +  127  -
Профиль  

Парсинг HTML

http://htmlbook.ru/html/table

out = get_html("0000.html","//table/tr","td")
или
out = get_html("0000.html","//span/table/tr","td")
покажите структуру документа, непонятно излагаете

Отредактировано vic57 (Май 20, 2017 17:40:40)

Офлайн

#7 Май 20, 2017 17:51:54

grapefruit_ocean
Зарегистрирован: 2016-01-31
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг HTML

Полностью не могу показать, документ большой, но примерно так:

 <html>
     <body>
         <span1 lang = "az"> ... </span1><div></div>
         <table1></table1><table2> ... </table2>
         <span2 lang = "en"></span2>
         <table3> ... </table3>
    </body>
</html>
И я хочу получить только те таблицы, что идут перед <span2>, т.е. <table1> и <table2>. К сожалению, нет каких-либо атрибутов, которые эти таблицы определяли бы. Т.е., пока я вижу только один способ извлечь именно их: по атрибуту lang=“en” найти <span2> и взять таблицы, что находятся над ним. Но учитывая, что теги <span>, <table> и прочие находятся на одном уровне, я не представляю, как это реализовать(

Отредактировано grapefruit_ocean (Май 20, 2017 17:52:22)

Офлайн

#8 Май 20, 2017 18:29:32

vic57
Зарегистрирован: 2015-07-07
Сообщения: 913
Репутация: +  127  -
Профиль  

Парсинг HTML

понятно. ну путь такой

 from lxml import html,etree
doc='''
 <html>
     <body>
         <span lang = "az"> ... </span>
         <div> … </div>
         <table><tr><td>1</td></tr></table>
         <table><tr><td>1</td></tr></table>
         <span lang = "en"> … </span>
         <table> ... </table>
    </body>
</html>
'''
def get_html(file_name,tag):
    tree = html.fromstring(file_name)
    nodes =  tree.xpath(tag)
    for i in nodes:
        print i.tag,i.attrib,i.sourceline
        
    
out = get_html(doc,'//body/*')
 
дальше можно по аттрибуту/номеру строки - пример xpath/count.

Отредактировано vic57 (Май 20, 2017 18:31:19)

Офлайн

#9 Май 20, 2017 18:31:08

grapefruit_ocean
Зарегистрирован: 2016-01-31
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг HTML

Справилась таким образом:

 text = BeautifulSoup(t, 'lxml')
first_el = text.findAll('span', id="Az.C9.99rbaycan_dili")[0].parent # это <span1> (вместо lang - id)
other_lang_id = re.compile('.+_dili')			                               # шаблон для поиска отличных id
languages = text.findAll('span', id=other_lang_id)                          # находим все id по этому шаблону
for l in languages:                                                                           # если какое-то из них отлично от первого, то берём тег и прерываем цикл (это будет <span2>)
	if l['id'] != "Az.C9.99rbaycan_dili":
		other_lang = l.parent
		break
all_tables = text.findAll('table', rules="all")                                      # находим все таблицы
all_tables.extend(text.findAll('table', attrs={"class": "inflection-table"}))
tables = []
for child in text.descendants:                                                        # используя итератор descendants из BeautifulSoup, спускаемся до <span2> и прерываем цикл как только доходим до него
	if child != other_lang:
		for table in all_tables:
			if child == table:
				tables.append(child)
	else:
		break
Вроде бы работает

Отредактировано grapefruit_ocean (Май 20, 2017 18:31:26)

Офлайн

#10 Май 20, 2017 18:32:05

grapefruit_ocean
Зарегистрирован: 2016-01-31
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг HTML

Ваш вариант выглядит явно проще) Пойду его пробовать

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version