回答編集履歴

1

追記

2020/10/25 09:11

投稿

nto
nto

スコア1438

test CHANGED
@@ -20,7 +20,291 @@
20
20
 
21
21
  ```
22
22
 
23
+
24
+
25
+
26
+
27
+ ```python
28
+
29
+ import requests
30
+
31
+ from bs4 import BeautifulSoup
32
+
33
+ import re
34
+
35
+ import pandas as pd
36
+
37
+ import time
38
+
39
+ import csv
40
+
41
+
42
+
43
+ class Tabelog:
44
+
45
+ def __init__(self, base_url, test_mode=False, p_ward='東京都内', begin_page=1, end_page=50):
46
+
47
+ #変数宣言
48
+
49
+ self.store_id = ''
50
+
51
+ self.store_id_num = 0
52
+
53
+ self.store_name = ''
54
+
55
+ self.score = 0
56
+
57
+ self.address_name = ""
58
+
59
+ self.columns = ['store_id', 'store_name', 'address_name','score']
60
+
61
+ self.df = pd.DataFrame(columns=self.columns)
62
+
63
+ self.__regexcomp = re.compile(r'\n|\s') # \nは改行、\sは空白
64
+
65
+
66
+
67
+ page_num = begin_page # 店舗一覧ページ番号
68
+
69
+
70
+
71
+ if test_mode:
72
+
73
+ list_url = base_url + str(page_num) + '/?Srt=D&SrtT=rt&sort_mode=1' #食べログの点数ランキングでソートする際に必要な処理
74
+
75
+ self.scrape_list(list_url, mode=test_mode)
76
+
77
+ else:
78
+
79
+ while True:
80
+
81
+ list_url = base_url + str(page_num) + '/?Srt=D&SrtT=rt&sort_mode=1' #食べログの点数ランキングでソートする際に必要な処理
82
+
83
+ if self.scrape_list(list_url, mode=test_mode) != True:
84
+
85
+ break
86
+
87
+
88
+
89
+ #INパラメータまでのページ数データを取得する
90
+
91
+ if page_num >= end_page:
92
+
93
+ break
94
+
95
+ page_num += 1
96
+
97
+ # dfの確認
98
+
99
+ print(self.df)
100
+
101
+
102
+
103
+
104
+
105
+ def scrape_list(self, list_url, mode):
106
+
107
+ r = requests.get(list_url)
108
+
109
+ if r.status_code != requests.codes.ok:
110
+
111
+ return False
112
+
113
+
114
+
115
+ soup = BeautifulSoup(r.content, 'html.parser')
116
+
117
+ soup_a_list = soup.find_all('a', class_='list-rst__rst-name-target') # 店名一覧
118
+
119
+
120
+
121
+ if len(soup_a_list) == 0:
122
+
123
+ return False
124
+
125
+
126
+
127
+ if mode:
128
+
129
+ for soup_a in soup_a_list[:2]:
130
+
131
+ item_url = soup_a.get('href') # 店の個別ページURLを取得
132
+
133
+ self.store_id_num += 1
134
+
135
+ self.scrape_item(item_url, mode)
136
+
137
+ else:
138
+
139
+ for soup_a in soup_a_list:
140
+
141
+ item_url = soup_a.get('href') # 店の個別ページURLを取得
142
+
143
+ self.store_id_num += 1
144
+
145
+ self.scrape_item(item_url, mode)
146
+
147
+
148
+
149
+ return True
150
+
151
+
152
+
153
+ def scrape_item(self, item_url, mode):
154
+
155
+ start = time.time()
156
+
157
+
158
+
159
+ r = requests.get(item_url)
160
+
161
+ if r.status_code != requests.codes.ok:
162
+
163
+ #print(f'error:not found{ item_url }')
164
+
165
+ return
166
+
167
+
168
+
169
+ soup = BeautifulSoup(r.content, 'html.parser')
170
+
171
+
172
+
173
+ store_name_tag = soup.find('h2', class_='display-name')
174
+
175
+ store_name = store_name_tag.span.string
176
+
177
+ #print('{}→店名:{}'.format(self.store_id_num, store_name.strip()), end='')
178
+
179
+ self.store_name = store_name.strip()
180
+
181
+
182
+
183
+ # ラーメン屋、つけ麺屋以外の店舗は除外
184
+
185
+ store_head = soup.find('div', class_='rdheader-subinfo') # 店舗情報のヘッダー枠データ取得
186
+
187
+ store_head_list = store_head.find_all('dl')
188
+
189
+ store_head_list = store_head_list[1].find_all('span')
190
+
191
+ #print('ターゲット:', store_head_list[0].text)
192
+
193
+
194
+
195
+ if store_head_list[0].text not in {'ラーメン', 'つけ麺'}:
196
+
197
+ #print('ラーメンorつけ麺のお店ではないので処理対象外')
198
+
199
+ self.store_id_num -= 1
200
+
201
+ return
202
+
203
+
204
+
205
+ try:
206
+
207
+ address_name = soup.find("p", class_="rstinfo-table__address").text
208
+
209
+ #print(" 住所:{}".format(address_name), end="")
210
+
211
+ self.address_name = address_name
212
+
213
+
214
+
215
+ except AttributeError:
216
+
217
+ href = ''
218
+
219
+
220
+
221
+ rating_score_tag = soup.find('b', class_='c-rating__val')
222
+
223
+ rating_score = rating_score_tag.span.string
224
+
225
+ #print(' 評価点数:{}点'.format(rating_score), end='')
226
+
227
+ self.score = rating_score
228
+
229
+
230
+
231
+ #評価点数が存在しない店舗は除外
232
+
233
+ if rating_score == '-':
234
+
235
+ #print(' 評価がないため処理対象外')
236
+
237
+ self.store_id_num -= 1
238
+
239
+ return
240
+
241
+
242
+
243
+ #評価が3.5未満店舗は除外
244
+
245
+ if float(rating_score) < 3.5:
246
+
247
+ #print(' 食べログ評価が3.5未満のため処理対象外')
248
+
249
+ self.store_id_num -= 1
250
+
251
+ return
252
+
253
+
254
+
255
+
256
+
257
+ #データフレームの生成
258
+
259
+ self.make_df()
260
+
261
+ return
262
+
263
+
264
+
265
+ def make_df(self):
266
+
267
+ self.store_id = str(self.store_id_num).zfill(8) #0パディング
268
+
269
+ se = pd.Series([self.store_id, self.store_name, self.address_name, self.score], self.columns) # 行を作成
270
+
271
+ self.df = self.df.append(se, self.columns) # データフレームに行を追加
272
+
273
+ print(self.address_name)
274
+
275
+ print(self.score)
276
+
277
+ print(self.store_name)
278
+
279
+ print(self.store_id)
280
+
281
+ print('df appended!')
282
+
283
+ print('='*50)
284
+
285
+ time.sleep(0.4)
286
+
287
+ return
288
+
289
+
290
+
291
+ if __name__ == '__main__':
292
+
293
+ tokyo_ramen_address = Tabelog(base_url="https://tabelog.com/tokyo/rstLst/ramen/",test_mode=False)
294
+
295
+ tokyo_ramen_address.df.to_csv("tokyo_ramen_address.csv", encoding='utf_8_sig')
296
+
297
+ ```
298
+
299
+
300
+
301
+
302
+
303
+ ### 追記
304
+
305
+ 作成者が違う様で、質問者様に言っても仕方がない事では有ると思いますが
306
+
23
- またアドバイスとしては、確認用のprintはscrape_item関数内で行うよりも
307
+ 確認用のprintはscrape_item関数内で行うよりも
24
308
 
25
309
  make_df関数内で確認を行った方が[抽出出来ているか]と[正しい値であるか]を
26
310
 
@@ -28,280 +312,14 @@
28
312
 
29
313
 
30
314
 
31
-
32
-
33
-
34
-
35
-
36
-
37
- ```python
38
-
39
- import requests
40
-
41
- from bs4 import BeautifulSoup
42
-
43
- import re
44
-
45
- import pandas as pd
46
-
47
- import time
48
-
49
- import csv
50
-
51
-
52
-
53
- class Tabelog:
54
-
55
- def __init__(self, base_url, test_mode=False, p_ward='東京都内', begin_page=1, end_page=50):
56
-
57
- #変数宣言
58
-
59
- self.store_id = ''
60
-
61
- self.store_id_num = 0
62
-
63
- self.store_name = ''
64
-
65
- self.score = 0
66
-
67
- self.address_name = ""
68
-
69
- self.columns = ['store_id', 'store_name', 'address_name','score']
70
-
71
- self.df = pd.DataFrame(columns=self.columns)
72
-
73
- self.__regexcomp = re.compile(r'\n|\s') # \nは改行、\sは空白
74
-
75
-
76
-
77
- page_num = begin_page # 店舗一覧ページ番号
78
-
79
-
80
-
81
- if test_mode:
82
-
83
- list_url = base_url + str(page_num) + '/?Srt=D&SrtT=rt&sort_mode=1' #食べログの点数ランキングでソートする際に必要な処理
84
-
85
- self.scrape_list(list_url, mode=test_mode)
86
-
87
- else:
88
-
89
- while True:
90
-
91
- list_url = base_url + str(page_num) + '/?Srt=D&SrtT=rt&sort_mode=1' #食べログの点数ランキングでソートする際に必要な処理
92
-
93
- if self.scrape_list(list_url, mode=test_mode) != True:
94
-
95
- break
96
-
97
-
98
-
99
- #INパラメータまでのページ数データを取得する
100
-
101
- if page_num >= end_page:
102
-
103
- break
104
-
105
- page_num += 1
106
-
107
- # dfの確認
108
-
109
- print(self.df)
110
-
111
-
112
-
113
-
114
-
115
- def scrape_list(self, list_url, mode):
116
-
117
- r = requests.get(list_url)
118
-
119
- if r.status_code != requests.codes.ok:
120
-
121
- return False
122
-
123
-
124
-
125
- soup = BeautifulSoup(r.content, 'html.parser')
126
-
127
- soup_a_list = soup.find_all('a', class_='list-rst__rst-name-target') # 店名一覧
128
-
129
-
130
-
131
- if len(soup_a_list) == 0:
132
-
133
- return False
134
-
135
-
136
-
137
- if mode:
138
-
139
- for soup_a in soup_a_list[:2]:
140
-
141
- item_url = soup_a.get('href') # 店の個別ページURLを取得
142
-
143
- self.store_id_num += 1
144
-
145
- self.scrape_item(item_url, mode)
146
-
147
- else:
148
-
149
- for soup_a in soup_a_list:
150
-
151
- item_url = soup_a.get('href') # 店の個別ページURLを取得
152
-
153
- self.store_id_num += 1
154
-
155
- self.scrape_item(item_url, mode)
156
-
157
-
158
-
159
- return True
160
-
161
-
162
-
163
- def scrape_item(self, item_url, mode):
164
-
165
- start = time.time()
166
-
167
-
168
-
169
- r = requests.get(item_url)
170
-
171
- if r.status_code != requests.codes.ok:
172
-
173
- #print(f'error:not found{ item_url }')
174
-
175
- return
176
-
177
-
178
-
179
- soup = BeautifulSoup(r.content, 'html.parser')
180
-
181
-
182
-
183
- store_name_tag = soup.find('h2', class_='display-name')
184
-
185
- store_name = store_name_tag.span.string
186
-
187
- #print('{}→店名:{}'.format(self.store_id_num, store_name.strip()), end='')
188
-
189
- self.store_name = store_name.strip()
190
-
191
-
192
-
193
- # ラーメン屋、つけ麺屋以外の店舗は除外
194
-
195
- store_head = soup.find('div', class_='rdheader-subinfo') # 店舗情報のヘッダー枠データ取得
196
-
197
- store_head_list = store_head.find_all('dl')
198
-
199
- store_head_list = store_head_list[1].find_all('span')
200
-
201
- #print('ターゲット:', store_head_list[0].text)
202
-
203
-
204
-
205
- if store_head_list[0].text not in {'ラーメン', 'つけ麺'}:
206
-
207
- #print('ラーメンorつけ麺のお店ではないので処理対象外')
208
-
209
- self.store_id_num -= 1
210
-
211
- return
212
-
213
-
214
-
215
- try:
216
-
217
- address_name = soup.find("p", class_="rstinfo-table__address").text
218
-
219
- #print(" 住所:{}".format(address_name), end="")
220
-
221
- self.address_name = address_name
222
-
223
-
224
-
225
- except AttributeError:
226
-
227
- href = ''
228
-
229
-
230
-
231
- rating_score_tag = soup.find('b', class_='c-rating__val')
232
-
233
- rating_score = rating_score_tag.span.string
234
-
235
- #print(' 評価点数:{}点'.format(rating_score), end='')
236
-
237
- self.score = rating_score
238
-
239
-
240
-
241
- #評価点数が存在しない店舗は除外
242
-
243
- if rating_score == '-':
244
-
245
- #print(' 評価がないため処理対象外')
246
-
247
- self.store_id_num -= 1
248
-
249
- return
250
-
251
-
252
-
253
- #評価が3.5未満店舗は除外
254
-
255
- if float(rating_score) < 3.5:
256
-
257
- #print(' 食べログ評価が3.5未満のため処理対象外')
258
-
259
- self.store_id_num -= 1
260
-
261
- return
262
-
263
-
264
-
265
-
266
-
267
- #データフレームの生成
268
-
269
- self.make_df()
270
-
271
- return
272
-
273
-
274
-
275
- def make_df(self):
276
-
277
- self.store_id = str(self.store_id_num).zfill(8) #0パディング
278
-
279
- se = pd.Series([self.store_id, self.store_name, self.address_name, self.score], self.columns) # 行を作成
280
-
281
- self.df = self.df.append(se, self.columns) # データフレームに行を追加
282
-
283
- print(self.address_name)
284
-
285
- print(self.score)
286
-
287
- print(self.store_name)
288
-
289
- print(self.store_id)
290
-
291
- print('df appended!')
292
-
293
- print('='*50)
294
-
295
- time.sleep(0.4)
296
-
297
- return
298
-
299
-
300
-
301
- if __name__ == '__main__':
302
-
303
- tokyo_ramen_address = Tabelog(base_url="https://tabelog.com/tokyo/rstLst/ramen/",test_mode=False)
304
-
305
- tokyo_ramen_address.df.to_csv("tokyo_ramen_address.csv", encoding='utf_8_sig')
306
-
307
- ```
315
+ また`if store_head_list[0].text not in {'ラーメン', 'つけ麺'}:`の点についてですが
316
+
317
+ 店舗情報のヘッダー枠のジャンルという項目の1個目が[ラーメン]ではない場合に
318
+
319
+ 実際にラーメン屋であった場合でも除外されてしまっております。
320
+
321
+ この場合の処理をもう少し柔軟に対応してあげられると更に精度が高まると思います。
322
+
323
+ 例:ジャンル: ラーメン▼担々麺▼ → 処理対象
324
+
325
+   ジャンル: 担々麺▼ラーメン▼ → 除外対象