получаю ошибку "AttributeError: 'NoneType' object has no attribute 'get_text'" хотя в коде тег и класс указаны правильно

Gleb

Новичок
Пользователь
Апр 7, 2021
10
0
1
я работаю над парсингом сайта на питоне, использую библиотеки(requests, BS4, csv)p.s все последних версий. система: винда, питон - 3.9. ПРОБЛЕМА - мне нужно спарсить несколько параметров с карточки товара и у меня получилось спарсить всё кроме цены. как только я прописал метод(get_text), мне вылетела ошибка - AttributeError: 'NoneType' object has no attribute 'get_text'. после этого я несколько раз проверил класс и тег, всё оказалось верно. без (get_text) всё работает.
на данный момент прога работает, две строки с ошибкой в комментариях.

Python:
import requests
from bs4 import BeautifulSoup
import csv

URL = 'https://sport-marafon.ru/catalog/muzhskie-krossovki/'
HEADERS = {'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Mobile Safari/537.36', 'accept': '*/*'}
HOST = 'https://sport-marafon.ru'
CSV = 'shoes.csv'

def save_content(items, path):
    with open(path, 'w', newline='') as file:
        writer = csv.writer(file, delimiter=';')
        writer.writerow(['наименование', 'ссылка товара', 'производитель', 'фото товара'])
        for item in items:
            writer.writerow([item['название'], item['ссылка'], item['бренд'], item['картинка']])

def get_content(html):
    soup = BeautifulSoup(html, 'html.parser')
    items = soup.find_all('div', class_='col-6 col-md-4 col-lg-4')
    shoes = []
    for item in items:
        shoes.append({
            'название': item.find('a', class_='product-list__name').get_text(),
            'ссылка': HOST + item.find('a').get('href'),
            'бренд': item.find('a', class_='product-list__brand').get_text(),
            #'цена без скидки': item.find('div', class_='product-list__price product-list__price_old').get_text(),
            #'цена со скидкой': item.find('div', class_='product-list__price product-list__price_new').get_text(),
            'картинка': HOST + item.find('div', class_='product-list__image-wrap').find('img').get('src'),
        })
    return shoes

def get_html(url, params=''):
    r = requests.get(url, headers=HEADERS, params=params)
    return r

def parse():
    PAGENATION = input('укажите кол-во страниц для парсинга: ')
    PAGENATION = int(PAGENATION.strip())
    html = get_html(URL)
    if html.status_code == 200:
        shoes = []
        for page in range(0, PAGENATION):
            print(f'идёт парсинг страницы: {page}')
            html = get_html(URL, params={'page': page})
            shoes.extend(get_content(html.text))
            save_content(shoes, CSV)
    else:
        print('Не удаётся получить доступ к сайту!')

parse()
и часть кода сайта по цене:
HTML:
<div data-v-49001340="" class="product-list__price product-list__price_new">
                    8 393 ₽
                    &nbsp;
                </div>
<div data-v-49001340="" class="product-list__price product-list__price_old">11 990 ₽
                </div>
 
Последнее редактирование:

regnor

Модератор
Команда форума
Модератор
Июл 7, 2020
2 668
475
83
чет я ваш код скопировал, а он ошибки выдает, про отступы какие то говорит...

P.S.
как задать вопрос
 

Gleb

Новичок
Пользователь
Апр 7, 2021
10
0
1
чет я ваш код скопировал, а он ошибки выдает, про отступы какие то говорит...

P.S.
как задать вопрос
спасибо, исправил
 

regnor

Модератор
Команда форума
Модератор
Июл 7, 2020
2 668
475
83
ну у вас класс же не так определен...

Python:
#'цена без скидки': item.find('div', class_='product-list__price product-list__price_old').get_text(),
#'цена со скидкой': item.find('div', class_='product-list__price product-list__price_new').get_text(),
это если скидка есть, а без скидки же класс такой
class="product-list__price" ...

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

Gleb

Новичок
Пользователь
Апр 7, 2021
10
0
1
таак... а как тогда будет выглядеть эта проверка?
 

regnor

Модератор
Команда форума
Модератор
Июл 7, 2020
2 668
475
83
как то так
Python:
...
def get_content(html):
    soup = BeautifulSoup(html, 'html.parser')
    items = soup.find_all('div', class_='col-6 col-md-4 col-lg-4')
    shoes = []
    for item in items:
        if item.find('div', class_='product-list__price product-list__price_old'):
            price_old = item.find('div', class_='product-list__price product-list__price_old').get_text()
            price_new = item.find('div', class_='product-list__price product-list__price_new').get_text()
        else:
            price_old = 'Нету'
            price_new = item.find('div', class_='product-list__price').get_text()
        shoes.append({
            'название': item.find('a', class_='product-list__name').get_text(),
            'ссылка': HOST + item.find('a').get('href'),
            'бренд': item.find('a', class_='product-list__brand').get_text(),
            'цена без скидки': price_old,
            'цена со скидкой': price_new,
            'картинка': HOST + item.find('div', class_='product-list__image-wrap').find('img').get('src'),
        })
    print(shoes[0])
    print(shoes[6])
    return shoes
...

принты в конце для проверки...
 

