Перейти к содержимому

Как парсить данные с сайта python bs4

  • автор:

Как правильно парсить страницу с помощью 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",) for item in items: time = soup.find("p", ) span = soup.find("span", ) print(time) print(span) if __name__ == '__main__': loop = asyncio.get_event_loop() loop.run_until_complete(main()) 

Отслеживать

задан 5 фев 2023 в 15:30

Дима Рогачев Дима Рогачев

63 4 4 бронзовых знака

Вы хотите выделить только текст, верно?

5 фев 2023 в 15:31

time = item.find span = item.find

5 фев 2023 в 16:48

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Есть ещё один вариант парсинга, но он сложнее по структуре и иногда может не видеть данные из 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 выполняет функцию выделения только текста 

введите сюда описание изображения

Результат:

Туториал по библиотеке BeautifulSoup4

Парсеры — это программы, которые скачивают из интернета странички и разбирают их на составляющие: заголовок, картинка, текст… С помощью него можно выкачать с сайта гигабайты полезной информации. Библиотека BeautifulSoup4 как раз предназначена для парсинга.

В этой статье вы узнаете как распарсить сайт Франка Сонненберга. Цель: по ссылке на пост вытащить его название, текст и картинку.

Франк Сонненберг — известный американский писатель и коуч. За свои книги он попал в “Топ 100 Американских мыслителей”, а его блог принадлежит списку “Лучшие блоги о лидерстве 21 века”.

Прежде чем начинать…

Для прохождения этого туториала вам понадобятся 3 библиотеки:

$ pip install requests BeautifulSoup4 lxml 

Получить страничку поста

Будем парсить пост “Are You Grateful?”. Чтобы распарсить HTML-страничку с постом, сначала нужно её скачать. Это можно сделать с помощью requests , вот статья об этой библиотеке.

import requests url = 'https://www.franksonnenbergonline.com/blog/are-you-grateful/' response = requests.get(url) response.raise_for_status() print(response.text) 

Здесь мы просто сделали запрос по ссылке и получили в ответ огромный HTML. Начинаться он будет примерно так:

DOCTYPE html> html lang="en-US"> head > meta charset="UTF-8" /> meta name="viewport" content="width=device-width, initial-scale=1" /> . 

Парсинг поста

У вас есть HTML страничка, но как достать оттуда заголовок поста, картинку и текст? Наконец, на сцену выходит BeautifulSoup. Сейчас вы получили HTML из response.text , но это просто строка с HTML кодом. Для работы с библиотекой BeautifulSoup нужно сделать из этой строки HTML-суп:

from bs4 import BeautifulSoup soup = BeautifulSoup(response.text, 'lxml') print(soup.prettify()) 

В Python-коде суп — это новый объект с кучей возможностей. Например, теперь можно вывести HTML красиво, с отступами, с помощью метода soup.prettify() :

DOCTYPE html> html lang="en-US"> head> meta charset="utf-8"/> meta content="width=device-width, initial-scale=1" name="viewport"/> title> Are You Grateful? . 

Супом он называется исторически, вот статья об этом термине. Если вкратце, то на самом деле верстальщики иногда косячат и, например, забывают закрывать теги или оставляют какие-нибудь неисправности. Такой код на HTML стали называть tag soup . Браузеры умеют самостоятельно исправлять какие-то огрехи и делать из такого “супа” нормальный, рабочий HTML. Но если вы скачиваете страничку через requests , то браузер тут ни при чём, и вы получите такой HTML, какой написали верстальщики сайта, со всеми его ошибками.

Для этого и нужна библиотека lxml , она подправит мелкие недочёты, и с ней BeautifulSoup справится даже с очень плохой вёрсткой. В этой строчке вы как раз говорите библиотеке BeautifulSoup использовать lxml :

soup = BeautifulSoup(response.text, 'lxml') 

Заголовок поста

Заголовок поста можно легко найти методом супа .find() . Для начала нужно узнать в какой тег этот заголовок обёрнут. В этом помогут инструменты разработчика:

Итак, тег h1 . Вот что вернёт метод .find() :

print(soup.find('h1')) # 

Это тоже суп, но уже не со всей HTML-страницей, а только с этим тегом и тегами внутри него. Заголовка поста тут нет: пост называется Are You Grateful? , а такого текста в этом теге нет. Похоже, что это не тот тег , который вы искали. Их на странице несколько и BeautifulSoup4 выдал первый, который нашёл. Это тег , который находится в самом верху страницы:

Как же найти заголовок поста, а не страницы? Можно уточнить запрос: заголовок поста лежит в теге , а тот — в :

Давайте попробуем такой запрос:

title_tag = soup.find('main').find('header').find('h1') print(title_tag) # 

Are You Grateful?

Тег нашли, а как достать его текст? Всё очень просто:

