1 parsing
1 | Введение¶
Цель¶
В этом ДЗ вы напишите свой парсер, который будет бегать по страничкам и автоматически что-то собирать.
Описание¶
По аналогии с занятием по парсингу данных, возьмите интересующий вас сайт, на котором можно пособирать какие-то данные (и при этом API не предоставляется). Идеальный датасет должен иметь текстовое описание некоторого объекта и некоторую целевую переменную, соответствующую этому объекту. Например:
- Сайт новостей: текстовое описание - сама новость, целевая переменная - количество просмотров новости (можно поделить на число дней с момента даты публикации, чтобы получить “среднее число просмотров в день”).
- Сайт с товарами/книгами/фильмами: текстовое описание товара/книги/фильма + средний рейтинг в качестве целевой переменной.
- Блоги - тексты заметок + число просмотров.
- И любые другие ваши идеи, которые подходят под такой формат.
Напишите свой парсер, который будет бегать по страничкам и автоматически что-то собирать.
- Не забывайте, что парсинг - это ответственное мероприятие, поэтому не бомбардируйте несчастные сайты слишком частыми запросами (можно ограничить число запросов в секунду при помощи time.sleep(0.3), вставленного в теле цикла)
- При необходимости очистить датасет от мусора с помощью регулярных выражений).
- Посчитать статистики по собранным данным и провести EDA собранных данных (в случае, если данные представляют собой текст - посчитать частотности слов, выявить наиболее частотные слова и т. п)
- Не забудьте сохранить полученный датасет, он вам еще пригодиться в дальнейших домашних заданиях.
Критерии оценки¶
- Написан парсер, но датасет по каким-то причинам получить не удалось (например, из-за блокировок) - 4 балла
- Написан парсер и собран датасет - 8 баллов
- Проведен EDA собранных данных - 2 балла
2 | Парсер¶
Отзывы о Сбербанке¶
- Для этой задачи выберем страницу
irecommend.ru
. На этой странице можно найти отзывы о разных товарах и услугах - Узнаем что нравится нашим клиентам, и попытаемся найти причины плохих отзывов c помощью дальнейшего EDA, для того чтобы это сделать, нам нужно сначала парсить данные и потом их обработать
- Так как отзывы есть для разных услуг и их достаточно много, ограничимся только общими отзывами Сбербанка
Сохраняем ссылки отзывов¶
- От каждой страницы мы будем получать по 100 отзывов
- Парсинг мы будем делать частично (по 2 страницы), так как парсинг всех страниц (даже с библиотекой time) привадило к блокировкам, либо какая то часть контетна просто не выгружалась
- Каждый отзыв расположен на своем личном URL, соответственно сначала парсим сборку отзывов (
/sberbank?
) (обобщенный вид отзывов) для того чтобы получить URL всех отзывов расположеных на этой странице - Потом уже парсим URL отзывов клиентов и выгружаем интересующее нас информацию об отзыве
# all page review sources
# sources = ['https://irecommend.ru/content/sberbank?new=50']
# sources.extend([f'https://irecommend.ru/content/sberbank?page={i}&new=50'for i in range(1,2)])
# sources
sources = [f'https://irecommend.ru/content/sberbank?page={i}&new=50'for i in range(22,24)]
sources
['https://irecommend.ru/content/sberbank?page=22&new=50', 'https://irecommend.ru/content/sberbank?page=23&new=50']
- Импортируем библиотеки
- Пригодятся вспомогательные функции для сохранения списков (для выгрузки индивидуальных отзывов)
import requests
from bs4 import BeautifulSoup
import time as t
from tqdm.notebook import tqdm
from random import randint
import numpy as np
import json
def write_list(a_list):
print("Started writing list data into a json file")
with open("names.json", "w") as fp:
json.dump(a_list, fp)
print("Done writing JSON data into .json file")
fp.close()
# Read list to memory
def read_list():
# for reading also binary mode is important
with open('names.json', 'rb') as fp:
n_list = json.load(fp)
return n_list
- Создаем сессию в
requests
, из браузера мы копируем информацию и вставляем ее в нашу сессию - Это помогает обходить периодическую блокировку выгрузки данных
- Так же мы используем proxy для того чтобы наш IP не внесли в черный список при написании парсера (не используем никаких личных данных)
s = requests.Session()
s.headers.update({
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/112.0',
})
s.cookies.update({
'sid': 'ZmIxNDk1MGViZDdmOWQ3NTkxYjBkY2VhOTUxMzhiYTE=|1683738281|4b50f094379eebb1ef9971cce80bd5a5a2aa4510',
'srv_menu_gender': 'women',
'lid': 'ZEACnGRb07W1ZAzPoeVGAgA=',
'_gcl_au': '1.1.178690257.1683739575',
'wt_cdbeid': '1',
'wt3_eid': '%3B717012440280310%7C2168373957543385423%232168374008056837262',
'wt3_sid': '%3B717012440280310',
'wt_rla': '717012440280310%2C18%2C1683739575310',
'sessionId': '1683739575312935624',
'is_synced': 'true',
'qrator_ssid': '1683739576.090.Zk4lm6ShpXdKDJ1p-858bkd8q7lopa6e0s03okmu6qa3kp1fa',
'_gid': 'GA1.2.1392953172.1683739578'
})
# proxies = {'http': ''}
# s.proxies.update(proxies)
- Парсим общюю страницу с отзывами, на ней мы найдем URL, которые сохраняем в список
reviews
(относительный url) - Полный URL сохраняем в
review_link
и сохраняем список вJSON
, для того чтобы не повторять операцию
def parse_page(url):
r = s.get(url)
page = r.text
print(r.status_code)
soup = BeautifulSoup(page, 'html.parser')
# review summary
content = soup.find_all(class_='reviewTextSnippet')
# extract review links
title = soup.find_all(class_='reviewTitle')
reviews = []
for div in title:
reviews.append(div.find('a')['href'])
review_link = []
for review in reviews:
review_link.append('https://irecommend.ru' + review)
return review_link
lst_all_review_sources = []
for link in tqdm(sources):
lst_all_review_sources.extend(parse_page(link))
t.sleep(randint(10,15))
write_list(lst_all_review_sources)
#lst_all_review_sources = read_list()
# lst_all_review_sources
0%| | 0/2 [00:00<?, ?it/s]
200 200 Started writing list data into a json file Done writing JSON data into .json file
read_list()
['https://irecommend.ru/content/ochen-plokho-57', 'https://irecommend.ru/content/budte-vnimatelny-pri-pomoshchi-mobilnogo-banka-s-karty-kradut-dengi', 'https://irecommend.ru/content/obsluzhivanie-klientov-vse-khuzhe-i-khuzhe', 'https://irecommend.ru/content/vozvrat-deneg', 'https://irecommend.ru/content/ogromnye-ocheredi', 'https://irecommend.ru/content/otkrovenno-lzhivyi-piar-obernetsya-sberbanku-povalnym-nedoveriem', 'https://irecommend.ru/content/kak-my-vlipli-s-ssudoi-v-etom-sderbanke', 'https://irecommend.ru/content/produmannyi-bank', 'https://irecommend.ru/content/vse-luchshe-i-luchshe-0', 'https://irecommend.ru/content/kak-podlechit-nervy-ili-kak-my-brali-ipoteku-ot-sberbanka', 'https://irecommend.ru/content/bank-kotoryi-rabotaet-ne-dlya-lyudei-protiv-lyudei', 'https://irecommend.ru/content/u-menya-propadayut-dengi-s-kartochki', 'https://irecommend.ru/content/lzhivyi-biznes', 'https://irecommend.ru/content/pri-vkhode-odna-mysl-tolko-ne-ochered', 'https://irecommend.ru/content/koshmar-265', 'https://irecommend.ru/content/kazhetsya-rabota-banka-uluchshaetsya', 'https://irecommend.ru/content/karta-kredit-momentum', 'https://irecommend.ru/content/bolshoi-i-poetomu-neudobnyi', 'https://irecommend.ru/content/izdevateltvo-kakoe', 'https://irecommend.ru/content/zhal-nelzya-postavit-otsenku-10', 'https://irecommend.ru/content/dobryi-den-ya-spetsialist-sberbanka-rosii-zvonyu-vam-iz-kieva', 'https://irecommend.ru/content/bank-konechno-ne-vinovat-chto-rukovoditel-otdeleniya-idiot-no-vse-zhe', 'https://irecommend.ru/content/kak-poteryat-5-tysyach-i-isportit-sebe-nastroenie', 'https://irecommend.ru/content/idite-v-nogu-so-vremenem-podarochnaya-karta-nemnogo-foto', 'https://irecommend.ru/content/poluchila-kartu-za-10-minut-ochen-udobnaya', 'https://irecommend.ru/content/kak-obchistit-klientov-drugikh-bankov-dlya-sberbanka-ne-vopros', 'https://irecommend.ru/content/brali-tam-kredit', 'https://irecommend.ru/content/bonusnaya-programma-spasibo-ne-ozhidala-takogo-ot-sbera', 'https://irecommend.ru/content/sberbank-slov-net-odni-emotsii', 'https://irecommend.ru/content/mobilnyi-bank-ot-sberbanka-chto-eto-takoe-i-stoit-li-podklyuchat', 'https://irecommend.ru/content/back-ussr-0', 'https://irecommend.ru/content/dengi-derzhu-tolko-v-sberbanke', 'https://irecommend.ru/content/khotite-poluchit-sms-v-3-chasa-nochi-vam-v-sberbank', 'https://irecommend.ru/content/bez-preduprezhdeniya-podklyuchili-platnuyu-uslugu', 'https://irecommend.ru/content/spasibo-sotrudnikam-sbera-chto-komu-pomogli-smyt-s-karty-pensionerki-nevelikie-dengi-nu-pust', 'https://irecommend.ru/content/sobralsya-zakryt-debetovuyu-kartu-sberatebya-zhdut-syurprizy', 'https://irecommend.ru/content/potrebitelskii-kredit-spb-100-kreditosposobnost-ne-garantiya-polucheniya-kredita-v-sberbanke', 'https://irecommend.ru/content/sberbank-obnaglel-v-konets', 'https://irecommend.ru/content/ostorozhno-moshenniki-11', 'https://irecommend.ru/content/navyazchivye-uslugi', 'https://irecommend.ru/content/bank-ne-bez-izyanov', 'https://irecommend.ru/content/vechnye-ocheredisotrudniki-mnogoe-ne-dogovarivayut', 'https://irecommend.ru/content/kak-ya-zakryvala-schet-v-sberbanke-vykup-sebya-iz-rabstva', 'https://irecommend.ru/content/pro-kreditnuyu-i-debetovuyu-kartu-ot-sberbanka-v-rossii-konkurentov-tochno-net', 'https://irecommend.ru/content/protivorechivyi-opyt-moi-priklyucheniya', 'https://irecommend.ru/content/lichno-dlya-menya-minusov-i-nedochetov-v-sberbanke-polno', 'https://irecommend.ru/content/menya-raduet-1', 'https://irecommend.ru/content/sberbank-rasshchedrilsya-na-bonusy', 'https://irecommend.ru/content/povyazana-ya-so-sberom', 'https://irecommend.ru/content/ob-optsii-sberbank-line-onlain', 'https://irecommend.ru/content/moi-bank', 'https://irecommend.ru/content/otnoshenie-kak-k-skotam', 'https://irecommend.ru/content/neuvazhenie', 'https://irecommend.ru/content/prosto-uzhasnaya-istoriya', 'https://irecommend.ru/content/ranshe-schitala-chto-eto-samyi-luchshii-bank-no-kak-ya-oshibalas', 'https://irecommend.ru/content/uzhasnyi-servis-9', 'https://irecommend.ru/content/vysokaya-komissiya-za-uslugi', 'https://irecommend.ru/content/o-tom-kak-ne-nado-oplachivat-scheta-zarubezhnykh-internet-magazinov-perevodit-dengi-inostran', 'https://irecommend.ru/content/moe-khoroshee-vpechatlenie-o-sbere-och-isportilos-posle-etogo-sluchaya', 'https://irecommend.ru/content/mobilnyi-bank-osteregaites-moshennikov', 'https://irecommend.ru/content/pochemu-zhe-takoe-uzhasnoe-otnoshenie-k-lyudyam-kotorykh-zarabatyvayut', 'https://irecommend.ru/content/meloch-priyatno-15', 'https://irecommend.ru/content/ya-ne-dovolna-3', 'https://irecommend.ru/content/kak-ni-stranno-u-nas-s-sb-osobykh-problem-net', 'https://irecommend.ru/content/lenivye-i-ne-kompetentnye', 'https://irecommend.ru/content/zhdite-zhdite-zhdite', 'https://irecommend.ru/content/zastuplyus-i-pust-v-menya-letyat-yaitsa-pomidory-i-tapki', 'https://irecommend.ru/content/sberbank-0', 'https://irecommend.ru/content/ipoteka-sberbank-bez-pervonachalnogo-vznosa-opisanie-skhemy-za-kotoruyu-nasha-semya-zaplatil', 'https://irecommend.ru/content/kvalifikatsiya-rabotnikov-ostavlyaet-zhelat-luchshego', 'https://irecommend.ru/content/moya-istoriya-otklyucheniya-uslugi-ili-srazu-idite-v-ofis', 'https://irecommend.ru/content/udivlena-naskolko-bystro-sberbank-mne-vydal-kartu-foto-udobnaya-karta-momentum-teper-so-mnoi', 'https://irecommend.ru/content/operatsii-po-karte-s-mobilnogo-telefona', 'https://irecommend.ru/content/moi-opyt-obshcheniya-so-sberbankom', 'https://irecommend.ru/content/vor-v-zakone', 'https://irecommend.ru/content/samyi-nadezhnyi-bank-ili-kak-u-menya-ukrali-dengi', 'https://irecommend.ru/content/nevygodno-i-neinteresno', 'https://irecommend.ru/content/ne-kompitentnost-sotrudnikov-i-uzhasy-oplaty-cherez-terminal', 'https://irecommend.ru/content/poluchit-legko-potratit-slozhno', 'https://irecommend.ru/content/uzhasnyi-bank-no-vybora-net', 'https://irecommend.ru/content/ochen-silno-podvel-chetvero-sutok-khodila-k-nim-kak-na-rabotu', 'https://irecommend.ru/content/khamstvo-i-obman-klient-vsegda-ne-prav', 'https://irecommend.ru/content/moi-priklyucheniya-v-sberbanke', 'https://irecommend.ru/content/apofeoz-marazma', 'https://irecommend.ru/content/karta-momentum-ochen-udobnaya-nuzhnaya-i-prostaya-v-ispolzovanii', 'https://irecommend.ru/content/5050-60', 'https://irecommend.ru/content/moi-sekrety-pochemu-ya-polzuyus-imenno-im', 'https://irecommend.ru/content/zagadochnoe-kodovoe-slovo', 'https://irecommend.ru/content/normalnyi-bank-8', 'https://irecommend.ru/content/razocharovalas-120', 'https://irecommend.ru/content/novogodnii-syurpriz-ot-sberbanka', 'https://irecommend.ru/content/dotoshnye-sotrudniki-pytayutsya-vse-vtyukhat', 'https://irecommend.ru/content/sperbank', 'https://irecommend.ru/content/nachinat-nado-s-sebya', 'https://irecommend.ru/content/telefonnye-strasti-sberbanka', 'https://irecommend.ru/content/lokhotron-v-terminale', 'https://irecommend.ru/content/delayut-dengi-iz-vozdukha-0', 'https://irecommend.ru/content/potrebitelskii-kredit-legko-bystro-dostupno', 'https://irecommend.ru/content/pomenyal-bank-i-zazhil-spokoino', 'https://irecommend.ru/content/esli-ne-nekotorye-sotrudniki-debily-ya-nazvala-ego-khoroshim-ili-kak-mozhno-ostatsya-bez-den']
Парсим отзывы клиентов¶
Имея URL отзывов, будем парсить сами отзывы
Используем две вспомогательные функции
parse_review
дял выгрузки текста отзываparse_additional
которая выгружает дополнительную информацию об отзыве (юзер,дата отзыва,итог,рейтинг)
flatten = lambda l: [item for sublist in l for item in sublist]
'''
Helper function #1
Return review
'''
def parse_review(r,review_url):
page = r.text
soup = BeautifulSoup(page, 'html.parser')
# extract review links
review = soup.find_all(class_='description hasinlineimage')
# review text stored in <p>, can have multiple parts
page_review = []
for i in review:
page_review.append(i.find_all('p'))
# flatten & store only strings
review_text = []
for i in flatten(page_review):
review_text.append(i.get_text())
return review_text
'''
Helper function #2
Return positive points, negative points & conclusion
'''
def parse_additional(r,review_url):
page = r.text
soup = BeautifulSoup(page, 'html.parser')
# extract user
user_id = soup.find(itemprop='url')
if(user_id is not None):
user = user_id.get_text()
else:
user = None
# publish time
date_id = soup.find(itemprop='datePublished')
if(date_id is not None):
date = date_id.get('content')
else:
date = None
# extract user verdict (positive/negative)
conclusion_id = soup.find(class_='verdict')
if(conclusion_id is not None):
conclusion = conclusion_id.get_text()
else:
conclusion = None
# extract user rating (1-5 rating)
rating_id = soup.find(itemprop="ratingValue")
if(rating_id is not None):
rating = rating_id.get("content")
else:
rating = None
return user,date,conclusion,rating
, can have multiple parts page_review = [] for i in review: page_review.append(i.find_all('p')) # flatten & store only strings review_text = [] for i in flatten(page_review): review_text.append(i.get_text()) return review_text ''' Helper function #2 Return positive points, negative points & conclusion ''' def parse_additional(r,review_url): page = r.text soup = BeautifulSoup(page, 'html.parser') # extract user user_id = soup.find(itemprop='url') if(user_id is not None): user = user_id.get_text() else: user = None # publish time date_id = soup.find(itemprop='datePublished') if(date_id is not None): date = date_id.get('content') else: date = None # extract user verdict (positive/negative) conclusion_id = soup.find(class_='verdict') if(conclusion_id is not None): conclusion = conclusion_id.get_text() else: conclusion = None # extract user rating (1-5 rating) rating_id = soup.find(itemprop="ratingValue") if(rating_id is not None): rating = rating_id.get("content") else: rating = None return user,date,conclusion,rating
- Парсим частями (по 100 данных), всего 1000 отзывов + что вполне достаточно для примера
- Данные из парсера сохраняются итеративно в списки
user
,time
,review
,conclusion
,rating
- Из рекомендации, советовали использовать разную дельту для времени операции sleep, используем интервал (15-22с)
'''
Parse Data
'''
# get_data - stores parsed data
def get_data(urls):
# Store parsed data for each reviewer
lst_user = []
lst_time = []
lst_review = []
lst_conclusion = []
lst_rating = []
# cycle through all review links on a single page
for ii,review_link in enumerate(urls):
# send request
r = s.get(review_link)
# r = requests.get(review_link)
if(r.status_code != 200):
print(r.status_code)
break
# store review
lst_review.append(parse_review(r,review_link))
# store additional information
user,time,conclusion,rating = parse_additional(r,review_link)
lst_user.append(user)
lst_time.append(time)
lst_conclusion.append(conclusion)
lst_rating.append(rating)
if(ii%10 == 0):
print(user,conclusion,rating)
print(f'review extracted: {ii}')
# random sleep
t.sleep(randint(15,22))
return lst_user,lst_time,lst_review,lst_conclusion,lst_rating
user,time,review,conclusion,rating = get_data(lst_all_review_sources)
irbisirbis не рекомендует 1 review extracted: 0 Владимирова не рекомендует 1 review extracted: 10 Maritaimi рекомендует 4 review extracted: 20 Frau J не рекомендует 1 review extracted: 30 Елена9924 рекомендует 3 review extracted: 40 kareglazoe_4udo рекомендует 4 review extracted: 50 LubovZ не рекомендует 1 review extracted: 60 дарья2512 рекомендует 4 review extracted: 70 JeNе4еk не рекомендует 1 review extracted: 80 плюшка не рекомендует 1 review extracted: 90
Сбор частичных данных¶
- Так как мы собираем данные частями, сохраним их в
csv
формате, когда все закончим, сохраняем все в единыйcsv
- Как видим,
review
уже под конец стал выдавать пустые данные что может обозначать что либо нас уже частично блокируют, либо в в 2012 году еще не было возможности вводить свои отзыв
# Post process & store data in dataframe
review_concat = []
for lst_review in review:
review_concat.append(" ".join(lst_review))
import pandas as pd
df = pd.DataFrame({'user':user,'time':time,'review':review_concat,'conclusion':conclusion,'rating':rating})
df.to_csv('df_2223.csv')
display(df)
user | time | review | conclusion | rating | |
---|---|---|---|---|---|
0 | irbisirbis | 2013-08-19T21:42:32+02:00 | похоже не один и ни два клиента СБ столкнулись... | не рекомендует | 1 |
1 | hellknows | 2013-08-14T10:46:43+02:00 | Услугами Сбербанка пользуюсь достаточно долго,... | не рекомендует | 3 |
2 | mescaline_ | 2013-08-13T10:03:15+02:00 | Отвратительное обслуживание клиента! Сбербанк ... | не рекомендует | 1 |
3 | DenisDDDDD | 2013-08-13T09:51:49+02:00 | г.Казань Очень отвратительная процедура создан... | не рекомендует | 1 |
4 | Natalia23 | 2013-08-12T17:09:38+02:00 | Еще когда работала стал вопрос о том, где же х... | рекомендует | 4 |
... | ... | ... | ... | ... | ... |
95 | Виктория Юрьевна | 2012-12-12T18:05:00+01:00 | не рекомендует | 1 | |
96 | stasya555 | 2012-12-06T09:56:14+01:00 | не рекомендует | 1 | |
97 | Мотылек | 2012-11-29T16:46:44+01:00 | рекомендует | 5 | |
98 | osvald197934310 | 2012-11-21T04:06:59+01:00 | не рекомендует | 3 | |
99 | vishnya | 2012-11-21T03:35:34+01:00 | рекомендует | 3 |
100 rows × 5 columns
- Итак мы сохранили данные в
csv
df_01,df_23,df_45,df_67,df_89,df_1011,df_1213,df_1415,df_1617,df_1819,df_2021,df_2223 - Итого у нас получилось парсить 1200 отзывов
import os
os.getcwd()
'c:\\otus_nlp-main\\4_parsing'
import os
import pandas as pd
pd_lst = []
for dirname, _, filenames in os.walk('c:\\otus_nlp-main\\4_parsing'):
for filename in filenames:
if('csv' in filename):
pd_lst.append(pd.read_csv(os.path.join(dirname, filename)))
parsed_data = pd.concat(pd_lst,axis=0)
parsed_data = parsed_data.drop(['Unnamed: 0'],axis=1) # забыли сохранить CSV без индекса
parsed_data.head()
user | time | review | conclusion | rating | |
---|---|---|---|---|---|
0 | dncmail | 2023-06-21T08:34:25+02:00 | Поделюсь с вами историей, которая произошла со... | не рекомендует | 2 |
1 | fomicevaa851 | 2023-06-21T07:39:25+02:00 | Сама недавно узнала, что в Сбербанке можно пол... | рекомендует | 5 |
2 | AlexStulov | 2023-06-14T13:52:43+02:00 | Сбер потерял мой миллион. В апреле брал ипотек... | не рекомендует | 1 |
3 | Zakharkot | 2023-06-13T08:04:53+02:00 | Доброго времени суток всем, я открыл в Сбере в... | рекомендует | 5 |
4 | sanaan | 2023-06-11T23:40:00+02:00 | Живу с мамой, оплатой коммунальных платежей до... | рекомендует | 4 |
parsed_data.to_csv('sberbank_reviews.csv',index=False)
3 | Разведывательный Анализ¶
Цель EDA¶
Вернемся к требованием:
- При необходимости очистить датасет от мусора с помощью регулярных выражений.
- Посчитать статистики по собранным данным и провести EDA собранных данных (в случае, если данные представляют собой текст - посчитать частотности слов, выявить наиболее частотные слова и т. п)
- Не забудьте сохранить полученный датасет, он вам еще пригодиться в дальнейших домашних заданиях.
Данные мы сохранили, теперь будем делать разведовательный анализ; особенно нас интересует что клиентам нравится и не нравится в сбербанке
Чистка Текста¶
Сами данные достаточно чиcтые и не содержат лишний мусор, используем библиотеку re
import re
import pandas as pd
sber_reviews = pd.read_csv('sberbank_reviews.csv')
display(sber_reviews.isna().sum())
sber_reviews_edit = sber_reviews.dropna()
user 0 time 0 review 78 conclusion 0 rating 0 dtype: int64
sber_reviews_edit.iloc[4]['review']
'Живу с мамой, оплатой коммунальных платежей долго занималась именно она. Платила она всегда наличкой (карты не открывает принципиально) и через сберкассу – по старинке. Пока ей там не начали говорить, что через терминалы можно платить без комиссии. Вот тут она насела на меня. До терминалов мы так и не дошли, но я начала сама оплачивать счета через мобильное приложение Сбербанка, благо QR-коды в этом сильно помогают. Комиссию за некоторые платежи снимали, но я особо этим не парилась, лишь бы матушка была довольна. Какое-то время мы так и жили, пока я не начала пользоваться картами других банков. И услыхала, что в других банках комиссию за коммуналку не взимают. Я очень удивилась, но решила опробовать. Сначала через один банк. Но то ли у меня QR-код тогда не сработал, и искать по реквизитам организацию я не захотела, так что бросила это дело, и снова перешла на Сбербанк с его комиссией. \n\n\n\n\n\n\n\n\n\n\nПотом пришел черед открыть карту третьего банка, где мне опять напомнили про платежи без комиссии. Плюс появилась программа лояльности, где посулили 5% кешбэк именно за коммуналку. Вот это предложение меня не на шутку заинтересовало. Не только отмена комиссии, дак еще и кешбэк! Сплошная выгода! И я опробовала. И что могу сказать. У каждого банка свои заморочки, свою плюсы и минусы. Например, если брать Сбербанк, то платить через мобильное приложение было легко, быстро и удобно. Все квитанции сканировались, всё было понятно, но да взимали комиссию. А вот через другие банки можно оплачивать коммуналку без комиссии, но там я столкнулась со своими трудностями. В банке, где начисляют кешбэк за коммунальные платежи, я замучилась сканировать QR-коды. Они тупо читались через раз. Приложение выбивало и сбоило, когда я пыталась навести камеру на QR-код. Мне пришлось искать организации по реквизитам. И пока я с этим делом настойчиво разбиралась, у меня возникло ощущение, что пару платежей я перевела просто не туда! Выяснить это я смогла только через месяц, когда пришли новые квитанции. На удивление оказалось, что все платежи прошли, это хорошо. Поэтому будьте готовы искать организации по реквизитам. Но в этом плане вам помогут сохраненные шаблоны. Потом я попробовала платить через третий банк, и там проблем с чтением QR-кодов уже не возникло, так что оказалось, что есть из чего выбирать. В целом для меня стало открытием, что платить коммуналку через мобильное приложение банков можно без комиссии. Ну, или по старинке, с комиссией через Сбербанк – выбирайте сами.'
sber_reviews_edit.iloc[7]['review']
'Оформили родителям карты МИР. Папе 71, маме 75. Папа ходит более-менее, мама практически не ходит. С трудом и на 2 костылях. Доехали на такси, получили, вернулись домой на такси. На планшете вошли в ЛК папы, все отлично. Вышли, попытались войти в ЛК мамы - пришла СМС, что ЛК заблокирован. Попробовали обратно в папин ЛК зайти - и тот уже заблокирован. Позвонили 900 - нам сказали, что для разблокировки надо ПРИЙТИ В ОТДЕЛЕНИЕ И НАПИСАТЬ ЗАЯВЛЕНИЕ!!! Вот это что вообще??? Клиентоориентированность??? Сколько такси надо ещё вызвать, чтобы всё нормально заработало??? Сами карты работают, вопросов нет. В списке достоинств галки "Можно не ходить в банк" и "Не нужно выходить из дома" выглядят как откровенное издевательство. Короче - отстой. У меня самого Тиньков, Альфа и Сбер. Сбером много лет не пользуюсь. Видимо, к счастью. Резюме: нам проще порезать и выкинуть эти карты и оформить тот же Тиньков. Там менеджеры сами приезжают и на дому оформляют, а не просят хронически больных людей со слезами ползти в отделение!!! \xa0 P.S.: 1 поставил только потому что 0 не предлагается. Не тянет этот сервис на 1.'
def clean(ltext):
ltext = re.sub(r':.+?:', '', ltext)
ltext = re.sub(r'\xa0','',ltext)
ltext = re.sub(r'[\n]','',ltext)
return ltext
sber_reviews_edit['review'].apply(clean)[4]
'Живу с мамой, оплатой коммунальных платежей долго занималась именно она. Платила она всегда наличкой (карты не открывает принципиально) и через сберкассу – по старинке. Пока ей там не начали говорить, что через терминалы можно платить без комиссии. Вот тут она насела на меня. До терминалов мы так и не дошли, но я начала сама оплачивать счета через мобильное приложение Сбербанка, благо QR-коды в этом сильно помогают. Комиссию за некоторые платежи снимали, но я особо этим не парилась, лишь бы матушка была довольна. Какое-то время мы так и жили, пока я не начала пользоваться картами других банков. И услыхала, что в других банках комиссию за коммуналку не взимают. Я очень удивилась, но решила опробовать. Сначала через один банк. Но то ли у меня QR-код тогда не сработал, и искать по реквизитам организацию я не захотела, так что бросила это дело, и снова перешла на Сбербанк с его комиссией. Потом пришел черед открыть карту третьего банка, где мне опять напомнили про платежи без комиссии. Плюс появилась программа лояльности, где посулили 5% кешбэк именно за коммуналку. Вот это предложение меня не на шутку заинтересовало. Не только отмена комиссии, дак еще и кешбэк! Сплошная выгода! И я опробовала. И что могу сказать. У каждого банка свои заморочки, свою плюсы и минусы. Например, если брать Сбербанк, то платить через мобильное приложение было легко, быстро и удобно. Все квитанции сканировались, всё было понятно, но да взимали комиссию. А вот через другие банки можно оплачивать коммуналку без комиссии, но там я столкнулась со своими трудностями. В банке, где начисляют кешбэк за коммунальные платежи, я замучилась сканировать QR-коды. Они тупо читались через раз. Приложение выбивало и сбоило, когда я пыталась навести камеру на QR-код. Мне пришлось искать организации по реквизитам. И пока я с этим делом настойчиво разбиралась, у меня возникло ощущение, что пару платежей я перевела просто не туда! Выяснить это я смогла только через месяц, когда пришли новые квитанции. На удивление оказалось, что все платежи прошли, это хорошо. Поэтому будьте готовы искать организации по реквизитам. Но в этом плане вам помогут сохраненные шаблоны. Потом я попробовала платить через третий банк, и там проблем с чтением QR-кодов уже не возникло, так что оказалось, что есть из чего выбирать. В целом для меня стало открытием, что платить коммуналку через мобильное приложение банков можно без комиссии. Ну, или по старинке, с комиссией через Сбербанк – выбирайте сами.'
sber_reviews_edit['review'].apply(clean)[7]
'Оформили родителям карты МИР. Папе 71, маме 75. Папа ходит более-менее, мама практически не ходит. С трудом и на 2 костылях. Доехали на такси, получили, вернулись домой на такси. На планшете вошли в ЛК папы, все отлично. Вышли, попытались войти в ЛК мамы - пришла СМС, что ЛК заблокирован. Попробовали обратно в папин ЛК зайти - и тот уже заблокирован. Позвонили 900 - нам сказали, что для разблокировки надо ПРИЙТИ В ОТДЕЛЕНИЕ И НАПИСАТЬ ЗАЯВЛЕНИЕ!!! Вот это что вообще??? Клиентоориентированность??? Сколько такси надо ещё вызвать, чтобы всё нормально заработало??? Сами карты работают, вопросов нет. В списке достоинств галки "Можно не ходить в банк" и "Не нужно выходить из дома" выглядят как откровенное издевательство. Короче - отстой. У меня самого Тиньков, Альфа и Сбер. Сбером много лет не пользуюсь. Видимо, к счастью. Резюме 1 поставил только потому что 0 не предлагается. Не тянет этот сервис на 1.'
sber_reviews_edit['review_cleaned'] = sber_reviews_edit['review'].apply(clean)
C:\Users\abduv\AppData\Local\Temp\ipykernel_28680\2578540058.py:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy sber_reviews_edit['review_cleaned'] = sber_reviews_edit['review'].apply(clean)
sber_reviews_edit.to_csv('review_cleaned.csv',index=False)
Токенизация Текста¶
- Токенизируем наши документы для того чтобы понять содержание текста
- Мы можем с помощью unigram,bigram,trigram и тд, для того что-то понять о содержание отзыва
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
from string import punctuation
stopwords = stopwords.words("russian") # stop words
def tokenise_documents(corpus:pd.Series):
# define a function for preprocessing
def text_cleaning(ltext):
ltext = ltext.lower() #changes to lower case
tokens = word_tokenize(ltext) #tokenize the text
punctuation_double = ['``',"''"]
clean_list = []
for token in tokens:
if (token not in stopwords):
if(token not in punctuation and token not in punctuation_double):
clean_list.append(token)
return " ".join(clean_list)# joins the tokens
return corpus.apply(text_cleaning)
tokenised_corpus = tokenise_documents(sber_reviews_edit['review'])
Частоты слов положительных отзывов¶
- Используем вспомогательная функция для создания н-грамм для каждого документа в корпусе
- Положительных отзывов достаточно много
from collections import Counter
def n_grams(tokens,n):
lst_bigrams = [' '.join(i) for i in [tokens[i:i+n] for i in range(len(tokens)-n+1)]]
return lst_bigrams
recommend = sber_reviews_edit[sber_reviews_edit['conclusion'] == 'рекомендует']
tokenised_corpus = tokenise_documents(recommend['review'])
print(recommend.shape)
# x-gram lists
tokenised_documents = [i.split(' ') for i in tokenised_corpus]
tokenised_documents_bigram = [n_grams(i.split(' '),2) for i in tokenised_corpus]
tokenised_documents_trigram = [n_grams(i.split(' '),3) for i in tokenised_corpus]
tokenised_documents_quadragram = [n_grams(i.split(' '),4) for i in tokenised_corpus]
(548, 5)
Counter(x for xs in tokenised_documents for x in set(xs)).most_common(20)
[('это', 413), ('сбербанка', 330), ('сбербанк', 318), ('деньги', 318), ('очень', 305), ('банк', 304), ('карту', 267), ('банка', 244), ('карты', 242), ('просто', 229), ('спасибо', 203), ('нужно', 202), ('сбербанке', 181), ('время', 180), ('сразу', 176), ('карта', 172), ('онлайн', 171), ('рублей', 169), ('денег', 165), ('лет', 163)]
Counter(x for xs in tokenised_documents_bigram for x in set(xs)).most_common(20)
[('сбербанк онлайн', 121), ('мобильный банк', 77), ('очень удобно', 71), ('спасибо сбербанка', 59), ('карту сбербанка', 48), ('следующий день', 44), ('это очень', 42), ('кредитную карту', 41), ('дебетовую карту', 36), ('3 года', 35), ('кредитная карта', 34), ('всем привет', 34), ('льготный период', 33), ('карта сбербанка', 33), ('отделение сбербанка', 33), ('других банках', 32), ('это время', 32), ('бонусы спасибо', 32), ('каждый месяц', 32), ('процентная ставка', 32)]
Counter(x for xs in tokenised_documents_trigram for x in set(xs)).most_common(20)
[('доброго времени суток', 28), ('это очень удобно', 19), ('являюсь клиентом сбербанка', 12), ('всем доброго времени', 11), ('бонусная программа спасибо', 11), ('приложение сбербанк онлайн', 10), ('всем привет сегодня', 10), ('услугами сбербанка пользуюсь', 9), ('период 50 дней', 9), ('бонусы спасибо сбербанка', 9), ('сбербанк онлайн очень', 9), ('60 рублей месяц', 8), ('подключен мобильный банк', 8), ('пользуюсь услугами сбербанка', 7), ('« спасибо сбербанка', 7), ('спасибо сбербанка »', 7), ('« сбербанк »', 7), ('карту другого банка', 7), ('льготный период 50', 7), ('дебетовую карту сбербанка', 7)]
Counter(x for xs in tokenised_documents_quadragram for x in set(xs)).most_common(20)
[('всем доброго времени суток', 11), ('« спасибо сбербанка »', 7), ('льготный период 50 дней', 7), ('« мобильный банк »', 5), ('доброго времени суток сегодня', 5), ('-- -- -- --', 4), ('времени суток сегодня хочу', 4), ('универсальный договор банковского обслуживания', 4), ('заработную плату карту сбербанка', 3), ('получала стипендию карту сбербанка', 3), ('хочу рассказать своем опыте', 3), ('спасибо внимание надеюсь отзыв', 3), ('внимание надеюсь отзыв полезен', 3), ('« сбербанк россии »', 3), ('полный пакет мобильного банка', 3), ('получаю зарплату карту сбербанка', 3), ('услугами сбербанка пользуюсь давно', 3), ('мобильном приложении сбербанк онлайн', 3), ('« сбербанк онлайн »', 3), ('пользуюсь услугой мобильный банк', 3)]
Выводы¶
Позитивных тем в отзывах много:
бонусная программа спасибо
, приложение сбербанк онлай
, льготный период 50 дней
, мобильный банк
Возможные причины положительных отзывов:
- программа спасибо больше ассоциируется с положительными отзывами
- удобство приложения сбербанка онлайн и мобильного банка
- большой льготный период для кредитно карты
Частоты слов негативных отзывов¶
- Рассмотрим отзывы клиентов которые не рекомендовали сбербанк, и найдем ключевые темы
- Это поможет нам быстро понять что конкретно не устраивает клиентов
not_recommend = sber_reviews_edit[sber_reviews_edit['conclusion'] == 'не рекомендует']
print(not_recommend.shape)
(574, 5)
tokenised_corpus = tokenise_documents(not_recommend['review'])
tokenised_documents = [i.split(' ') for i in tokenised_corpus]
tokenised_documents_bigram = [n_grams(i.split(' '),2) for i in tokenised_corpus]
tokenised_documents_trigram = [n_grams(i.split(' '),3) for i in tokenised_corpus]
tokenised_documents_quadragram = [n_grams(i.split(' '),4) for i in tokenised_corpus]
Counter(x for xs in tokenised_documents for x in set(xs)).most_common(20)
[('это', 448), ('банк', 384), ('деньги', 354), ('сбербанк', 346), ('банка', 345), ('сбербанка', 331), ('карту', 316), ('карты', 295), ('просто', 242), ('очень', 231), ('время', 225), ('карта', 200), ('день', 195), ('...', 192), ('денег', 189), ('нужно', 185), ('рублей', 182), ('отделение', 181), ('банке', 172), ('сразу', 164)]
Counter(x for xs in tokenised_documents_bigram for x in set(xs)).most_common(30)
[('сбербанк онлайн', 91), ('мобильный банк', 76), ('следующий день', 57), ('горячую линию', 56), ('отделение сбербанка', 56), ('отделение банка', 45), ('это время', 45), ('карту сбербанка', 45), ('горячей линии', 43), ('кредитную карту', 41), ('сих пор', 40), ('другом банке', 39), ('свои деньги', 35), ('денежных средств', 35), ('этим банком', 34), ('мои деньги', 33), ('другого банка', 33), ('карты сбербанка', 30), ('2 недели', 30), ('сотрудники банка', 29), ('таким образом', 29), ('клиентом сбербанка', 29), ('снять деньги', 29), ('номер телефона', 29), ('самое интересное', 29), ('личный кабинет', 28), ('это просто', 28), ('деньги карты', 28), ('других банков', 28), ('личном кабинете', 28)]
Counter(x for xs in tokenised_documents_trigram for x in set(xs)).most_common(30)
[('позвонила горячую линию', 18), ('доброго времени суток', 15), ('каково мое удивление', 10), ('являюсь клиентом сбербанка', 10), ('несколько лет назад', 10), ('ближайшее отделение сбербанка', 9), ('горячую линию сбербанка', 9), ('захожу сбербанк онлайн', 8), ('подключить мобильный банк', 8), ('подключен мобильный банк', 8), ('звонить горячую линию', 8), ('услуга мобильный банк', 7), ('окончания срока действия', 7), ('низкие проценты вкладам', 7), ('приложение сбербанк онлайн', 7), ('звоню горячую линию', 7), ('150 рублей год', 6), ('всем доброго времени', 6), ('тех пор пока', 6), ('срок действия моей', 6), ('карту другого банка', 6), ('это очень удобно', 6), ('60 рублей месяц', 6), ('услугу мобильный банк', 6), ('приложении сбербанк онлайн', 5), ('сегодня хочу рассказать', 5), ('срок действия карты', 5), ('оставляет желать лучшего', 5), ('закончился срок действия', 5), ('заявление закрытие счета', 5)]
Counter(x for xs in tokenised_documents_quadragram for x in set(xs)).most_common(30)
[('всем доброго времени суток', 6), ('позвонила горячую линию сбербанка', 5), ('пользоваться услугами данного банка', 4), ('окончания срока действия карты', 4), ('всем привет сегодня хочу', 3), ('личный кабинет сбербанк онлайн', 3), ('это самый надежный банк', 3), ('начала звонить горячую линию', 3), ('оао « сбербанк россии', 3), ('« сбербанк россии »', 3), ('пао « сбербанк »', 3), ('срок действия моей карты', 3), ('лет являюсь клиентом сбербанка', 3), ('историей которая произошла мной', 2), ('личного кабинета сбербанк онлайн', 2), ('получаю зарплату карту сбербанка', 2), ('привет сегодня хочу рассказать', 2), ('закончился срок действия моей', 2), ('самых низких процентов вкладам', 2), ('одни самых низких процентов', 2), ('истек срок действия моей', 2), ('доброго времени суток друзья', 2), ('сбербанка несколько лет назад', 2), ('тариф полный снимается 60', 2), ('логин пароль личного кабинета', 2), ('полный снимается 60 рублей', 2), ('сумма 50 тысяч рублей', 2), ('будьте бдительны спасибо внимание', 2), ('самые низкие проценты вкладам', 2), ('низкие проценты вкладам высокие', 2)]
Выводы¶
Негативных тем в отзывах достаточно много
горячую линию
, окончания срока действия карты
, личный кабинет сбербанк онлайн
, одни самых низких процентов
, срок действия
, тариф полный снимается 60 рублей
, услугу мобильный банк
, сбербанк онлайн
Возможные причины негативных отзывов:
- это взаимодействие с горячей линии
- возможные проблемы при истеки срока действии карты
- проблемы с личным кабинетом сбербанка онлайн и мобильным банком
- низкий проценты (вкладов)
- тариф на какой то товар (например кредитная карта)