回答編集履歴

15

秒数

2017/05/08 06:22

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -338,11 +338,19 @@
338
338
 
339
339
  `sleep(1)`だとちょっと不安なのでもっと増やしたほうが個人的にはいいですが・・・
340
340
 
341
- `import random`をして`time.sleep(random.uniform(30, 50))`とかにすると10sec - 20secの間でランダムな秒数待てます。
341
+ `import random`をして`time.sleep(random.uniform(5, 10))`とかにすると5sec - 10secの間でランダムな秒数待てます。
342
-
343
-
344
-
342
+
343
+
344
+
345
- ただこれだけ待ってると99999件取得した場合に半月前後かかるとおもいます・・・w
345
+ ただこれだけ待ってると99999件取得した場合に尋常じゃない時間がかかます
346
+
347
+
348
+
349
+ 普通1秒に1アクセスでも問題にはならないようですが、岡崎市図書館事件のように、相手側のサーバーでの通信方式に不備があると障害を引き起こすこともあります。
350
+
351
+
352
+
353
+ 一番は相手側にスクレイピングの許可をもらえることですね。
346
354
 
347
355
 
348
356
 

14

HEY

2017/05/08 06:22

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -336,13 +336,13 @@
336
336
 
337
337
 
338
338
 
339
- `sleep(1)`だとちょっと不安なのでもっと増やしたほうがと思
339
+ `sleep(1)`だとちょっと不安なのでもっと増やしたほうが個人的にはいいが・・・
340
-
340
+
341
- `import random`をして`time.sleep(random.uniform(30, 50))`とかにすると30sec - 50secの間でランダムな秒数待てます。
341
+ `import random`をして`time.sleep(random.uniform(30, 50))`とかにすると10sec - 20secの間でランダムな秒数待てます。
342
-
343
-
344
-
342
+
343
+
344
+
345
- は寝前に実行すればいいいます
345
+ ただこれだけ待ってる99999件取得した場合に半月前後かかるとおもいます・・・w
346
346
 
347
347
 
348
348
 

13

ごめん間違えて無編集でOKしちゃった

2017/05/08 06:18

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -242,8 +242,6 @@
242
242
 
243
243
  from bs4 import BeautifulSoup
244
244
 
245
- import random
246
-
247
245
 
248
246
 
249
247
  f = codecs.open('hiyoko.csv', 'w', 'utf-8')
@@ -260,7 +258,7 @@
260
258
 
261
259
  soup = BeautifulSoup(urllib2.urlopen(url).read(), "lxml")
262
260
 
263
- time.sleep(random.uniform(1, 10))
261
+ time.sleep(1)
264
262
 
265
263
  horse_name_tag = soup.find('div', {'class': 'horse_title'})
266
264
 

12

a

2017/05/08 06:10

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
File without changes

11

pep8違反修正

2017/05/08 06:09

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -242,6 +242,8 @@
242
242
 
243
243
  from bs4 import BeautifulSoup
244
244
 
245
+ import random
246
+
245
247
 
246
248
 
247
249
  f = codecs.open('hiyoko.csv', 'w', 'utf-8')
@@ -250,23 +252,31 @@
250
252
 
251
253
  start_url = 'http://db.netkeiba.com/horse/201310069{0}/'
252
254
 
255
+
256
+
253
257
  for i in xrange(1, 10):
254
258
 
255
259
  url = start_url.format(i)
256
260
 
257
- soup = BeautifulSoup(urllib2.urlopen(url).read(),"lxml")
261
+ soup = BeautifulSoup(urllib2.urlopen(url).read(), "lxml")
258
-
262
+
259
- time.sleep(1)
263
+ time.sleep(random.uniform(1, 10))
260
-
264
+
261
- horse_name_tag = soup.find('div',{'class':'horse_title'})
265
+ horse_name_tag = soup.find('div', {'class': 'horse_title'})
266
+
267
+
262
268
 
263
269
  if horse_name_tag != None:
264
270
 
271
+
272
+
265
273
  if horse_name_tag.find('h1') != None:
266
274
 
267
275
  horse_name = horse_name_tag.find('h1').text
268
276
 
277
+ horse_name = "".join(
278
+
269
- horse_name = "".join([x for x in horse_name_tag.text if not x == u'\xa0' and not x == u'\n'])
279
+ [x for x in horse_name_tag.text if not x == u'\xa0' and not x == u'\n'])
270
280
 
