AttributeError: 'NoneType' object has no attribute 'text' и AttributeError Traceback (most recent call last) при парсинге
!pip3 install requests
import requests
from bs4 import BeautifulSoup
def get_page(p):
url = 'https://www.cian.ru/kupit-kvartiru/'.format(p)
response=requests.get(url)
bridge=BeautifulSoup(response.content, 'html.parser')
flats=bridge.find_all('article',{'class': '_93444fe79c--container--2pFUD _93444fe79c--cont--1Ddh2'})
inform = [ ]
for flat in flats:
inform.append({'General price': flat.find('span', {'class': '_93444fe79c--color_black_100--A_xYw _93444fe79c--lineHeight_28px--3QLml _93444fe79c--fontWeight_bold--t3Ars _93444fe79c--fontSize_22px--3UVPd _93444fe79c--display_block--1eYsq _93444fe79c--text--2_SER'}).text,
'Adress': flat.find('a', {'class': '_93444fe79c--link--10mjQ'}).text,
'Metro': flat.find('a', {'class': '_93444fe79c--link--3ruIo'}).text,
'Kind of flat': flat.find('span', {'class': '_93444fe79c--color_black_100--A_xYw _93444fe79c--lineHeight_20px--2dV2a _93444fe79c--fontWeight_bold--t3Ars _93444fe79c--fontSize_16px--1mDFP _93444fe79c--display_block--1eYsq _93444fe79c--text--2_SER'}).text,
'Time': flat.find('span', {'class': '_93444fe79c--color_gray60_100--3VLtJ _93444fe79c--lineHeight_20px--2dV2a _93444fe79c--fontWeight_normal--2G6_P _93444fe79c--fontSize_14px--10R7l _93444fe79c--display_inline--2gjyY _93444fe79c--text--2_SER'}).text,
'href': flat.h3.a.get('href')})
return infa
inform = []
for p in range(1,10):
inform.extend(get_page(p))
import pandas as pd
df = pd.DataFrame(inform)
print(df.shape)
df.head()
Код ошибки следующий:
AttributeError Traceback (most recent call last)
<ipython-input-41-33245b75d686> in <module>
25
26 for p in range(1,2):
---> 27 inform.extend(get_page(p))
28 import pandas as pd
29
<ipython-input-41-33245b75d686> in get_page(p)
17 'Adress': flat.find('a', {'class': '_93444fe79c--link--10mjQ'}).text,
18 'Metro': flat.find('a', {'class': '_93444fe79c--link--3ruIo'}).text,
---> 19 'Kind of flat': flat.find('span', {'class': '_93444fe79c--color_black_100--A_xYw _93444fe79c--lineHeight_20px--2dV2a _93444fe79c--fontWeight_bold--t3Ars _93444fe79c--fontSize_16px--1mDFP _93444fe79c--display_block--1eYsq _93444fe79c--text--2_SER'}).text,
20 'Time': flat.find('span', {'class': '_93444fe79c--color_gray60_100--3VLtJ _93444fe79c--lineHeight_20px--2dV2a _93444fe79c--fontWeight_normal--2G6_P _93444fe79c--fontSize_14px--10R7l _93444fe79c--display_inline--2gjyY _93444fe79c--text--2_SER'}).text,
21 'href': flat.h3.a.get('href')})
AttributeError: 'NoneType' object has no attribute 'text'
Как тут быть вообще? Отчего вылезли эти две ошибки? Я попробовал сократить число страниц в range, но это не помогло.
Ответы (1 шт):
Действительно, имена классов на этом ресурсе динамические и меняются от вызова к вызову, поэтому ваш методы .find() их не находит и возвращает None и, соответственно, не имея воможность применить атрибут text, возвращает вам ошибку...
Но не все так уж плохо: даже в этих динамических именах есть одинаковые части для всех карточек (card в данном случае), которые можно парсить, используя регулярные выражения и их метод .compile()
Пробуем парсить cards:
import re
import requests
from bs4 import BeautifulSoup
url = 'https://www.cian.ru/kupit-kvartiru/'
r = requests.get(url)
soup = BeautifulSoup(r.content, 'html.parser')
cards = soup.find_all('div', {'class': re.compile(r'card')})
Проверяем количество полученных записей (их 28 на странице):
>>> len(cards)
28
Внутри карточки даже проще (там есть уникальные data-mark в span):
flats = []
for card in cards:
title = card.find('span', {'data-mark': 'OfferTitle'})
subtitle = card.find('span', {'data-mark': 'OfferSubtitle'})
price = card.find('span', {'data-mark': 'MainPrice'})
flats.append({
'title': title.text if title else None,
'subtitle': subtitle.text if subtitle else None,
'price': price.text.replace('\xa0₽', '') if price else None,
})
Выводим содержимое списка flats:
>>> flats
[
{'title': 'Вид на Москва Сити!', 'subtitle': '2-комн. кв., 52 м², 10/40 этаж', 'price': '15 950 000'},
{'title': 'Квартира с современным ремонтом', 'subtitle': '3-комн. кв., 89,9 м², 21/40 этаж', 'price': '40 000 000'},
{'title': 'Loft River - Тихая гавань!', 'subtitle': '2-комн. апарт., 66 м², 4/5 этаж', 'price': '22 374 000'},
...
{'title': 'Апартаменты-студия, 54,3 м², 75/96 этаж', 'subtitle': None, 'price': '33 500 000'},
{'title': 'Квартира с просторной террасой', 'subtitle': '6-комн. кв., 393,4 м², 6/7 этаж', 'price': '549 380 110'},
{'title': 'Пентхаус - 3 этажа - 115,6 м2', 'subtitle': 'Своб. планировка, 115,6 м², 5/5 этаж', 'price': '42 656 400'}
]
UPD Если хорошо поискать, можно обнаружить внутренний api, который отдает все эти данные (и даже гораздо больше, чем в html) сразу в json:
но это уже совсем другая история ;) если будет интересно - продолжим в другом вопросе...

