

# 前提・実現したいこと

お世話になります、python初心者ですpython2.7,beautifulsoupを用いて、競馬データをスクレイピングしておりますが、どうにも困っております。  
１行だけはprintすることが出来るのですが、２０行をスクレイピングするスクリプトと、併せて、CSVに出力させるスクリプトが分かりません。

# 発生している問題・エラーメッセージ

csvに保存が出来ないこと

２０行をまとめてスクレイピングすることが出来ないこと

[code]

    # -*- coding:utf-8 -*-
    
    
    import urllib2
    import codecs
    from bs4 import BeautifulSoup
    
    f = codecs.open('horse.csv', 'w', 'utf-8')
    f.write('race_date,kaisai,weather,race_number,race_name,tousuu,frame_number,horse_number,single_win_ratio,popularity,horse_arrival,horse_name,weight,distance,baba, race_time,difference,horse_pass,pace,nobori,horse_weight,win_horse,prize_money'+ u"\n")
    
    tpl_url='http://db.netkeiba.com/?pid=jockey_detail&id=00663&page={0}'
    
    for i in xrange(1, 5):
        url=tpl_url.format( i )
        soup = BeautifulSoup(urllib2.urlopen(url).read(),"lxml")
        tr_arr = soup.find('div', {'id':'contents_liquid'}).findAll('tbody')  
    
        for tr in tr_arr:
    
        #日付#race_date
            lrg1= tr.findAll('td')[0].string
            #開催#kaisai
            lrg2= tr.findAll('td')[1].string
            #天気#weather
            lrg3= tr.findAll('td')[2].string
            #第○ﾚｰｽ#race_number
            lrg4= tr.findAll('td')[3].string
            #ﾚｰｽ名#race_name
            lrg5= tr.findAll('td')[4].string
            #映像（この部分、削除したいです）
            lrg6= tr.findAll('td')[5].string
            #頭数#tousuu
            lrg7= tr.findAll('td')[6].string
            #枠番#frame_number
            lrg8= tr.findAll('td')[7].string
            #馬番#horse_number
            lrg9= tr.findAll('td')[8].string
            #単勝#single_win_racio
            lrg10= tr.findAll('td')[9].string
            #人気#popularity
            lrg11= tr.findAll('td')[10].string
            #着順#horse_arrival
            lrg12= tr.findAll('td')[11].string
            #馬名#horse_name
            lrg13= tr.findAll('td',{'class':'txt_l'}) [1]
            #斤量#weight
            lrg14= tr.findAll('td')[13].string
            #距離#distance
            lrg15= tr.findAll('td')[14].string
            #馬場#baba
            lrg16= tr.findAll('td')[15].string
            #タイム#race_time
            lrg17= tr.findAll('td')[16].string
            #着差#difference
            lrg18= tr.findAll('td')[17].string
            #通過#horse_pass
            lrg19= tr.findAll('td')[18].string
            #ペース#pace
            lrg20= tr.findAll('td')[19].string
            #上り#nobori
            lrg21= tr.findAll('td')[20].string
            #馬体重#horse_weight
            lrg22= tr.findAll('td')[21].string
            #勝ち馬#win_horse
            lrg23= tr.findAll('td',{'class':'txt_l'}) [2]
            #賞金#prize_money
            lrg24= tr.findAll('td')[23].string
    
            print lrg1,lrg2,lrg3,lrg4,lrg5,lrg6,lrg7,lrg8,lrg9,lrg10,\
                      lrg11,lrg12,lrg13.a.string,lrg14,lrg15,lrg16,lrg17,\
                      lrg18,lrg19,lrg20,lrg21,lrg22,lrg23.a.string,lrg24
    
    
            f.close()
    
[/code]

# 試したこと

forなどで、ループさせてみましたが、スキル不足でうまくいきませんでした。

# 補足情報(言語/FW/ツール等のバージョンなど)

python2.7

findAllを多用して、力ずくで作ったプログラムでございます。  
先輩の皆様方、御教示よろしくお願いいたします。


CC BY-SA 3.0
2016-08-10T11:28:53.053
28178
2018-07-20T07:52:38.363
2018-07-20T07:52:38.363
19110
18438
question
python array csv python2 beautifulsoup
beautifulsoupを用いて、規則性のある20行24列の競馬のデータ表をCSVに書き込みたい


`f.close()` した時点で続きを書き込めなくなり、2行目以降が出力されないのでしょう。  
`f.close()` を削除してください。


CC BY-SA 3.0
2016-08-10T12:32:32.213
28182
2016-08-10T12:32:32.213
806
28178
answer


テーブルには２０行があるのに、１行しか取得できないの原因は

[code]

    soup.find('div', {'id':'contents_liquid'}).findAll('tbody')
    
[/code]

`tbody` は一つしかないので、for ループが１回だけ走らせしました。`tbody` から各 `tr` を取り出す必要があります。すなわち

[code]

    soup.find('div', {'id':'contents_liquid'}).find('tbody').findAll('tr')
    
[/code]

なお、`tr.findAll('td')[0].string` は `NavigableString` タイプのオブジェクトを取り出すことです。その後
CSV に書き込むから、`tr.findAll('td')[0].text` で文字列を取得すべきです。

Python で csv
の利用するのは、[こちら](https://docs.python.org/2/library/csv.html)ご参考ください。また、CSV に
Unicode を書くため、各 unicode 文字列を `.encode('utf-8')` すれば結構です。なお、`with` 文を使用して、自ら
`.close()` しないほうが良いと思います。

コードを修正してみました

[code]

    import urllib2
    import codecs
    from bs4 import BeautifulSoup
    import csv
    
    # with 文を使い、f.close() を取り除きました
    with open('horse.csv', 'w') as f:
        writer = csv.writer(f)
        writer.writerow(['race_date', 'kaisai', 'weather', # ...
                        ])
    
        tpl_url='http://db.netkeiba.com/?pid=jockey_detail&id=00663&page={0}'
    
        for i in xrange(1, 5):
            url=tpl_url.format( i )
            soup = BeautifulSoup(urllib2.urlopen(url).read(),"lxml")
            tr_arr = soup.find('div', {'id':'contents_liquid'}).find('tbody').findAll('tr')
    
            for tr in tr_arr:
                tds = tr.findAll('td')
    
                lrg = []
                for index, td in enumerate(tr.findAll('td')):
                    # ループの改善について：一部の td は特別処理されて
                    if index == 12:
                        lrg.append(tr.findAll('td', {'class':'txt_l'})[1].text)
                    elif index == 22:
                        lrg.append(tr.findAll('td', {'class':'txt_l'})[2].text)
                    else:
                        # ほかの普通の td はそのままリストに入れる
                        lrg.append(td.text)
    
                writer.writerow([s.strip().encode('utf-8') for s in lrg])
    
[/code]


CC BY-SA 3.0
2016-11-24T05:11:44.253
30641
2016-11-24T05:42:18.793
2016-11-24T05:42:18.793
18621
18621
28178
answer