Gleb

Новичок
Пользователь
Апр 7, 2021
10
0
1
спасибо, сейчас попробую
 

Gleb

Новичок
Пользователь
Апр 7, 2021
10
0
1
всё заработало, но цена в таблицу выводится одинаковая
 

Вложения

  • Screenshot таблицы.png
    Screenshot таблицы.png
    16,6 КБ · Просмотры: 3

regnor

Модератор
Команда форума
Модератор
Июл 7, 2020
2 668
475
83
код покажите
 

Gleb

Новичок
Пользователь
Апр 7, 2021
10
0
1
всё, сам подправил. работает
 

regnor

Модератор
Команда форума
Модератор
Июл 7, 2020
2 668
475
83
я тоже)
Python:
import requests
from bs4 import BeautifulSoup
import csv

URL = 'https://sport-marafon.ru/catalog/muzhskie-krossovki/'
HEADERS = {'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Mobile Safari/537.36', 'accept': '*/*'}
HOST = 'https://sport-marafon.ru'
CSV = 'shoes.csv'

def save_content(items, path):
    with open(path, 'w', newline='') as file:
        writer = csv.writer(file, delimiter=';')
        writer.writerow(['наименование', 'цена', 'цена без скидки', 'цена со скидкой', 'ссылка товара', 'производитель', 'фото товара'])
        for item in items:
            writer.writerow([item['название'], item['цена'], item['цена без скидки'], item['цена со скидкой'], item['ссылка'], item['бренд'], item['картинка']])

def get_content(html):
    soup = BeautifulSoup(html, 'html.parser')
    items = soup.find_all('div', class_='col-6 col-md-4 col-lg-4')
    shoes = []
    for item in items:
        if item.find('div', class_='product-list__price product-list__price_old'):
            price_old = item.find('div', class_='product-list__price product-list__price_old').get_text()
            price_new = item.find('div', class_='product-list__price product-list__price_new').get_text()
            price = 'Отсутствует'
        else:
            price_old = 'Отсутствует'
            price_new = 'Отсутствует'
            price = item.find('div', class_='product-list__price').get_text()
        shoes.append({
            'название': item.find('a', class_='product-list__name').get_text(),
            'ссылка': HOST + item.find('a').get('href'),
            'бренд': item.find('a', class_='product-list__brand').get_text(),
            'цена': price,
            'цена без скидки': price_old,
            'цена со скидкой': price_new,
            'картинка': HOST + item.find('div', class_='product-list__image-wrap').find('img').get('src'),
        })
    return shoes

def get_html(url, params=''):
    r = requests.get(url, headers=HEADERS, params=params)
    return r

def parse():
    PAGENATION = input('укажите кол-во страниц для парсинга: ')
    PAGENATION = int(PAGENATION.strip())
    html = get_html(URL)
    if html.status_code == 200:
        shoes = []
        for page in range(0, PAGENATION):
            print(f'идёт парсинг страницы: {page}')
            html = get_html(URL, params={'page': page})
            shoes.extend(get_content(html.text))
            save_content(shoes, CSV)
    else:
        print('Не удаётся получить доступ к сайту!')

parse()
 

Gleb

Новичок
Пользователь
Апр 7, 2021
10
0
1
у меня ещё странный баг с пагинацией, после 4ой страницы происходит повторение. если не сложно, гляньте мож там какая-то глупая ошибка, которую я не заметил
 

Gleb

Новичок
Пользователь
Апр 7, 2021
10
0
1
с ценой всё отлично, огромное спасибо. думаете с тремя переменными удобнее('цена', 'цена со скидкой ', 'цена без скидки',)?
 

regnor

Модератор
Команда форума
Модератор
Июл 7, 2020
2 668
475
83
с ценой всё отлично, огромное спасибо. думаете с тремя переменными удобнее('цена', 'цена со скидкой ', 'цена без скидки',)?
ну понятнее, как по мне...

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

Gleb

Новичок
Пользователь
Апр 7, 2021
10
0
1
ну понятнее, как по мне...

по поводу повторений, у вас там повторяются целые страницы, это надо разбираться сидеть, может в коде ошибка, может сайт так отрабатывает... так сразу не скажу, возможно проблемы с переходом по страницам...
ну я вот тоже не смог понять в чём конкретно проблема. попробовал вывести общее кол-во страниц(принт лен пейдж), вывел 4. ну и когда прописал получение всех 8и страниц, получил повторения.
 

regnor

Модератор
Команда форума
Модератор
Июл 7, 2020
2 668
475
83
ну я вот тоже не смог понять в чём конкретно проблема. попробовал вывести общее кол-во страниц(принт лен пейдж), вывел 4. ну и когда прописал получение всех 8и страниц, получил повторения.
я нашел проблему вашу...
он делает повторения, потому что у первой страницы нет параметра page...
Безымянный ше.jpg
если делать парсинг со второй, то все норм показывает...
вам нужно первую страницу парсить отдельным циклом...
 
  • Мне нравится
Реакции: Gleb

Gleb

Новичок
Пользователь
Апр 7, 2021
10
0
1
воу... понял. спасибо ещё раз
 

Форум IT Специалистов