271
281
  print horse_name.strip()
272
282
 
@@ -274,6 +284,8 @@
274
284
 
275
285
  f.write(",".join(cols) + "\n")
276
286
 
287
+
288
+
277
289
  else:
278
290
 
279
291
  continue

10

また編集

2017/05/08 06:08

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -214,7 +214,7 @@
214
214
 
215
215
  ```
216
216
 
217
- ここで`class=horse_title`の`div`の下でまた`class=horse_title`の`div`を探しちゃってるのでNoneになります。
217
+ ここで`class="horse_title"`の`div`の下でまた`class="horse_title"`の`div`を探しちゃってるのでNoneになります。
218
218
 
219
219
  サイト内で確認したら`class="horse_title"`の`div`の直下に`h1`があるので
220
220
 
@@ -322,6 +322,20 @@
322
322
 
323
323
 
324
324
 
325
+ あとは`xrange(1, 100000)`にすれば2013100000から2013199999までの情報がとれます。
326
+
327
+
328
+
329
+ `sleep(1)`だとちょっと不安なのでもっと増やしたほうが良いと思います。
330
+
331
+ `import random`をして`time.sleep(random.uniform(30, 50))`とかにすると30sec - 50secの間でランダムな秒数待てます。
332
+
333
+
334
+
335
+ あとは寝る前に実行すればいいと思います。
336
+
337
+
338
+
325
339
 
326
340
 
327
341
  長文で申し訳ないです・・・

9

さいごっていうのやめる

2017/05/08 05:59

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -178,7 +178,7 @@
178
178
 
179
179
  ```python
180
180
 
181
- find( ('div',{'class':'horse_title'}).find('h1') )
181
+ soup.find('div',{'class':'horse_title'}).find( ('div',{'class':'horse_title'}).find('h1') )
182
182
 
183
183
  ```
184
184
 
@@ -194,27 +194,29 @@
194
194
 
195
195
  ```python
196
196
 
197
- find('div',{'class':'horse_title'}).find('h1')
197
+ soup.find('div',{'class':'horse_title'}).find('div',{'class':'horse_title'}).find('h1')
198
-
198
+
199
- ```
199
+ ```
200
-
200
+
201
- これでOK。
201
+ これでOK。(違う理由でこれだとエラーになります。以下参照)
202
+
203
+
202
204
 
203
205
  おそらくただのタイプミスだとは思いますが一応。
204
206
 
205
207
 
206
208
 
207
-
209
+ 上記のままだエラーになる理由がこれ。
208
-
210
+
209
- ```python
211
+ ```python
210
-
212
+
211
- horse_name_tag=soup.find('div',{'class':'horse_title'}).find(('div',{'class':'horse_title'})).find('h1')
213
+ horse_name_tag=soup.find('div',{'class':'horse_title'}).find('div',{'class':'horse_title'}).find('h1')
212
214
 
213
215
  ```
214
216
 
215
217
  ここで`class=horse_title`の`div`の下でまた`class=horse_title`の`div`を探しちゃってるのでNoneになります。
216
218
 
217
- サイト内で確認したら`class=horse_title`の`div`の直下に`h1`があるので
219
+ サイト内で確認したら`class="horse_title"`の`div`の直下に`h1`があるので
218
220
 
219
221
  ```python
220
222
 
@@ -260,15 +262,17 @@
260
262
 
261
263
  if horse_name_tag != None:
262
264
 
263
- horse_name_tag.find('h1')
265
+ if horse_name_tag.find('h1') != None:
266
+
264
-
267
+ horse_name = horse_name_tag.find('h1').text
268
+
265
- horse_name = "".join([x for x in horse_name_tag.text if not x == u'\xa0' and not x == u'\n'])
269
+ horse_name = "".join([x for x in horse_name_tag.text if not x == u'\xa0' and not x == u'\n'])
266
-
270
+
267
- print horse_name.strip()
271
+ print horse_name.strip()
268
-
272
+
269
- cols = [horse_name]
273
+ cols = [horse_name]
270
-
274
+
271
- f.write(",".join(cols) + "\n")
275
+ f.write(",".join(cols) + "\n")
272
276
 
273
277
  else:
274
278
 
@@ -282,7 +286,7 @@
282
286
 
283
287
 
284
288
 
