Die URL jedes Shops in Tokio hat die Form "//tabelog.com/tokyo/A .... / A ...... / ........ /". Es ist geworden. Im Fall eines Shops in Shibuya lautet die URL beispielsweise "//tabelog.com/tokyo/A1303/A130301/......../" und "Eat log / Tokyo / Shibuya / Ebisu / Daikanyama /". Es kann als "Shibuya / spezifischer Laden /" interpretiert werden. Wenn Sie sich die oberste Seite des Lebensmittelprotokolls ansehen, finden Sie Daten bis zu "// tabelog.com/tokyo/A .... /" anstelle von "Suche nach Gebiet". Ich werde diese also zuerst erhalten. Wie erwartet benötigen wir nicht alle Daten für das gesamte Land. Nachdem wir einen großen Bereich eingegrenzt haben, erhalten wir nur die gewünschten Daten.
import numpy as np
import pandas as pd
import requests
from bs4 import BeautifulSoup
import time
root_url = 'https://tabelog.com/'
res = requests.get(root_url)
soup = BeautifulSoup(res.content, 'html.parser')
Ich habe es mit Beautiful Soup so analysiert, und als ich hineinschaute,
<h2 class="rsttop-heading1 rsttop-search__title">
Suche nach Gebiet
</h2>
</div>
<ul class="rsttop-area-search__list">
<li class="rsttop-area-search__item">
<a class="rsttop-area-search__target js-area-swicher-target" data-swicher-area-list='[{"areaName":"Ginza / Shimbashi / Yurakucho","url":"/tokyo/A1301/"},{"areaName":"Tokio / Nihonbashi","url":"/tokyo/A1302/"},{"areaName":"Shibuya / Ebisu / Daikanyama","url":"/tokyo/A1303/"},...
↑ Die Daten, die Sie hier haben möchten! !!
a = soup.find_all('a', class_='rsttop-area-search__target js-area-swicher-target')
a[0].get('data-swicher-area-list')
Wenn du es so machst
'[{"areaName":"Ginza / Shimbashi / Yurakucho","url":"/tokyo/A1301/"},{"areaName":"Tokio / Nihonbashi","url":"/tokyo/A1302/"},{"areaName":"Shibuya / Ebisu / Daikanyama","url":"/tokyo/A1303/"},...
Und so weiter. Ich dachte jedoch, dass es eine schöne Liste von Wörterbüchern war, aber es war komplett eine Zeichenkette. .. .. Also habe ich versucht herauszufinden, wie es geht, aber ich konnte es nicht finden, also werde ich es gewaltsam in der erforderlichen Form reparieren, obwohl es nicht gut ist. Wenn Sie wissen, wie Sie den Prozess hier reibungslos abwickeln können, lassen Sie es mich bitte wissen!
splitted = a[0].get('data-swicher-area-list').split('"')
area_dict = {}
for i in range(int((len(splitted)-1)/8)):
area_dict[splitted[i*8+3]] = splitted[i*8+7]
Damit gelang es mir, das folgende Wörterbuch zu erhalten.
{'Ueno / Asakusa / Nippori': '/tokyo/A1311/',
'Ryogoku, Kinshicho, Koiwa': '/tokyo/A1312/',
'Nakano-Nishiogikubo': '/tokyo/A1319/',...
Um ehrlich zu sein, Tokio allein ist in Ordnung, aber wenn Sie es umfassend erhalten möchten, ist es wie folgt.
area_url = {}
for area in a:
area_dict = {}
splitted = area.get('data-swicher-area-list').split('"')
for i in range(int((len(splitted)-1)/8)):
area_dict[splitted[i*8+3]] = splitted[i*8+7]
area_url[area.get('data-swicher-city').split('"')[3]] = area_dict
Was mich unterwegs interessierte, war len (area_url) = 47 für len (a) = 53. Als ich es nachgeschlagen habe, war die Ursache, dass Tokio, Kanagawa, Aichi, Osaka, Kyoto und Fukuoka zweimal erschienen, aber der Inhalt war für den Teil, den ich wollte, der gleiche, also sagte ich, dass der obige Code den Zweck erreicht hat. Es wurde beurteilt. Die URL erhalten Sie in der folgenden Form.
area_url
│
├──'Tokio'
│ ├──'Ueno / Asakusa / Nippori' : '/tokyo/A1311/'
│ ├──'Ryogoku, Kinshicho, Koiwa' : '/tokyo/A1312/'
│ ⋮
│ └──'Ginza / Shimbashi / Yurakucho' : '/tokyo/A1301/'
│
├──'Kanagawa'
│ ├──'Rund um Odawara' : '/kanagawa/A1409/'
│ ⋮
⋮
Nachdem die Hauptbereiche erworben wurden, besteht der nächste Schritt darin, die Nebenkategorien zu erwerben. Genauso wie eine Hauptkategorie,
url = '/tokyo/A1304/'
res = requests.get(root_url + url[1:])
soup = BeautifulSoup(res.content, 'html.parser')
a = soup.find_all('a', class_='c-link-arrow')
area_dict = {}
for area in a:
href = area['href']
if href[-21:-8]!=url:
continue
else:
area_dict[area.text] = href
Wenn Sie tun
{'Yoyogi': 'https://tabelog.com/tokyo/A1304/A130403/',
'Okubo / New Okubo': 'https://tabelog.com/tokyo/A1304/A130404/',
'Shinjuku': 'https://tabelog.com/tokyo/A1304/A130401/',
'Shinjuku Gyoen': 'https://tabelog.com/tokyo/A1304/A130402/'}
Es fühlt sich gut an. Außerdem wurde die if-Anweisung eingefügt, da einige Anzeigen class = "c-link-arrow" haben, wennoup.find_all ('a', class_ = 'c-link-arrow') ausgeführt wird. Dies dient dazu, diese zu beseitigen.
Geben Sie als Nächstes den Bereich an, in den Sie gehen möchten, und rufen Sie die URL dieses Bereichs ab.
visit_areas = ['Roppongi / Azabu / Hiroo', 'Harajuku / Omotesando / Aoyama', 'Yotsuya / Ichigaya / Iidabashi', 'Shinjuku / Yoyogi / Okubo',
'Tokio / Nihonbashi', 'Shibuya / Ebisu / Daikanyama', 'Meguro / Shirokane / Gotanda', 'Akasaka / Nagatacho / Tameike', 'Ginza / Shimbashi / Yurakucho']
url_dict = {}
for visit_area in visit_areas:
url = area_url['Tokio'][visit_area]
time.sleep(1)
res = requests.get(root_url + url[1:])
soup = BeautifulSoup(res.content, 'html.parser')
a = soup.find_all('a', class_='c-link-arrow')
for area in a:
href = area['href']
if href[-21:-8]!=url:
continue
else:
url_dict[area.text] = href
Es ist uns gelungen, die URL von 34 Bereichen in der folgenden Form zu erhalten!
{'Marunouchi / Otemachi': 'https://tabelog.com/tokyo/A1302/A130201/',
'9 Schritte nach unten': 'https://tabelog.com/tokyo/A1309/A130906/',...
Nachdem Sie die URL haben, die auf den Bereich verweist ("// tabelog.com/tokyo/A .... / A ...... /"), müssen Sie im nächsten Schritt die URL des einzelnen Restaurants abrufen ("/"). /tabelog.com/tokyo/A .... / A ...... / ........ / ").
url = 'https://tabelog.com/tokyo/A1302/A130201/'
res = requests.get(url)
soup = BeautifulSoup(res.content, 'html.parser')
Die obige URL zeigt Ihnen die ersten 20 Geschäfte in diesem Bereich. Die URL der nächsten 20 Geschäfte lautet "//tabelog.com/tokyo/A1302/A130201/rstLst/2/", und Sie können rstLst / 3,4,5, ... Sie können sehen, dass. Da hier der Maximalwert von rstLst für die Schleifenverarbeitung erforderlich ist, wird der Wert, der durch Teilen der Gesamtzahl der Restaurants durch 20 erhalten wird, wie unten gezeigt auf eine ganze Zahl aufgerundet.
import math
count = soup.find_all('span', class_='list-condition__count')
print(math.ceil(int(count[0].text)/20))
90
Insgesamt gibt es 1.784 Geschäfte. Wenn sich auf einer Seite 20 Geschäfte befinden, ist die letzte Seite die 90. Seite. Als ich jedoch versuchte, die 90. Seite anzuzeigen ...
Diese Seite kann nicht angezeigt werden Vielen Dank, dass Sie das Essprotokoll verwendet haben. Es kann nicht nach Seite 60 angezeigt werden. Bitte schränken Sie die Bedingungen ein und suchen Sie erneut.
Wird angezeigt! !! Derzeit werden nur bis zu 60 Seiten angezeigt. Sie müssen sich also keine Gedanken darüber machen, ob Sie die Bedingungen außerhalb des Bereichs eingrenzen möchten, sodass die Anzahl der Filialen 1.200 oder weniger beträgt, und dann die Schleifenverarbeitung ausführen oder die besten 1.200 in der neuen Eröffnungsreihenfolge erhalten und zufrieden sein möchten. In einem schlechten Weg. Überprüfen Sie also einmal, wie viele Geschäfte in jedem Bereich aufgelistet sind.
counts = {}
for key,value in url_dict.items():
time.sleep(1)
res = requests.get(value)
soup = BeautifulSoup(res.content, 'html.parser')
counts[key] = int(soup.find_all('span', class_='list-condition__count')[0].text)
print(sorted(counts.items(), key=lambda x:x[1], reverse=True)[:15])
[('Shinjuku', 5756),
('Shibuya', 3420),
('Shimbashi / Shiodome', 2898),
('Ginza', 2858),
('Roppongi / Nogizaka / Nishi Azabu', 2402),
('Marunouchi / Otemachi', 1784),
('Iidabashi / Kagurazaka', 1689),
('Ebisu', 1584),
('Nihonbashi / Kyobashi', 1555),
('Akasaka', 1464),
('Ningyocho / Kodenmacho', 1434),
('Gotanda / Takanawadai', 937),
('Yurakucho / Hibiya', 773),
('Tameike Sanno / Kasumigaseki', 756),
('Kayabacho / Hatchobori', 744)]
Infolgedessen wurde deutlich, dass die Anzahl der Veröffentlichungen in 11 Bereichen 1.200 überstieg. Aufgrund verschiedener Versuche und Irrtümer entschied ich mich zufrieden zu sein, da ich das Genre vor diesem Hintergrund auf Restaurants beschränkte und die Daten der 1.200 Top-Artikel in der Reihenfolge der Neueröffnung erfasste. Lassen Sie sich vorerst die Restaurantinformationen auf einer bestimmten Seite anzeigen.
url = 'https://tabelog.com/tokyo/A1301/A130101/rstLst/RC/1/?Srt=D&SrtT=nod'
res = requests.get(url)
soup = BeautifulSoup(res.content, 'html.parser')
rc_list = []
for rc_div in soup.find_all('div', class_='list-rst__wrap js-open-new-window'):
rc_name = rc_div.find('a', class_='list-rst__rst-name-target cpy-rst-name').text
rc_url = rc_div.find('a', class_='list-rst__rst-name-target cpy-rst-name')['href']
rc_score = rc_div.find('span', class_='c-rating__val c-rating__val--strong list-rst__rating-val')
if rc_score is None:
rc_score = -1.
else:
rc_score = float(rc_score.text)
rc_review_num = rc_div.find('em', class_='list-rst__rvw-count-num cpy-review-count').text
rc_list.append([rc_name, rc_url, rc_score, rc_review_num])
Ich werde einige Erklärungen hinzufügen. Erstens beschränkt '/ rstLst / RC' für die erste URL das Genre auf Restaurants. Das '/ 1', das danach kommt, bedeutet die erste Seite, dh die ersten 20 Fälle. Darüber hinaus ist '/? Srt = D & SrtT = nod' eine neue Spezifikation offener Ordnung. In der for-Anweisung werden 20 Restaurantdaten der Reihe nach verarbeitet. Es ist die Punktzahl des Essprotokolls, die Aufmerksamkeit erfordert. Sie können die Punktzahl mit der oben genannten Suchmethode abrufen. Wenn jedoch keine Punktzahl vorhanden ist, ist dieses Tag selbst nicht vorhanden. Daher wurde der Fall in der if-Anweisung durch None geteilt, und wenn keine Punktzahl vorhanden war, wurde ein Prozess hinzugefügt, um die Punktzahl vorübergehend auf -1 zu setzen. In Bezug auf die Anzahl der Bewertungen wird '-' zurückgegeben, wenn keine Bewertung vorliegt. Danach können Sie die URL des Restaurants abrufen, indem Sie die Schleife für jeden Bereich und jede Seite drehen! !!
Nachdem Sie nun die URL jedes Restaurants abrufen können, besteht der Zweck darin, Mundpropaganda-Informationen von der Seite jedes Restaurants abzurufen. Als ich den Code zuerst eingegeben habe, habe ich Folgendes getan.
url = 'https://tabelog.com/tokyo/A1301/A130101/13079232/dtlrvwlst/COND-2/smp0/?smp=0&lc=2&rvw_part=all&PG=1'
res = requests.get(url)
soup = BeautifulSoup(res.content, 'html.parser')
station = soup.find_all('dl', class_='rdheader-subinfo__item')[0].find('span', class_='linktree__parent-target-text').text
genre = '/'.join([genre_.text for genre_ in soup.find_all('dl', class_='rdheader-subinfo__item')[1].find_all('span', class_='linktree__parent-target-text')])
price = soup.find_all('dl', class_='rdheader-subinfo__item')[2].find('p', class_='rdheader-budget__icon rdheader-budget__icon--dinner').find('a', class_='rdheader-budget__price-target').text
score = [score_.next_sibling.next_sibling.text for score_ in soup.find_all('span', class_='c-rating__time c-rating__time--dinner')]
print(station, genre, price, score)
Ich werde einen Kommentar hinzufügen. In Bezug auf die URL ist '/ dtlrvwlst' eine Bewertungsliste, '/ COND-2' eine Nachtbewertung, 'smp0' eine einfache Anzeige, 'lc = 2'ist jeweils 100 Elemente und'PG = 1'ist 1 Es bedeutet die Seite. Die nächstgelegene Station, das nächstgelegene Genre und das nächstgelegene Budget werden in der richtigen Reihenfolge erfasst, da sich Daten im Datentag befinden, deren Klassenname "rdheader-subinfo__item "lautet. Bei Genres werden in den meisten Fällen einem Geschäft mehrere Genres zugewiesen. Daher haben wir hier '/' verwendet, um alle Genre-Namen zu kombinieren. Das Budget und die Punktzahl jeder Mundpropaganda sind etwas kompliziert, weil ich nachts nur die eine wollte.
Jetzt, da wir die erforderlichen Informationen einzeln erhalten können, müssen wir nur noch die gewünschten Daten durch Schleifenverarbeitung erhalten! !!
import numpy as np
import pandas as pd
import requests
from bs4 import BeautifulSoup
import math
import time
from tqdm import tqdm
root_url = 'https://tabelog.com/'
res = requests.get(root_url)
soup = BeautifulSoup(res.content, 'html.parser')
a = soup.find_all('a', class_='rsttop-area-search__target js-area-swicher-target')
area_url = {}
for area in a:
area_dict = {}
splitted = area.get('data-swicher-area-list').split('"')
for i in range(int((len(splitted)-1)/8)):
area_dict[splitted[i*8+3]] = splitted[i*8+7]
area_url[area.get('data-swicher-city').split('"')[3]] = area_dict
visit_areas = ['Shibuya / Ebisu / Daikanyama']
url_dict = {}
for visit_area in visit_areas:
url = area_url['Tokio'][visit_area]
time.sleep(1)
res = requests.get(root_url + url[1:])
soup = BeautifulSoup(res.content, 'html.parser')
a = soup.find_all('a', class_='c-link-arrow')
for area in a:
href = area['href']
if href[-21:-8]!=url:
continue
else:
url_dict[area.text] = href
max_page = 20
restaurant_data = []
for area, url in url_dict.items():
time.sleep(1)
res_area = requests.get(url)
soup_area = BeautifulSoup(res_area.content, 'html.parser')
rc_count = int(soup_area.find_all('span', class_='list-condition__count')[0].text)
print('There are ' + str(rc_count) + ' restaurants in ' + area)
for i in tqdm(range(1,min(math.ceil(rc_count/20)+1,max_page+1,61))):
url_rc = url + 'rstLst/RC/' + str(i) + '/?Srt=D&SrtT=nod'
res_rc = requests.get(url_rc)
soup_rc = BeautifulSoup(res_rc.content, 'html.parser')
for rc_div in soup_rc.find_all('div', class_='list-rst__wrap js-open-new-window'):
rc_name = rc_div.find('a', class_='list-rst__rst-name-target cpy-rst-name').text
rc_url = rc_div.find('a', class_='list-rst__rst-name-target cpy-rst-name')['href']
rc_score = rc_div.find('span', class_='c-rating__val c-rating__val--strong list-rst__rating-val')
if rc_score is None:
rc_score = -1.
else:
rc_score = float(rc_score.text)
rc_review_num = rc_div.find('em', class_='list-rst__rvw-count-num cpy-review-count').text
if rc_review_num != ' - ':
for page in range(1,math.ceil(int(rc_review_num)/100)+1):
rc_url_pg = rc_url + 'dtlrvwlst/COND-2/smp0/?smp=0&lc=2&rvw_part=all&PG=' + str(page)
time.sleep(1)
res_pg = requests.get(rc_url_pg)
soup_pg = BeautifulSoup(res_pg.content, 'html.parser')
if 'Ich kann die gesuchte Seite nicht finden' in soup_pg.find('title').text:
continue
try:
station = soup_pg.find_all('dl', class_='rdheader-subinfo__item')[0].find('span', class_='linktree__parent-target-text').text
except:
try:
station = soup_pg.find_all('dl', class_='rdheader-subinfo__item')[0].find('dd', class_='rdheader-subinfo__item-text').text.replace('\n','').replace(' ','')
except:
station = ''
genre = '/'.join([genre_.text for genre_ in soup_pg.find_all('dl', class_='rdheader-subinfo__item')[1].find_all('span', class_='linktree__parent-target-text')])
price = soup_pg.find_all('dl', class_='rdheader-subinfo__item')[2].find('p', class_='rdheader-budget__icon rdheader-budget__icon--dinner').find('a', class_='rdheader-budget__price-target').text
score = [score_.next_sibling.next_sibling.text for score_ in soup_pg.find_all('span', class_='c-rating__time c-rating__time--dinner')]
restaurant_data.append([area, rc_count, rc_name, rc_url, rc_score, rc_review_num, station, genre, price, score])
Aufgrund der großen Datenmenge war das Gebiet vorübergehend auf visit_areas = ['Shibuya / Ebisu / Daikanyama'] beschränkt. Da max_page = 20 ist, können für jeden Standort nur 400 Daten von 20 Elementen / Seite 20 (max_page) erfasst werden. Darüber hinaus werden nach dem Erfassen der Anzahl der Bewertungen 100 Bewertungen / Seite erfasst, aber die Anzahl der zuerst erfassten Bewertungen umfasst die Tagesauswertung, und die Schleifenverarbeitung zielt nur auf die Nachtauswertung ab. Daher gab es bei der Schleifenverarbeitung eine Situation, in der nicht so viele Überprüfungen durchgeführt wurden, wie ursprünglich erwartet.
if 'Ich kann die gesuchte Seite nicht finden' in soup_pg.find('title').text:
continue
Es wurde in verarbeitet. Außerdem listen die meisten Geschäfte die nächstgelegene Station auf, aber es gibt einige Geschäfte, die den Bereich anstelle der nächstgelegenen Station auflisten. In diesem Fall unterscheiden sich die Tag-Namen
try:
station = soup_pg.find_all('dl', class_='rdheader-subinfo__item')[0].find('span', class_='linktree__parent-target-text').text
except:
try:
station = soup_pg.find_all('dl', class_='rdheader-subinfo__item')[0].find('dd', class_='rdheader-subinfo__item-text').text.replace('\n','').replace(' ','')
except:
station = ''
Handelt damit. Als Ergebnis konnten wir 895 Daten erhalten. Von diesen hatten 804 sogar eine Bewertung.
Das obige Streudiagramm zeigt die Beziehung zwischen der durchschnittlichen Mundpropaganda und der Bewertung des Essprotokolls. Geschäfte ohne Lebensmittelprotokoll werden mit 2,9 Punkten behandelt. Wenn die durchschnittliche Mundpropaganda hoch ist, können Sie insgesamt feststellen, dass auch die Punktzahl des Essprotokolls hoch ist. Obwohl die durchschnittliche Mundpropaganda hoch war, war die Punktzahl des Essprotokolls niedrig, und es wurde auch festgestellt, dass es Geschäfte gibt, die unterschätzt werden.
Also werde ich das nächste Mal in einen dieser unterschätzten Läden gehen! !!
Recommended Posts