Разбор скрытых элементов в статическом html-файле с использованием Python Lxml - PullRequest
0 голосов
/ 06 декабря 2018

У меня есть набор статических HTML-файлов, которые мне нужно проанализировать и извлечь некоторые детали. Я использую модуль Python-lxml для получения необходимых деталей. Пример статического html-файла показан ниже:

<div class="top">
<a data-bind="text">abc</a>
<span data-bind="visible:hotel.marca1!='' &amp;&amp; hotel.marca1!='logo_ha', attr:{title:hotel.textoMarca1}" title="Hotusa" style="display: none;">
    </span>
<span class="marca" data-bind="visible:hotel.marca1==='' || hotel.marca1==='logo_ha'">
    </span>
<span class="star sprite-disponibilidad star1" data-bind="visible:hotel.cat === '1'" style="display: none;"></span>
<span class="star sprite-disponibilidad star2" data-bind="visible:hotel.cat === '2'" style="display: none;"></span>
<span class="star sprite-disponibilidad star3" data-bind="visible:hotel.cat === '3'" style="display: none;"></span>
<span class="star sprite-disponibilidad star4" data-bind="visible:hotel.cat === '4'"></span>
<span class="star sprite-disponibilidad star5" data-bind="visible:hotel.cat === '5'" style="display: none;"></span>
<div class="adr">
    <span></span>
    <span class="locality" data-bind="text: hotel.pob"></span>
</div>
</div>

<div class="top">
<a data-bind="text">dfg</a>
<span data-bind="visible:hotel.marca1!='' &amp;&amp; hotel.marca1!='logo_ha', attr:{title:hotel.textoMarca1}" title="Hotusa" style="display: none;">
    </span>
<span class="marca" data-bind="visible:hotel.marca1==='' || hotel.marca1==='logo_ha'">
    </span>
<span class="star sprite-disponibilidad star1" data-bind="visible:hotel.cat === '1'" style="display: none;"></span>
<span class="star sprite-disponibilidad star2" data-bind="visible:hotel.cat === '2'" style="display: none;"></span>
<span class="star sprite-disponibilidad star3" data-bind="visible:hotel.cat === '3'" style="display: none;"></span>
<span class="star sprite-disponibilidad star4" data-bind="visible:hotel.cat === '4'" style="display: none;"></span>
<span class="star sprite-disponibilidad star5" data-bind="visible:hotel.cat === '5'" style="display: none;"></span>
<div class="adr">
    <span></span>
    <span class="locality" data-bind="text: hotel.pob"></span>
</div>

Итак, вот проблема, мне нужно получить рейтинг звезды из видимого элемента span class = 'star';например, в первом div [@top] рейтинг звезды видимого промежутка равен '4', в то время как второй div [@top] не имеет видимого элемента span [class = star], поэтому он должен вернутьзвездный рейтинг «0».Однако, поскольку эти элементы скрыты, у меня проблема с извлечением их, а также с тем, чтобы скрипт возвращал «0» звездных оценок для элемента div, который имеет весь span [@ class = star] «hidden».

Это то, что я пробовал до сих пор:

tree = html.fromstring(page)
for sali in tree.xpath('//div[@class="top"]'):
    for x in sali.xpath('a'):
        for sal in sali.xpath('span[not(contains(@style,"display:none"))]'): 
            print x , sal.attrib['data-bind']

Но этот код не помогает мне с желаемым результатом, какую ошибку я делаю?

Ожидаемый результат: abc 4 dfg 0

Ответы [ 2 ]

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

Вы можете использовать lxml через BeautifulSoup.Кто-то, более знакомый с Python, может привести в порядок это

from bs4 import BeautifulSoup

html = '''
<div class="top">
<a data-bind="text">abc</a>
<span data-bind="visible:hotel.marca1!='' &amp;&amp; hotel.marca1!='logo_ha', attr:{title:hotel.textoMarca1}" title="Hotusa" style="display: none;">
    </span>
<span class="marca" data-bind="visible:hotel.marca1==='' || hotel.marca1==='logo_ha'">
    </span>
<span class="star sprite-disponibilidad star1" data-bind="visible:hotel.cat === '1'" style="display: none;"></span>
<span class="star sprite-disponibilidad star2" data-bind="visible:hotel.cat === '2'" style="display: none;"></span>
<span class="star sprite-disponibilidad star3" data-bind="visible:hotel.cat === '3'" style="display: none;"></span>
<span class="star sprite-disponibilidad star4" data-bind="visible:hotel.cat === '4'"></span>
<span class="star sprite-disponibilidad star5" data-bind="visible:hotel.cat === '5'" style="display: none;"></span>
<div class="adr">
    <span></span>
    <span class="locality" data-bind="text: hotel.pob"></span>
</div>
</div>

<div class="top">
<a data-bind="text">dfg</a>
<span data-bind="visible:hotel.marca1!='' &amp;&amp; hotel.marca1!='logo_ha', attr:{title:hotel.textoMarca1}" title="Hotusa" style="display: none;">
    </span>
<span class="marca" data-bind="visible:hotel.marca1==='' || hotel.marca1==='logo_ha'">
    </span>
<span class="star sprite-disponibilidad star1" data-bind="visible:hotel.cat === '1'" style="display: none;"></span>
<span class="star sprite-disponibilidad star2" data-bind="visible:hotel.cat === '2'" style="display: none;"></span>
<span class="star sprite-disponibilidad star3" data-bind="visible:hotel.cat === '3'" style="display: none;"></span>
<span class="star sprite-disponibilidad star4" data-bind="visible:hotel.cat === '4'" style="display: none;"></span>
<span class="star sprite-disponibilidad star5" data-bind="visible:hotel.cat === '5'" style="display: none;"></span>
<div class="adr">
    <span></span>
    <span class="locality" data-bind="text: hotel.pob"></span>
</div>
'''

soup = BeautifulSoup(html, 'lxml')
ratings = []
for item in soup.select("div.top"):
    hotel = item.select_one('a').text
    found = False
    for item2 in item.select("[data-bind*='visible:hotel.cat']"):
        try:
            style = item2['style']
        except KeyError as e:
            rating = item2['data-bind'].strip("visible:hotel.cat === ").strip("'")
            found = True
            break
    ratings.append([hotel + ' ' + rating if found else hotel + ' 0'])
print(ratings)

Вывод:

enter image description here

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

Существует несколько способов решения проблемы, и вот один из способов ее решения: получить элементы рейтинга «звезда» и вернуть индекс первого «видимого» элемента, падающий до 0, если ничего не найдено.Мы можем использовать next() и enumerate() для достижения этого:

def is_visible(element):
    """Naive implementation of the element visibility check."""
    return 'display: none;' not in element.attrib.get("style", "")


def get_rating(entry):
    rating_elements = entry.xpath(".//span[contains(@class, 'star')]")
    visibile_rating = (index 
                       for index, element in enumerate(rating_elements, start=1)
                       if is_visible(element))
    return next(visibile_rating, 0)


root = fromstring(html)
for sali in root.xpath('//div[@class="top"]'):
    for x in sali.xpath('a'):
        print(x.text, get_rating(sali))

Отпечатки:

('abc', 4)
('dfg', 0)

Осторожноиз-за того, что атрибут class является многозначным атрибутом и, строго говоря, contains() не лучший инструмент для поиска элемента по значению класса:

...