Как правильно парсить страницу с помощью BeautifulSoup?
Хочу спарсить страницу новостей сайта, а именно: время публикации, название новости, ссылка на новость. Но, вместо того, чтобы выводить все новости страницы выводит только 1 пункт.
import asyncio
import aiohttp
from bs4 import BeautifulSoup as BS
BASE_URL = "https://nubip.edu.ua/"
async def main():
async with aiohttp.ClientSession() as session:
async with session.get(BASE_URL) as response:
r = await aiohttp.StreamReader.read(response.content)
soup = BS(r,"html.parser")
items = soup.find_all("div",{"class": "block"})
for item in items:
time = soup.find("p", {"class": "datetime"})
span = soup.find("span", {"class": "b-selection-em"})
print(time)
print(span)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Вывод
<p class="datetime"><span>5 лютого 2023 року</span></p>
<span class="b-selection-em">НУБіП піднявся в міжнародному рейтинзі WEBOMETRICS і посів четверте місце в Україні!</span>
<p class="datetime"><span>5 лютого 2023 року</span></p>
<span class="b-selection-em">НУБіП піднявся в міжнародному рейтинзі WEBOMETRICS і посів четверте місце в Україні!</span>
<p class="datetime"><span>5 лютого 2023 року</span></p>
<span class="b-selection-em">НУБіП піднявся в міжнародному рейтинзі WEBOMETRICS і посів четверте місце в Україні!</span>
Ответы (3 шт):
Автор решения: 9evoldpy
→ Ссылка
Есть ещё один вариант парсинга, но он сложнее по структуре и иногда может не видеть данные из html-данных сайта. Вот пример парсинга евро:
from bs4 import BeautifulSoup
import requests
eur = 'https://quote.rbc.ru/ticker/59090'
response = requests.get(eur)
bs = BeautifulSoup(response.text, "lxml")
euro = bs.find('span', class_='chart__info__sum')
print(euro.text) # .text выполняет функцию выделения только текста
Автор решения: Сергей Ш
→ Ссылка
Например так:
items = soup.find(id="news-block").find_all(attrs={"class": "item"})
for item in items:
time, *span = item.stripped_strings
link = item.a['href']
print(time)
print(' '.join(span))
print(link)
Автор решения: Igor
→ Ссылка
Проблема в вашем коде связана с тем, что внутри цикла вы ищете элементы не внутри текущего item, а в целом в soup. Поэтому для каждого блока div.block вы каждый раз получаете первый элемент <p class="datetime"> и <span class="b-selection-em">, а не тот, который относится к текущему item.
import asyncio
import aiohttp
from bs4 import BeautifulSoup as BS
BASE_URL = "https://nubip.edu.ua/"
async def main():
async with aiohttp.ClientSession() as session:
async with session.get(BASE_URL) as response:
r = await response.text() # правильный способ получить HTML
soup = BS(r, "html.parser")
items = soup.find_all("div", {"class": "block"})
for item in items:
# ищем внутри конкретного блока
time_tag = item.find("p", {"class": "datetime"})
span_tag = item.find("span", {"class": "b-selection-em"})
if time_tag and span_tag:
time_text = time_tag.get_text(strip=True)
span_text = span_tag.get_text(strip=True)
print(time_text, "-", span_text)
if __name__ == '__main__':
asyncio.run(main())
