В настоящее время я работаю над скриптом сканирования на Python, где я хочу отобразить следующий HTML-ответ в мультилист или словарь (это не имеет значения).
Мой текущий код:
from bs4 import BeautifulSoup
from urllib.request import Request, urlopen
req = Request("https://my.site.com/crawl", headers = {'User-Agent': 'Mozilla/5.0'})
webpage = urlopen(req)
soup = BeautifulSoup(webpage, 'html.parser')
ul = soup.find('ul', {'class': ''})
После запуска я получаю следующий результат, хранящийся в ул.:
<ul>
<li><a class = "reference" href = "#ref1">Data1</a></li>
<li><a class = "reference" href = "#ref2">Data2</a>
<ul>
<li><a class = "reference" href = "#ref3">Data3</a></li>
<li><a class = "reference" href = "#ref4">Data4</a>
<ul>
<li><a class = "reference" href = "#ref5"><span class = "pre">Data5</span></a></li>
<li><a class = "reference" href = "#ref6"><span class = "pre">Data6</span></a></li>
.
.
.
</ul>
</li>
</ul>
</li>
<li><a class = "reference" href = "#ref7">Data7</a>
<ul>
<li><a class = "reference" href = "#ref8"><span class = "pre">Data8</span></a></li>
<li><a class = "reference" href = "#ref9"><span class = "pre">Data9</span></a></li>
.
.
.
</ul>
</li>
<li><a class = "reference" href = "#ref10">Data10</a>
<ul>
<li><a class = "reference" href = "#ref11"><span class = "pre">Data11</span></a></li>
<li><a class = "reference" href = "#ref12">Data12</a></li>
</ul>
</li>
</ul>
Поскольку это внешний сайт, я не могу контролировать идентификатор или класс элементов в списке.
Кажется, я не могу об этом разобраться, есть ли простой способ упорядочить данные в виде списка или диктовки ?:
dict = {'Data1': {'href': 'ref1'},
'Data2': {'href': 'ref2', {
'Data3': {'href': 'ref3'},
'Data4': {'href': 'ref4', {
'Data5': {'href': 'ref5'},
'Data6': {'href': 'ref6'},
.
.
. }
}
}
}
}
Мне кажется, что это обременительный процесс, но я не вижу другого способа сделать это.
Любая помощь, которая поможет мне двигаться в правильном направлении, очень ценится!
Ваше здоровье!
Это настоящие ценности, которые я хочу найти в будущем, например formsemailmodel.
Это недопустимая структура данных. В каждом наборе фигурных скобок ваш href dicts имеет ключи, а ваш дочерний dict - нет. Это не диктат и не набор, это просто SyntaxError. Может хотите что-то вроде 'href': 'ref2', children: { …?
@MartijnPieters: да, вы правы насчет структуры HTML. Данных, которые я получаю, намного больше, и я попытался сократить их. Я предполагаю, что по ошибке были добавлены два дополнительных элемента <li>, теперь это исправлено в посте.






Просто выполните рекурсию элемента ul, извлекая текст из всех элементов li, которые имеют текст, рекурсивно продвигаясь глубже, если вместо этого есть элемент <ul>:
def parse_ul(elem):
result = {}
for sub in elem.find_all('li', recursive=False):
if sub.a is None:
continue
data = {k: v for k, v in sub.a.attrs.items() if k != 'class'}
if sub.ul is not None:
# recurse down
data['children'] = parse_ul(sub.ul)
result[sub.a.get_text(strip=True)] = data
return result
Это принимает все прямые элементы li; если есть элемент <a>, текст этого элемента привязки превращается в ключ, и мы сохраняем копию атрибутов тега в качестве значения (игнорируя любые атрибуты class). Если рядом с тегом <ul> есть также элемент a, он рекурсивно анализируется и добавляется как ключ children в словарь атрибутов для тега <a>.
Для вашего образца ввода это дает:
>>> from pprint import pprint
>>> pprint(parse_ul(soup.ul))
{'Data1': {'href': '#ref1'},
'Data10': {'children': {'Data11': {'href': '#ref11'},
'Data12': {'href': '#ref12'}},
'href': '#ref10'},
'Data2': {'children': {'Data3': {'href': '#ref3'},
'Data4': {'children': {'Data5': {'href': '#ref5'},
'Data6': {'href': '#ref6'}},
'href': '#ref4'}},
'href': '#ref2'},
'Data7': {'children': {'Data8': {'href': '#ref8'}, 'Data9': {'href': '#ref9'}},
'href': '#ref7'}}
Нет способа сделать это с помощью банальный, но это не так уж и громоздко.
Например, вы можете сделать это рекурсивно, примерно так:
def make_data(ul):
d = {}
for a in ul.find_all('a'):
d[a.text] = {'href': a.attrs['href']}
lis = ul.find_all('li', recursive=False)
children = {}
for li in lis:
child = li.ul
if child:
children[li.a.attrs['href']] = make_data(child)
if children:
d['children'] = children
return d
(Мне пришлось дать каждому из этих children dicts ключ, потому что структура, которую вы действительно хотели, не является действительным dict.)
Конечно, вы захотите, например, добавить некоторую обработку ошибок, но этого должно быть достаточно, чтобы вы начали.
Спасибо, что помогли мне на этом пути, к сожалению, это привело к тому, что дети добавили несколько раз
Мне очень нравится parse_ul () Martijn Pieters, но у меня есть код, который не соответствует правилам этого парсера, с двойным <ul></ul> внутри одиночного <li> .. </li>, где последний раздел имеет префикс <a ... > text </a>.
Например, <li><a ...> <ul> </ul> <a..></a><ul> </ul> </li>
См. ниже
<ul>
<li><a class = "ref" href = "#ref1">Data1</a></li>
<li><a class = "ref" href = "#ref2">Data2</a>
<ul>
<li><a class = "ref" href = "#ref4">Data4</a>
<ul>
<li><a class = "ref" href = "#ref5"><span class = "pre">Data5</span></a>/li>
<li><a class = "ref" href = "#ref6"><span class = "pre">Data6</span></a></li>
.
.
</ul>
<!-- a-tag without preceding <li> tag -->
<a class = "ref" href = "#ref4a">Data4a</a>
<ul>
<li><a class = "ref" href = "#ref5a"><span class = "pre">Data5a</span></a></li>
<li><a class = "ref" href = "#ref6a"><span class = "pre">Data6a</span></a></li>
.
.
</ul>
</li>
</ul>
</li>
.
.
</ul>
Я не могу понять, как изменить parse_ul (), чтобы он принимал это отклонение и выводил это?
{'Data1': {'href': '#ref1'},
'Data2': {'children': {'Data4': {'children': {'Data5': {'href': '#ref5'},
'Data6': {'href': '#ref6'}}},
'href': '#ref4'},
{'Data4a': {'children':{'Data5a': {'href': '#ref5a'},
'Data6a': {'href': '#ref6a'}}},
'href': '#ref4a'},
'href': '#ref2'}
}
Следующий скрипт:
from bs4 import BeautifulSoup
import pprint
pp = pprint.PrettyPrinter(indent=4) # Init pritty print (pprint)
soup = BeautifulSoup(html_contents, 'lxml')
menu_dict = parse_ul(soup.ul)
pp.pprint(menu_dict)
сгенерирует следующий вывод, в котором отсутствует вторая часть, содержащаяся в <a..></a><ul> </ul>:
{'Data1': {'href': '#ref1'},
'Data2': {'children': {'Data4': {'children': {'Data5': {'href': '#ref5'},
'Data6': {'href': '#ref6'}}},
'href': '#ref4'},
'href': '#ref2'}
}
Ваша структура HTML непоследовательна, вам не хватает хотя бы одного открывающего
<li>(или слишком много закрывающих</li>). Убедитесь, что это чистый HTML. В словаре вам нужен ключ для проверенного значения словаря. Может,'children'?