title_tag = soup.find('main').find('header').find('h1') title_text = title_tag.text print(title_text) # Are You Grateful? 

Победа, вы добрались до заголовка поста!

Картинка поста

Картинку можно найти так же: это единственный тег внутри тега . Но давайте попробуем другой подход, найдём её по классу. У картинки есть классы:

У картинки есть 3 класса, они перечислены через пробел:

attachment-post-image size-post-image wp-post-image 

Класс attachment-post-image переводится как “Картинка поста”, а значит наверняка он есть только у картинок поста. Вот как найти тег img , у которого есть такой класс:

soup.find('img', class_='attachment-post-image') # # fortunate, things to be grateful for, why you should be grateful, Frank Sonnenberg" class token comment"># size-post-image wp-post-image" height="400" sizes="(max-width: 800px) 100vw, 800px" # src="https://www.franksonnenbergonline.com/wp-content/uploads/2019/10/image_are-you-grateful.jpg" ... 

Тот же .find() , только указали параметр class_ . Нижнее подчёркивание разработчики библиотеки добавили для того, чтобы не было пересечения со словом class из Python, которое используется для создания классов.

Осталось достать адрес картинки, он лежит в аргументе src :

soup.find('img', class_='attachment-post-image')['src'] # https://www.franksonnenbergonline.com/wp-content/uploads/2019/10/image_are-you-grateful.jpg 

Домашнее задание

Осталось спарсить текст поста. Сделать это можно одним из способов выше: по классу или тегам, с помощью метода find .

Попробуйте бесплатные уроки по Python

Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.

Переходите на страницу учебных модулей «Девмана» и выбирайте тему.

Парсим данные каталога сайта, используя Beautiful Soup (часть 1)

Продолжим разбираться с Python и чековыми данными. У нас имеется информация о чековых записях, полученная с сайта налоговой, это хорошо. Теперь нужно научиться определять категорию, к которой относится товар. Мы будем это делать в автоматическом режиме, предварительно построив модель машинного обучения.

Ключевая «боль» / сложность — нам требуется так называемый сет для обучения (training set). Забегая вперед скажу, что успел протестировать такой сет для обучения на реальных данных из одной продуктовой сети, результаты, к сожалению, оказались не самые радужные, поэтому попробуем собрать другой честный сет для обучения, используя открытые источники в интернете.

Для работы возьмем популярный сайт по доставке еды из гипермаркетов. Сегодня будем использовать простую, удобную и функциональную библиотеку в Python для парсинга данных с .html страниц — Beatiful Soup.

Целевая страница, на которой интересующие нас данные имеет следующий вид.

Страница каталога сайта по доставке еды из гипермаркетов

Однако если мы впервые зайдем на сайт нас перебросит на главную, поскольку мы не выбрали ближайший гипермаркет.

Главная страница сайта по доставке еды из гипермаркетов

Проблема понятна, скорее всего, ее можно решить установлением cookies, подобных тем, что сохраняются локально у пользователя.

Теперь важно определить порядок действий и структуру сбора данных.

Основная задача:

  1. Собрать наименования всех верхнеуровневых категорий и соответствующие им URL сайта
  2. Используя полученный в пункте 1 список, собрать данные о товарах с каждой страницы категории.

Сегодня будем разбирать первую часть. Приступим, в теории нам должно хватить таких команд:

from bs4 import BeautifulSoup #импортируем модуль BeautifulSoup import requests r = requests.get('https://i****.ru/products?category_id=1-ovoschi-frukty-griby-yagody&from_category=true') soup = BeautifulSoup(r.text)

Однако если мы посмотрим содержимое soup, то обнаружим, что мы получили исходный код главной страницы, а не той, что интересует нас. Главная страница не подходит для целей нашего анализа и сбора информации.

Получили исходный код главной страницы сайта

Поэтому воспользуемся методом Session библиотеки requests, которым можно передать cookies в качестве параметра. Итого наш код выглядит так:

import requests s = requests.Session() r = s.get('https://i****.ru/products?category_id=1-ovoschi-frukty-griby-yagody&from_category=true', \ cookies = ) soup = BeautifulSoup(r.text)

Мы устанавливаем 4 cookies, которые эмулируют поведение человека и выбранный гипермаркет (их мы установили эмпирическим путем из cookies, установленных браузером, при выборе соответствующего гипермаркета):

Cookies, влияющие на отображение главной страницы сайта

Прекрасно, осталось лишь собрать нужные нам категории и ссылки на них. Для этого напишем следующий код:

categories=soup.find_all('div', <'class':['with-children']>) tree = <> for x in categories: tree[x.findNext('span').text]=x.findNext('a').get('href')

В этом сниппете мы как и раньше GET-запросом с параметрами (cookies) вызываем желаемую страницу браузера и скачиваем данные, затем у нас появляется объект класса BeautifulSoup.
Мы используем команду:

