Ravi de vous rencontrer. Je suis N.D., un étudiant universitaire de 4e année appartenant au Département de physique. L'expérience de Python est un peu touchée par moi-même. C'était ma première fois à gratter et à ramper.
La Division de la science des données de Kakko Co., Ltd., qui est actuellement stagiaire, a pour tâche de créer un robot d'exploration pendant la période d'essai pour collecter, traiter et visualiser les données, et discuter brièvement de ce qu'il a appris.
Visualisez et considérez les prix du marché des restaurants à travers Tokyo Acquérir également d'autres variables susceptibles d'être prises et les analyser en les comparant avec le budget.
Le thème étant abstrait, je voudrais mettre en place les situations spécifiques suivantes. situation Utilisez les données pour montrer objectivement aux amis qui viennent à Tokyo: "Quel est le prix du marché des restaurants à Tokyo et quel est le genre le plus sur ce marché?"
Visualisez et montrez ce que vous avez appris pour comparer les budgets avec d'autres variables ainsi que des sous-thèmes.
Cette fois, l'exploration est le résultat de la recherche de "Boutiques qui peuvent faire des réservations en ligne dans tout Tokyo" sur le site gastronomique du piment. Acquisition de 16475 boutiques le mercredi 16 octobre 2019.
** Procédure d'exploration **
Le code d'exploration ressemble à ceci:
crawling.py
from bs4 import BeautifulSoup
import requests
import time
import os
# timer
t1 = time.time()
# function
# get number of shop
def get_num(soup):
num = soup.find('p', {'class':'sercheResult fl'}).find('span', {'class':'fcLRed bold fs18 padLR3'}).text
print('num:{}'.format(num))
# get url of shop
def get_shop_urls(tags):
shop_urls = []
# ignore the first shop because it is PR
tags = tags[1:]
for tag in tags:
shop_url = tag.a.get('href')
shop_urls.append(shop_url)
return shop_urls
def save_shop_urls(shop_urls, dir_path=None, test=False):
# make directry
if test:
if dir_path is None:
dir_path = './html_dir_test'
elif dir_path is None:
dir_path = './html_dir'
if not os.path.isdir(dir_path):
os.mkdir(dir_path)
for i, shop_url in enumerate(shop_urls):
time.sleep(1)
shop_url = 'https://www.hotpepper.jp' + shop_url
r = requests.get(shop_url).text
file_path = 'shop{:0>5}_url.html'.format(i)
with open(dir_path + '/' + file_path, 'w') as f:
f.write(r)
# return last shop number
return len(shop_urls)
start_url = 'https://www.hotpepper.jp/yoyaku/SA11/'
response = requests.get(start_url).text
soup = BeautifulSoup(response, 'html.parser')
tags = soup.find_all('h3', {'class':'detailShopNameTitle'})
# get last page number
last_page = soup.find('li', {'class':'lh27'}).text.replace('1/', '').replace('page', '')
last_page = int(last_page)
print('last page num:{}'.format(last_page))
# get the number of shops before crawling
get_num(soup)
# first page crawling
start_shop_urls = get_shop_urls(tags)
# from 2nd page
shop_urls = []
# last page(test)
last_page = 10 # test
for p in range(last_page-1):
time.sleep(1)
url = start_url + 'bgn' + str(p+2) + '/'
r = requests.get(url).text
soup = BeautifulSoup(r, 'html.parser')
tags = soup.find_all('h3', {'class':'detailShopNameTitle'})
shop_urls.extend(get_shop_urls(tags))
# how speed
if p % 100 == 0:
percent = p/last_page*100
print('{:.2f}% Done'.format(percent))
start_shop_urls.extend(shop_urls)
shop_urls = start_shop_urls
t2 = time.time()
elapsed_time = t2 - t1
print('time(get_page):{:.2f}s'.format(elapsed_time))
print('num(shop_num):{}'.format(len(shop_urls)))
# get the url of shop
last_num = save_shop_urls(shop_urls) # html_dir
# get the number of shops after crawling
get_num(soup)
t3 = time.time()
elapsed_time = t3 - t1
print('time(get_html):{:.2f}s'.format(elapsed_time))
print('num(shop_num):{}'.format(last_num))
Voici les variables grattées cette fois.
procédure
Le code de scraping ressemble à ceci:
scraping.py
from bs4 import BeautifulSoup
import glob
import requests
import time
import os
import pandas as pd
from tqdm import tqdm
import numpy as np
def get_shopinfo(category, soup):
shopinfo_th = soup.find('div', {'class':'shopInfoDetail'}).find_all('th')
# get 'category' from 'shopinfo_th'
category_value = list(filter(lambda x: category in x , shopinfo_th))
if not category_value:
category_value = None
else:
category_value = category_value[0]
category_index = shopinfo_th.index(category_value)
shopinfo_td = soup.find('div', {'class':'shopInfoDetail'}).find_all('td')
category_value = shopinfo_td[category_index].text.replace('\n', '').replace('\t', '')
return category_value
# judge [] or in
def judge(category):
if category is not None:
category = category.text.replace('\n', '').replace('\t', '')
else:
category = np.nan
return category
# judge [] or in
def judge_atag(category):
if category is not None:
category = category.a.text.replace('\n', '').replace('\t', '')
else:
category = np.nan
return category
# judge [] or in
def judge_ptag(category):
if category is not None:
category = category.p.text.replace('\n', '').replace('\t', '')
else:
category = np.nan
return category
# judge [] or in
def judge_spantag(category):
if category is not None:
category = category.span.text.replace('\n', '').replace('\t', '')
else:
category = 0
return category
# available=1, not=0
def available(strlist):
available_flg = 0
if 'disponible' in strlist:
available_flg = 1
return available_flg
# categorize money
def category2index(category, range):
if category in range:
category = range.index(category)
return category
def scraping(html, df, price_range):
soup = BeautifulSoup(html, 'html.parser')
dinner = soup.find('span', {'class':'shopInfoBudgetDinner'})
dinner = judge(dinner)
dinner = category2index(dinner, price_range)
lunch = soup.find('span', {'class':'shopInfoBudgetLunch'})
lunch = judge(lunch)
lunch = category2index(lunch, price_range)
genre_tag = soup.find_all('dl', {'class':'shopInfoInnerSectionBlock cf'})[1]
genre = genre_tag.find('p', {'class':'shopInfoInnerItemTitle'})
genre = judge_atag(genre)
area_tag = soup.find_all('dl', {'class':'shopInfoInnerSectionBlock cf'})[2]
area = area_tag.find('p', {'class':'shopInfoInnerItemTitle'})
area = judge_atag(area)
rating = soup.find('div', {'class':'ratingInfo'})
rating = judge_ptag(rating)
review = soup.find('p', {'class':'review'})
review = judge_spantag(review)
f_meter = soup.find_all('dl', {'class':'featureMeter cf'})
# if 'f_meter' is nan, 'size'='customer'='people'='peek'=nan
if f_meter == []:
size = np.nan
customer = np.nan
people = np.nan
peek = np.nan
else:
meterActive = f_meter[0].find('span', {'class':'meterActive'})
size = f_meter[0].find_all('span').index(meterActive)
meterActive = f_meter[1].find('span', {'class':'meterActive'})
customer = f_meter[1].find_all('span').index(meterActive)
meterActive = f_meter[2].find('span', {'class':'meterActive'})
people = f_meter[2].find_all('span').index(meterActive)
meterActive = f_meter[3].find('span', {'class':'meterActive'})
peek = f_meter[3].find_all('span').index(meterActive)
credits = get_shopinfo('carte de crédit', soup)
credits = available(credits)
emoney = get_shopinfo('Monnaie électronique', soup)
emoney = available(emoney)
data = [lunch, dinner, genre, area, float(rating), review, size, customer, people, peek, credits, emoney]
s = pd.Series(data=data, index=df.columns, name=str(i))
df = df.append(s)
return df
columns = ['budget(Le midi)', 'budget(Nuit)', "Genre", "zone", 'Évaluation', 'Nombre d'avis', 'Taille de la boutique'
, 'Clientèle', 'Nombre de personnes/ensemble', 'Heures de pointe', 'carte de crédit', 'Monnaie électronique']
base_url = 'https://www.hotpepper.jp/SA11/'
response = requests.get(base_url).text
soup = BeautifulSoup(response, 'html.parser')
# GET range of price
price_range = soup.find('ul', {'class':'samaColumnList'}).find_all('a')
price_range = [p.text for p in price_range]
# price_range = ['~ 500 yens', '501 à 1 000 yens', '1001 à 1500 yens', '1501 à 2000 yens', '2001 à 3000 yens', '3001 à 4000 yens', '4001 à 5000 yens'
# , '5001 à 7000 yens', '7001-10000 yens', '10001 à 15000 yens', '15001 à 20000 yens', '20001 ~ 30000 yens', '30001 yens ~']
num = 16475 # number of data
# num = 1000 # test
df = pd.DataFrame(data=None, columns=columns)
for i in range(num):
# for i in tqdm(lis):
html = './html_dir/shop{:0>5}_url.html'.format(i)
with open(html,"r", encoding='utf-8') as f:
shop_html = f.read()
df = scraping(shop_html, df, price_range)
if i % 1600 == 0:
percent = i/num*100
print('{:.3f}% Done'.format(percent))
df.to_csv('shop_info.csv', encoding='shift_jis')
Les résultats d'acceptation sont les suivants.
L'exploration a pris un peu moins d'une heure, le site a donc été mis à jour pendant cette période. Vous pouvez voir qu'il existe une différence entre le nombre de magasins qui étaient initialement et le nombre de magasins après l'exploration.
"Visualisez le prix du marché des restaurants à Tokyo, Précisez quel genre de magasins est le plus populaire dans cette gamme de prix. "
Les données sous-jacentes sont présentées ci-dessous dans l'ordre.
Nous avons visualisé le prix du marché du budget séparément pour le dîner et le déjeuner.
À partir des résultats ci-dessus, nous avons trouvé un prix de marché approximatif pour les restaurants à Tokyo, alors visualisons les genres par gamme de prix.
** Genres inclus dans "Autre" ** Pour le dîner et le déjeuner, les genres suivants avec un petit nombre sont inclus dans "Autre". [Oshiyaki / Monja / Café / Bonbons / Ramen / Coréen / International / Occidental / Créatif / Autre gastronomique]
Je pensais que le "Tavern" dans la fourchette de prix de "500-1000 yens" était trop bon marché pour le déjeuner, donc je vais creuser plus profondément ici.
Comme indiqué ci-dessous, on peut constater que le menu du midi est proposé pendant la journée, même s'il s'appelle "Izakaya".
―― La clientèle des magasins dans la fourchette de prix de «** 7 000 yens à » pour le dîner a tendance à être plus masculine que les femmes, et le dîner et le déjeuner sont de « 1 000 à 3 000 yens **». La clientèle des magasins de la gamme de prix a tendance à être plus féminine que masculine.
―― Plus la fourchette de prix pour le dîner et le déjeuner est élevée, plus la note est élevée.
-Dans la ** gamme de prix haut **, de nombreux magasins acceptent ** les cartes de crédit **
――Les magasins dans la fourchette de prix "** 2000-4000 yens **" pour le dîner ont tendance à avoir une large ** capacité **.
Voici les données à l'appui.
Nous avons comparé la fourchette de prix par clientèle.
De là, on peut dire que la clientèle des magasins dans la fourchette de prix de "7 000 yens" a tendance à être plus masculine que les clientes au dîner, et le prix de "1000-3000 yens" pour le dîner et le déjeuner. Il a été constaté que la clientèle de la boutique obi a tendance à avoir plus de femmes que de clients masculins.
Nous tracerons les notes pour chacune des gammes de prix du dîner et du déjeuner. À cette époque, il y a beaucoup de magasins avec la même évaluation dans la même gamme de prix, nous avons donc adopté le jittering et intentionnellement décalé l'intrigue. Le résultat du test t est indiqué sous le graphique. ** Définition du test t ** Dîner: groupe par magasins à moins de 4000 yens et magasins à plus de 4000 yens Déjeuner: groupe par magasins à moins de 2000 yens et magasins à plus de 2000 yens Vous pouvez voir que plus la fourchette de prix pour le dîner et le déjeuner est élevée, plus la note a tendance à être élevée. D'après le résultat du test t, on peut dire qu'il existe une différence d '«** évaluation **» entre la fourchette de prix élevée et la fourchette de prix bas.
Nous avons comparé le statut d'utilisation des cartes de crédit par fourchette de prix.
Encore une fois, conformément à mon intuition, j'ai constaté qu'un grand pourcentage de magasins de la ** gamme de prix élevés ** acceptent ** les cartes de crédit **. De plus, la fourchette de prix «10 000 yens ~» pour le déjeuner n'est pas affichée car le nombre de caisses n'était pas suffisant pour être évalué.
Nous avons comparé les tailles des magasins évalués sur une échelle de 5 points par gamme de prix. Comme je ne pourrais conclure que le dîner ici, il ne sera affiché que là-bas. Plus le bleu est foncé, plus la boutique est large. Vous pouvez voir que les magasins dans la gamme de prix de «2000-4000 yens» ont tendance à avoir une grande capacité pour le dîner. Étant donné que le ratio de tavernes est important dans cette gamme de prix, on pense que les tavernes de grande capacité sont grandes.
Je me suis rendu compte à quel point il est difficile de «collecter les informations obtenues en grattant et de les visualiser afin que la conclusion puisse être transmise à l'autre partie». ** Si vous recommencez ** Définissez un objectif clair pour l'analyse avant d'écrire du code et calculez à nouveau pour planifier le processus
** A reçu un examen de code ** J'ai reçu les points suivants, et je voudrais l'améliorer par la suite.
** Après la revue de l'annonce ** C'était un processus de "comment montrer le graphique pour le rendre plus facile à transmettre". Nous avons reçu des commentaires selon lesquels il est important de créer un «graphique intuitif», par exemple en disant que plus la fourchette de prix est élevée, plus la fourchette de prix est élevée et que la densité est exprimée par la gigue. J'ai également appris que montrer une conclusion semblable à une histoire mène à la compréhension de l'autre partie. Je passerai ma future vie d'analyse tout en sachant comment relier les résultats obtenus à des problèmes réels.