285
- これで動きます。
289
+ これで動くはずです。
286
290
 
287
291
 
288
292
 

8

さいごのさいごの編集

2017/05/08 05:52

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -172,7 +172,7 @@
172
172
 
173
173
  ```
174
174
 
175
- の部分で、find関数にタプルを渡してしまっています。(丸括弧を閉じる場所違う
175
+ の部分で、find関数にタプルを渡してしまっています。(丸括弧が多い
176
176
 
177
177
  この部分ですね。
178
178
 
@@ -190,11 +190,11 @@
190
190
 
191
191
  ```
192
192
 
193
- というエラーになります。
193
+ というエラーになります。なので、
194
-
194
+
195
- ```python
195
+ ```python
196
-
196
+
197
- find( ('div',{'class':'horse_title'}) ).find('h1')
197
+ find('div',{'class':'horse_title'}).find('h1')
198
198
 
199
199
  ```
200
200
 

7

さいごの編集

2017/05/08 05:45

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -172,7 +172,7 @@
172
172
 
173
173
  ```
174
174
 
175
- の部分で、find関数にタプルを渡してしまっています。(丸括弧が多い
175
+ の部分で、find関数にタプルを渡してしまっています。(丸括弧を閉じる場所違う
176
176
 
177
177
  この部分ですね。
178
178
 
@@ -192,7 +192,13 @@
192
192
 
193
193
  というエラーになります。
194
194
 
195
-
195
+ ```python
196
+
197
+ find( ('div',{'class':'horse_title'}) ).find('h1')
198
+
199
+ ```
200
+
201
+ これでOK。
196
202
 
197
203
  おそらくただのタイプミスだとは思いますが一応。
198
204
 

6

加筆修正

2017/05/08 05:43

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -100,6 +100,10 @@
100
100
 
101
101
  `print i` をするとちゃんと順番にたされた数字が返ってきてるのですが・・・
102
102
 
103
+ **※このへんは変数urlを上書きしてるのが原因でした。一番下で言及します**
104
+
105
+
106
+
103
107
  なのでいろいろやってこうなりました。
104
108
 
105
109
  ```python
@@ -282,6 +286,10 @@
282
286
 
283
287
 
284
288
 
289
+ `format`関数は文字列内に`{0}`などがなくてもエラー吐かないんですね・・・
290
+
291
+
292
+
285
293
  確か同スコープ内なので、最初のurlはstart_urlという変数にいれて、for内でフォーマットして使うものはurlとしました。
286
294
 
287
295
 

5

長文になったのでまとめを最初に書きます。

2017/05/08 05:41

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -1,3 +1,23 @@
1
+ ## 長文になったのでまとめを最初に書いときます
2
+
3
+ * `find`にタプルを渡してるのでエラーになってた
4
+
5
+
6
+
7
+ * `url`の変数を上書きしない
8
+
9
+
10
+
11
+ * DOM要素の指定ミス(最初の`div`タグの指定を2回行っていたため、`h1`が見つからず`None`が返ってた)
12
+
13
+
14
+
15
+ * ページが変だったとき(馬の情報が空だったとき)はDOM要素が見つからず`None`が返るので、そのときはスキップ
16
+
17
+
18
+
19
+ ## 以下、試行の変遷記録(笑)
20
+
1
21
  最初に言っておくと、Python3しか書けないのでPython3で書きました。
2
22
 
3
23
  連番をurlに埋め込んで使うのは良いと思いますが、ページが変なページで取得したものがNoneだったらエラーになってしまいます。
@@ -266,7 +286,7 @@
266
286
 
267
287
 
268
288
 
269
- ## まとめ
289
+ ## 最後にもう一度まとめ
270
290
 
271
291
  * `find`にタプルを渡してるのでエラーになってた
272
292
 

4

ちょい修正

2017/05/08 05:36

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -138,7 +138,63 @@
138
138
 
139
139
  ## 追記:
140
140
 
141
+
142
+
143
+ 質問者様のコードでは
144
+
145
+ ```python
146
+
147
+ horse_name_tag=soup.find('div',{'class':'horse_title'}).find(('div',{'class':'horse_title'}).find('h1'))
148
+
149
+ ```
150
+
151
+ の部分で、find関数にタプルを渡してしまっています。(丸括弧が多い)
152
+
153
+ この部分ですね。
154
+
155
+ ```python
156
+
157
+ find( ('div',{'class':'horse_title'}).find('h1') )
158
+
159
+ ```
160
+
161
+ このまま実行すると
162
+
163
+ ```
164
+
165
+ AttributeError: 'tuple' object has no attribute 'find'
166
+
167
+ ```
168
+
141
- みません初歩的なミスでした。
169
+ というエラーになります。
170
+
171
+
172
+
173
+ おそらくただのタイプミスだとは思いますが一応。
174
+
175
+
176
+
177
+ あと
178
+
179
+ ```python
180
+
181
+ horse_name_tag=soup.find('div',{'class':'horse_title'}).find(('div',{'class':'horse_title'})).find('h1')
182
+
183
+ ```
184
+
185
+ ここで`class=horse_title`の`div`の下でまた`class=horse_title`の`div`を探しちゃってるのでNoneになります。
186
+
187
+ サイト内で確認したら`class=horse_title`の`div`の直下に`h1`があるので
188
+
189
+ ```python
190
+
191
+ horse_name_tag=soup.find('div',{'class':'horse_title'}).find('h1')
192
+
193
+ ```
194
+
195
+ これで取得できます。
196
+
197
+ あとはページが変だったときにNoneが返るのをifで分岐してエラー回避して・・・
142
198
 
143
199
  ```python
144
200
 
@@ -200,8 +256,34 @@
200
256
 
201
257
 
202
258
 
259
+
260
+
203
- 最初に定義したurlという変数をfor内で上書きしちゃってたらそりゃうごきませんですね
261
+ 最初コード書いたとき、最初に定義したurlという変数をfor内で上書きしちゃってました。
204
-
205
-
206
-
262
+
263
+
264
+
207
- 同スコープ内なので、最初のurlはstart_urlという変数にいれて、for内でフォーマットして使うものはurlとしました。
265
+ 確か同スコープ内なので、最初のurlはstart_urlという変数にいれて、for内でフォーマットして使うものはurlとしました。
266
+
267
+
268
+
269
+ ## まとめ
270
+
271
+ * `find`にタプルを渡してるのでエラーになってた
272
+
273
+
274
+
275
+ * `url`の変数を上書きしない
276
+
277
+
278
+
279
+ * DOM要素の指定ミス(最初の`div`タグの指定を2回行っていたため、`h1`が見つからず`None`が返ってた)
280
+
281
+
282
+
283
+ * ページが変だったとき(馬の情報が空だったとき)はDOM要素が見つからず`None`が返るので、そのときはスキップ
284
+
285
+
286
+
287
+
288
+
289
+ 長文で申し訳ないです・・・

3

修正

2017/05/08 05:34

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -70,7 +70,7 @@
70
70
 
71
71
 
72
72
 
73
- 追記:
73
+ ## 追記:
74
74
 
75
75
  2.7で質問にあるコードでいろいろやってみたのですが、なんかxrangeで返るイテレータをforで回してurlに入れ込んでもurlが変わらないみたいです。
76
76
 
@@ -120,10 +120,6 @@
120
120
 
121
121
  horse_name = "".join([x for x in horse_name_tag.text if not x == u'\xa0' and not x == u'\n'])
122
122
 
123
- print horse_name
124
-
125
-
126
-
127
123
  print horse_name.strip()
128
124
 
129
125
  cols = [horse_name]
@@ -140,6 +136,72 @@
140
136
 
141
137
  ```
142
138
 
143
-
139
+ ## 追記:
140
+
144
-
141
+ すみません。初歩的なミスでした。
142
+
143
+ ```python
144
+
145
+ # -*- coding:utf-8 -*-
146
+
147
+
148
+
149
+ import urllib2
150
+
151
+ import codecs
152
+
153
+ import time
154
+
155
+ from bs4 import BeautifulSoup
156
+
157
+
158
+
159
+ f = codecs.open('hiyoko.csv', 'w', 'utf-8')
160
+
161
+ horse_name = ""
162
+
163
+ start_url = 'http://db.netkeiba.com/horse/201310069{0}/'
164
+
165
+ for i in xrange(1, 10):
166
+
167
+ url = start_url.format(i)
168
+
169
+ soup = BeautifulSoup(urllib2.urlopen(url).read(),"lxml")
170
+
171
+ time.sleep(1)
172
+
173
+ horse_name_tag = soup.find('div',{'class':'horse_title'})
174
+
145
- Python3.x系なら最初のコードで動くと思います。
175
+ if horse_name_tag != None:
176
+
177
+ horse_name_tag.find('h1')
178
+
179
+ horse_name = "".join([x for x in horse_name_tag.text if not x == u'\xa0' and not x == u'\n'])
180
+
181
+ print horse_name.strip()
182
+
183
+ cols = [horse_name]
184
+
185
+ f.write(",".join(cols) + "\n")
186
+
187
+ else:
188
+
189
+ continue
190
+
191
+
192
+
193
+ f.close()
194
+
195
+ ```
196
+
197
+
198
+
199
+ これで動きます。
200
+
201
+
202
+
203
+ 最初に定義したurlという変数をfor内で上書きしちゃってたらそりゃうごきませんですね。
204
+
205
+
206
+
207
+ 同スコープ内なので、最初のurlはstart_urlという変数にいれて、for内でフォーマットして使うものはurlとしました。

2

2\.7でやってみた

2017/05/08 05:12

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -67,3 +67,79 @@
67
67
 
68
68
 
69
69
  求めているものと違ったら申し訳ありません。
70
+
71
+
72
+
73
+ 追記:
74
+
75
+ 2.7で質問にあるコードでいろいろやってみたのですが、なんかxrangeで返るイテレータをforで回してurlに入れ込んでもurlが変わらないみたいです。
76
+
77
+ ずっと`http://db.netkeiba.com/horse/2013100691/`のままなので同じものしか取得できませんでした。
78
+
79
+ 2.7の仕様はよく分かってませんので、きっとなにかがPython3と違うのでしょう。
80
+
81
+ `print i` をするとちゃんと順番にたされた数字が返ってきてるのですが・・・
82
+
83
+ なのでいろいろやってこうなりました。
84
+
85
+ ```python
86
+
87
+ # -*- coding:utf-8 -*-
88
+
89
+
90
+
91
+ import urllib2
92
+
93
+ import codecs
94
+
95
+ import time
96
+
97
+ from bs4 import BeautifulSoup
98
+
99
+
100
+
101
+ f = codecs.open('hiyoko.csv', 'w', 'utf-8')
102
+
103
+ horse_name = ""
104
+
105
+
106
+
107
+ for i in xrange(1, 10):
108
+
109
+ url = 'http://db.netkeiba.com/horse/201310069%d/' % i
110
+
111
+ soup = BeautifulSoup(urllib2.urlopen(url).read(),"lxml")
112
+
113
+ time.sleep(5)
114
+
115
+ horse_name_tag = soup.find('div',{'class':'horse_title'})
116
+
117
+ if horse_name_tag != None:
118
+
119
+ horse_name_tag.find('h1')
120
+
121
+ horse_name = "".join([x for x in horse_name_tag.text if not x == u'\xa0' and not x == u'\n'])
122
+
123
+ print horse_name
124
+
125
+
126
+
127
+ print horse_name.strip()
128
+
129
+ cols = [horse_name]
130
+
131
+ f.write(",".join(cols) + "\n")
132
+
133
+ else:
134
+
135
+ continue
136
+
137
+
138
+
139
+ f.close()
140
+
141
+ ```
142
+
143
+
144
+
145
+ Python3.x系なら最初のコードで動くと思います。

1

冗長なのでちょっと直しました

2017/05/08 05:04

投稿

kurosuke___
kurosuke___

スコア217

test CHANGED
@@ -30,6 +30,8 @@
30
30
 
31
31
  soup = BeautifulSoup(urlopen(url.format(i)), "lxml")
32
32
 
33
+ time.sleep(5)
34
+
33
35
  div = soup.find('div', class_='horse_title')
34
36
 
35
37
 
@@ -40,17 +42,17 @@
40
42
 
41
43
  horse_name = div.h1.text
42
44
 
43
- print(horse_name)
45
+ if horse_name != None:
44
46
 
45
- horse_name_list.append(horse_name)
47
+ horse_name_list.append(horse_name)
46
48
 
47
- time.sleep(5)
49
+ else:
50
+
51
+ continue
48
52
 
49
53
  else:
50
54
 
51
55
  print("取得できないから飛ばすよ")
52
-
53
- time.sleep(5)
54
56
 
55
57
  continue
56
58