categories=soup.find_all('div', <'class':['with-children']>)

И находим все элементы , у которых имеется класс with-children, вот то же самое в коде сайта:

Элементы, которые содержат название категории.

Далее, объявляем пустой объект класса dict и для каждого найденного выше элемента в цикле собираем:

tree[x.findNext('span').text]=x.findNext('a').get('href’)

Что фактически означает: мы берем текст следующего, за найденным элемента и адрес ссылки, следующей за найденным .
Именно это нам и требовалось получить. Таким образом мы получили словарь вида :

Справочник категорий и соответствующих им URL

В следующей статье — продолжение о сборе информации по карточкам товаров каталога.

Парсим данные каталога сайта, используя Beautiful Soup и Selenium (часть 2)

Продолжение предыдущей статьи о сборе данных с известного онлайн каталога товаров.

Если внимательно проанализировать поведение страницы с товарами, можно заметить, что товары подгружаются динамически, то есть при скролле страницы вниз мы получим новый набор товаров, и, тем самым, код из предыдущей статьи для данной задачи окажется бесполезным.

Динамическая подгрузка товаров на странице

Для таких случае в python также имеется решение — библиотека Selenium, она запускает движок браузера и эмулирует поведение человека.

В первой части скрипта мы соберем дерево категорий аналогично прошлой статье, но уже с использованием Selenium.

import time from selenium import webdriver from bs4 import BeautifulSoup as bs browser = webdriver.Chrome() browser.get("https://i****.ru/products?category_id=1-ovoschi-frukty-griby-yagody&from_category=true") cookies_1= cookies_2= cookies_3= browser.add_cookie(cookies_1) browser.add_cookie(cookies_2) browser.add_cookie(cookies_3) browser.get("https://i****.ru/products?category_id=1-ovoschi-frukty-griby-yagody&from_category=true") source_data = browser.page_source soup = bs(source_data) categories=soup.find_all('div', <'class':['with-children']>) tree = <> for x in categories: tree[x.findNext('span').text]=x.findNext('a').get('href')

В этом сниппете мы как и раньше get-запросом с параметрами вызываем желаемую страницу браузера и скачиваем данные, затем у нас появляется объект класса bs, с которым мы проделываем аналогичные операции. Таким образом, мы получили словарь tree, в котором для каждой категории хранится URL страницы для данной категории, в дальнейшем этот словарь нам пригодится для перебора в цикле.

Приступим к сбору данных о товарах. Для этого импортируем библиотеку pandas и создадим новый dataframe с четырьмя колонками.

import pandas as pd df = pd.DataFrame(columns=['SKU', 'Weight', 'Price','Category'])

Далее, воспользуемся нашим словарем tree и для каждой категории получим данные страницы. Ниже приведен код. Мы по-прежнему должны установить куки, которые установлены у пользователя, а также выполнить некоторые хитрые команды для работы движка браузеры, которые сэмулируют перемещение курсора вниз страницы.

for cat, link in tree.items(): browser.maximize_window() browser.get('https://i****.ru'+link) cookies_1= cookies_2= cookies_3= browser.add_cookie(cookies_1) browser.add_cookie(cookies_2) browser.add_cookie(cookies_3) browser.get('https://i****.ru'+link) # Скрипт, который через каждые 3 секунды ищет конец страницы и выполняется пока не закончится получение свежих данных lenOfPage = browser.execute_script("window.scrollTo(0, document.body.scrollHeight);var lenOfPage=document.body.scrollHeight;return lenOfPage;") match=False while(match==False): lastCount = lenOfPage time.sleep(3) lenOfPage = browser.execute_script("window.scrollTo(0, document.body.scrollHeight);var lenOfPage=document.body.scrollHeight;return lenOfPage;") if lastCount==lenOfPage: match=True

Теперь мы дошли до конца страницы и можем собрать данные для работы библиотеки beautifulsoup.

# Собираем данные со страницы source_data = browser.page_source soup = bs(source_data) skus=soup.find_all('div', <'class':['b-product-small-card']>) last_value=len(df)+1 if len(df)>0 else 0 for i,x in enumerate(skus): df.loc[last_value+i]=[x.findNext('a').contents[0],\ x.findNext('div',).contents[0],\ x.findNext('div',)['data-price'],\ cat] browser.close()

В приведенном выше фрагменте кода мы ищем все элементы , у которых класс — b-product-small-card, а далее для каждого найденного товара собираем значения полей веса и цены.

Исходный код сайта продуктовой карточки

Ставим выполняться скрипт и пьем кофе. Вуа-ля, теперь у нас есть pandas dataframe с данными всех товаров:

DataFrame с товарами, собранными с сайта

Теперь, у нас есть отличные данные для обучения NLP модели — наименования товаров и их принадлежность к различным категориям.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *