Проблемы с получением правильных значений для каждого элемента - PullRequest
0 голосов
/ 07 мая 2018

Я пытаюсь разобрать элемент names, и он соответствует values из приведенного ниже фрагмента. Тег dt содержит names и dd, содержащие values. Есть несколько тегов dt, которые не имеют соответствующих values. Итак, все names не имеют values. Что я хочу сделать, так это оставить пустым values против любого name, если у последнего нет значений.

Вот элементы, из которых я хотел бы очистить данные:

content="""
<div class="movie_middle">
    <dl>
        <dt>Genres:</dt> 
        <dt>Resolution:</dt> 
        <dd>1920*1080</dd> 
        <dt>Size:</dt> 
        <dd>1.60G</dd> 
        <dt>Quality:</dt> 
        <dd>1080p</dd> 
        <dt>Frame Rate:</dt> 
        <dd>23.976 fps</dd> 
        <dt>Language:</dt>
    </dl>
</div>
"""

Я пробовал, как показано ниже:

soup = BeautifulSoup(content,"lxml")
title = [item.text for item in soup.select(".movie_middle dt")]
result = [item.text for item in soup.select(".movie_middle dd")]
vault = dict(zip(title,result))
print(vault)

Это дает мне грязные результаты (неправильные пары):

{'Genres:': '1920*1080', 'Resolution:': '1.60G', 'Size:': '1080p', 'Quality:': '23.976 fps'}

Мой ожидаемый результат:

{'Genres:': '', 'Resolution:': '1920*1080', 'Size:': '1.60G', 'Quality:': '1080p','Frame Rate:':'23.976 fps','Language:':''}

Любая помощь по устранению проблемы будет высоко оценена.

Ответы [ 4 ]

0 голосов
/ 08 мая 2018

Вы можете перебрать элементы внутри dl.Если текущий элемент dt, а следующий элемент dd, сохраните значение в качестве следующего элемента, в противном случае установите значение в виде пустой строки.

dl = soup.select('.movie_middle dl')[0]
elems = dl.find_all()  # Returns the list of dt and dd
data = {}
for i, el in enumerate(elems):
    if el.name == 'dt':
        key = el.text.replace(':', '')

        # check if the next element is a `dd`
        if i < len(elems) - 1 and elems[i+1].name == 'dd':
            data[key] = elems[i+1].text
        else:
            data[key] = ''
0 голосов
/ 08 мая 2018

Проблема в том, что пустых элементов нет.Поскольку между <dt> и <dd> нет никакой иерархии, я боюсь, что вам придется создавать словарь самостоятельно.

vault = {}
category = ""
for item in soup.find("dl").findChildren():
    if item.name == "dt":
        if category == "":
            category = item.text
        else:
            vault[category] = ""
            category = ""
    elif item.name == "dd":
        vault[category] = item.text
        category = ""


По сути, этот код перебирает дочерние элементы<dl> и заполняет словарь vault значениями.

0 голосов
/ 08 мая 2018

Вы можете использовать BeautifulSoup для анализа структуры dl, а затем написать функцию для создания словаря:

from bs4 import BeautifulSoup as soup 
import re
def parse_result(d):
  while d:
    a, *_d = d
    if _d:
      if re.findall('\<dt', a) and re.findall('\<dd', _d[0]):
        yield [a[4:-5], _d[0][4:-5]]
        d = _d[1:]
      else:
        yield [a[4:-5], '']
        d = _d
    else:
      yield [a[4:-5], '']
      d = []

print(dict(parse_result(list(filter(None, str(soup(content, 'html.parser').find('dl')).split('\n')))[1:-1])))

Выход:

{'Genres:': '', 'Resolution:': '1920*1080', 'Size:': '1.60G', 'Quality:': '1080p', 'Frame Rate:': '23.976 fps', 'Language:': ''}

Для немного более длинного, хотя и более чистого решения, вы можете создать декоратор для удаления тегов HTML выходных данных, что устраняет необходимость дополнительной нарезки строк в основной функции parse_result:

def strip_tags(f):
  def wrapper(data):
     return {a[4:-5]:b[4:-5] for a, b in f(data)}
  return wrapper

@strip_tags
def parse_result(d):
  while d:
    a, *_d = d
    if _d:
      if re.findall('\<dt', a) and re.findall('\<dd', _d[0]):
        yield [a, _d[0]]
        d = _d[1:]
      else:
        yield [a, '']
        d = _d
    else:
      yield [a, '']
      d = []

print(parse_result(list(filter(None, str(soup(content, 'html.parser').find('dl')).split('\n')))[1:-1]))

Выход:

{'Genres:': '', 'Resolution:': '1920*1080', 'Size:': '1.60G', 'Quality:': '1080p', 'Frame Rate:': '23.976 fps', 'Language:': ''}
0 голосов
/ 08 мая 2018
from collections import defaultdict 
test = soup.text.split('\n')   
d = defaultdict(list)
for i in range(len(test)):
     if (':' in test[i]) and (':' not in test[i+1]):
         d[test[i]] = test[i+1]
     elif ':' in test[i]:
         d[test[i]] = ''


d
defaultdict(list,
            {'Frame Rate:': '23.976 fps',
             'Genres:': '',
             'Language:': '',
             'Quality:': '1080p',
             'Resolution:': '1920*1080',
             'Size:': '1.60G'})

Логика здесь в том, что вы знаете, что у каждого ключа будет двоеточие. Зная это, вы можете написать оператор if else для захвата уникальных комбинаций, будь то key с последующим key или key с последующим value

Edit:

Если вы хотите почистить ключи, ниже заменяется : на каждый:

d1 = { x.replace(':', ''): d[x] for x in d.keys() }
d1
{'Frame Rate': '23.976 fps',
 'Genres': '',
 'Language': '',
 'Quality': '1080p',
 'Resolution': '1920*1080',
 'Size': '1.60G'}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...