Группировать результаты из веб-разбивки на разделы - PullRequest
1 голос
/ 10 марта 2019

Пытаясь узнать, как использовать Python для просмотра веб-страниц, я выбрал обеденное меню из этого http://bramatno8.kvartersmenyn.se/

Страница построена так:

<div class="menu">
<strong>Monday<br></strong>
<br>
Food 1<br>
Food 2
<br><br>
<strong>Tuesday<br></strong>
<br>
Food 3<br>
Food 4
<br><br>
<strong>Wednesday<br></strong>
<br>
Food 5<br>
Food 6
<br><br>
<strong>Thursday<br></strong>
<br>
Food 7<br>
Food 8
<br><br>
<strong>Friday<br></strong>
<br>
Food 9<br>
Food 10
<br><br>
</div>

Так чтоУ меня так далеко, вот что:

import requests
from bs4 import BeautifulSoup

url = 'http://lunchmenu.com'

fetchlunch = requests.get(url)

soup = BeautifulSoup(fetchlunch.text, 'html.parser')

menu = soup.findAll(class_='menu')[0]

for br in menu.find_all('br'):
    br.replace_with('\n')

print(menu.get_text())

Так что это напечатает все меню за неделю в одном разделе.

То, что я хотел бы сделать, это просто получить меню длядень.т.е. если это вторник, то должно отображаться только меню на вторник.Итак, я думаю, что мне нужно иметь результат в массиве, чтобы затем вытащить меню на день?

1 Ответ

3 голосов
/ 10 марта 2019

Один из подходов состоит в том, чтобы найти тег <strong> с соответствующим содержимым дня, а затем использовать .next_siblings, чтобы перебирать продукты, пока вы не нажмете еще один <strong> или не исчерпаете братьев и сестер. Я использовал парсер lxml, но он работает и с html.parser.

Вот пример вашего DOM (я настроил продукты, чтобы было ясно, что они работают):

import bs4
import requests

day = "Tuesday"
dom = """
<div class="menu">
<strong>Monday</strong>
<br>
Food 1<br>
Food 2
<br><br>
<strong>Tuesday</strong>
<br>
Food 3<br>
Food 4
<br><br>
<strong>Wednesday</strong>
<br>
Food 5<br>
Food 6
<br><br>
<strong>Thursday</strong>
<br>
Food 7<br>
Food 8
<br><br>
<strong>Friday</strong>
<br>
Food 9<br>
Food 10
<br><br>
</div>
"""

soup = bs4.BeautifulSoup(dom, "lxml")
menu = soup.find(class_ = "menu")
foods = []

for elem in menu.find("strong", text=day).next_siblings:
    if elem.name == "strong": 
        break

    if isinstance(elem, bs4.element.NavigableString) and elem.strip() != "":
        foods.append(elem.strip())

print(foods)

Выход:

['Food 3', 'Food 4']

Здесь он находится на первом действующем сайте. https://www.kvartersmenyn.se/rest/15494. Обратите внимание на расширенную кодировку символов и лямбду для обеспечения соответствия в случае, если в теге <b> есть дополнительный контент:

# -*- coding: latin1 -*-

import bs4
import requests

day = "Måndag"
url = "https://www.kvartersmenyn.se/rest/15494"

soup = bs4.BeautifulSoup(requests.get(url).text, "lxml")
menu = soup.find(class_ = "meny")
foods = []

for elem in menu.find("b", text = lambda x: day in x).next_siblings:
    if elem.name == "b": 
        break

    if isinstance(elem, bs4.element.NavigableString):
        foods.append(elem)

print(day)

for food in foods:
    print(food)

Выход:

Måndag
A: Gaeng phed**
röd curry i cocosmjölk med sötbasilika, wokade blandade grönsaker
B: Ghai phad med mauang** (biff) wok i chilipaste med cashewnötter, grönsaker
C: Phad bamme (fläsk) wokade äggnudlar i ostronsås, grönsaker
D: Satay gay currymarinerade kycklingfiléspett med jordnötssås
E: Gai chup pheng tood*
Friterad kyckling med söt chilisås och ris
F: Phad bambou* (biff) wok i ostronsås med bambu, lök, champinjoner

Наконец, вот он на вашем втором живом сайте, http://bramatno8.kvartersmenyn.se/ , Все эти сайты имеют различную и непоследовательную структуру, поэтому не очевидно, есть ли для них серебряная пуля. Я подозреваю, что эти меню написаны вручную кем-то, кто может не понимать структурирование документа, поэтому потребуется некоторая работа для обработки произвольных обновлений страницы.

Вот так:

# -*- coding: latin1 -*-

import bs4
import requests

day = "Måndag"
url = "http://bramatno8.kvartersmenyn.se/"

soup = bs4.BeautifulSoup(requests.get(url).text, "lxml")
menu = soup.find(class_ = "meny")
foods = []

for elem in menu.find(text = day).parent.next_siblings:
    if elem.name == "strong": 
        break

    if isinstance(elem, bs4.element.NavigableString):
        foods.append(elem)

print(day)

for food in foods:
    print(food)

Выход:

Måndag
Viltskav med rårörda lingon (eko), vaxbönor och potatispuré
Sesambakad blomkål med sojamarinerade böngroddar, salladslök, rädisa och sojabönor samt ris
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...