Freut mich, dich kennenzulernen. Ich bin N.D., ein Universitätsstudent im 4. Jahr, der zum Fachbereich Physik gehört. Die Erfahrung von Python ist von mir ein wenig berührt. Es war mein erstes Mal, dass ich kratzte und krabbelte.
Die Data Science Division der Kakko Co., Ltd., die derzeit ein Praktikant ist, hat die Aufgabe, während des Testzeitraums einen Crawler zu erstellen, um die Daten zu sammeln, zu verarbeiten, zu visualisieren und kurz zu diskutieren, was sie gelernt haben.
Visualisieren und berücksichtigen Sie die Marktpreise von Restaurants in ganz Tokio Erfassen Sie auch andere Variablen, die wahrscheinlich verwendet werden, und analysieren Sie sie, während Sie sie mit dem Budget vergleichen.
Da das Thema abstrakt ist, möchte ich die folgenden spezifischen Situationen einrichten. Lage Verwenden Sie Daten, um Freunden, die nach Tokio kommen, objektiv zu zeigen: "Was ist der Marktpreis für Restaurants in Tokio und welches Genre ist das größte auf diesem Markt?"
Visualisieren und zeigen Sie, was Sie gelernt haben, um Budgets mit anderen Variablen und Unterthemen zu vergleichen.
Dieses Mal ist Crawlen das Suchergebnis von "Geschäfte, die Online-Reservierungen in ganz Tokio vornehmen können" auf der Gourmet-Website für Paprika. Erwerb von 16475 Geschäften am Mittwoch, 16. Oktober 2019.
** Crawling-Verfahren **
Der Crawler-Code sieht folgendermaßen aus:
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('Seite', '')
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))
Das Folgende sind die Variablen, die dieses Mal abgekratzt wurden.
Verfahren
Der Scraping-Code sieht folgendermaßen aus:
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 'verfügbar' 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('Kreditkarte', soup)
credits = available(credits)
emoney = get_shopinfo('Elektronisches Geld', 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(Mittag)', 'Budget(Nacht)', "Genre", "Bereich", 'Auswertung', 'Anzahl der Bewertungen', 'Ladengröße'
, 'Kundenbasis', 'Anzahl der Personen/einstellen', 'Stoßzeiten', 'Kreditkarte', 'Elektronisches Geld']
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 Yen', '501-1000 Yen', '1001-1500 Yen', '1501-2000 Yen', '2001-3000 Yen', '3001-4000 Yen', '4001-5000 Yen'
# , '5001 ~ 7000 Yen', '7001-10000 Yen', '10001-15000 Yen', '15001 ~ 20000 Yen', '20001 ~ 30000 Yen', '30001 Yen ~']
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')
Die Akzeptanzergebnisse sind wie folgt.
Das Crawlen dauerte etwas weniger als eine Stunde, daher wurde die Site während dieser Zeit aktualisiert. Sie können sehen, dass es einen Unterschied zwischen der Anzahl der Geschäfte, die ursprünglich vorhanden waren, und der Anzahl der Geschäfte nach dem Crawlen gibt.
"Visualisieren Sie den Marktpreis von Restaurants in Tokio, Klären Sie, welches Genre von Geschäften in dieser Preisklasse am beliebtesten ist. ""
Die zugrunde liegenden Daten werden unten in der angegebenen Reihenfolge angezeigt.
Wir haben den Marktpreis des Budgets für Abendessen und Mittagessen separat visualisiert.
Aus den obigen Ergebnissen haben wir einen ungefähren Marktpreis für Restaurants in Tokio ermittelt. Lassen Sie uns also die Genres nach Preisklassen visualisieren.
** Genres in "Sonstige" enthalten ** Sowohl zum Abendessen als auch zum Mittagessen sind die folgenden Genres mit einer kleinen Anzahl in "Andere" enthalten. [Oshiyaki / Monja / Cafe / Süßigkeiten / Ramen / Koreanisch / International / Westlich / Kreativ / Anderer Gourmet]
Ich dachte, dass die "Taverne" in der Preisklasse von "500-1000 Yen" zu billig für das Mittagessen war, also werde ich hier tiefer graben.
Wie unten gezeigt, ist zu sehen, dass das Mittagsmenü tagsüber angeboten wird, obwohl es "Izakaya" heißt.
――Der Kundenstamm von Geschäften in der Preisspanne von "** 7.000 Yen bis " für das Abendessen ist tendenziell männlicher als für weibliche Kunden, und sowohl das Abendessen als auch das Mittagessen betragen " 1000 bis 3000 Yen **". Der Kundenstamm von Geschäften in der Preisklasse ist eher weiblich als männlich.
―― Je höher die Preisspanne für Abendessen und Mittagessen ist, desto höher ist tendenziell die Bewertung.
-In der ** hohen Preisspanne ** gibt es viele Geschäfte, die ** Kreditkarten ** akzeptieren
――Läden in der Preisklasse von "** 2000-4000 Yen **" zum Abendessen haben in der Regel eine große ** Kapazität **.
Das Folgende sind die unterstützenden Daten.
Wir haben die Preisspanne nach Kundenstamm verglichen.
Daraus lässt sich ableiten, dass der Kundenstamm von Geschäften in der Preisspanne von "7.000 Yen" beim Abendessen eher männlich als weiblich ist und der Preis für Abendessen und Mittagessen "1000-3000 Yen" beträgt. Es wurde festgestellt, dass der Kundenstamm des Obi-Shops tendenziell mehr weibliche als männliche Kunden hat.
Wir zeichnen die Bewertungen für jede Preisklasse für Abendessen und Mittagessen auf. Zu dieser Zeit gibt es viele Geschäfte mit der gleichen Bewertung in der gleichen Preisklasse, daher haben wir Jittering angewendet und die Handlung absichtlich verschoben. Das Ergebnis des t-Tests ist unter der Grafik dargestellt. ** Definition von t Test ** Abendessen: Gruppieren Sie nach Geschäften unter 4000 Yen und Geschäften über 4000 Yen Mittagessen: Gruppiert nach Geschäften unter 2000 Yen und Geschäften über 2000 Yen Sie können sehen, dass die Bewertung tendenziell umso höher ist, je höher die Preisspanne für Abendessen und Mittagessen ist. Aus dem Ergebnis des t-Tests kann gesagt werden, dass es einen Unterschied in der "** Bewertung **" zwischen der hohen Preisspanne und der niedrigen Preisspanne gibt.
Wir haben den Nutzungsstatus von Kreditkarten nach Preisklassen verglichen.
Entsprechend meiner Intuition stellte ich wieder fest, dass ein großer Prozentsatz der Geschäfte in der ** hohen Preisklasse ** Kreditkarten ** akzeptiert. Außerdem wird die Preisspanne von "10.000 Yen ~" für das Mittagessen nicht angezeigt, da die Anzahl der Fälle nicht ausreichte, um sie zu bewerten.
Wir haben die Größe der Geschäfte auf einer 5-Punkte-Skala nach Preisspanne verglichen. Da ich hier nur das Abendessen abschließen konnte, wird es nur dort veröffentlicht. Je dunkler das Blau, desto breiter der Laden. Sie können sehen, dass Geschäfte in der Preisklasse von "2000-4000 Yen" tendenziell eine große Kapazität für das Abendessen haben. Da das Verhältnis der Tavernen in dieser Preisklasse groß ist, wird angenommen, dass Tavernen mit einer großen Kapazität groß sind.
Ich erkannte selbst, wie schwierig es ist, "die durch Schaben erhaltenen Informationen zu sammeln und zu visualisieren, damit die Schlussfolgerung an die andere Partei weitergegeben werden kann". ** Wenn du es noch einmal machst ** Legen Sie einen klaren Zweck für die Analyse fest, bevor Sie Code schreiben, und rechnen Sie zurück, um den Prozess zu planen
** Codeüberprüfung erhalten ** Ich habe die folgenden Punkte erhalten und möchte sie danach verbessern.
--Schreiben Sie Code, während Sie die Python-Code-Konvention pep8 kennen
** Nach der Ankündigung Überprüfung ** Es war ein Prozess, "wie man das Diagramm zeigt, um es einfacher zu vermitteln". Wir haben die Rückmeldung erhalten, dass es wichtig ist, ein "intuitives Diagramm" zu erstellen, z. B. je höher die Preisspanne und je höher die Dichte und je dichter es ist. Ich habe auch gelernt, dass das Zeigen einer geschichtenähnlichen Schlussfolgerung zum Verständnis der anderen Partei führt. Ich werde mein zukünftiges Analyseleben damit verbringen, mir bewusst zu sein, wie ich die erzielten Ergebnisse mit echten Problemen in Verbindung bringen kann.
Recommended Posts