質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.45%

  • Python

    12377questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 2.7

    1473questions

    Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

python2.7,beautifulsoupでのスクレイピングが、うまく出来ません。

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,804

akakage13

score 80

前提・実現したいこと

python初心者でございます。
競走馬の情報をスクレイピングしておりますが、父馬、母馬の抽出がうまく出来ません。

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

Traceback (most recent call last):
  File "C:\Users\satoru\horse\horse-test-kami-1.py", line 46, in <module>
    tdh = tr_arr1.findAll("td") #縺薙%縺ョ謚ス蜃コ譁ケ豕輔↓闍ヲ諷ョ縺励※縺翫j縺セ縺・
AttributeError: 'list' object has no attribute 'findAll'

該当のソースコード

# -*- coding:utf-8 -*-

import urllib2
import codecs
import time
from bs4 import BeautifulSoup
f = codecs.open('horse.csv', 'w', 'utf-8')
f.write('horse_name,f_horse_name,m_horse_name,race_date,kaisai,weather,race_number,race_name,tousuu,frame_number,horse_number,horse_odds,popularity,horse_arrival,jockey_name,weight,distance,baba,race_time,difference,horse_pass,pace,nobori,horse_weight,win_horse'+u"\n")

url='http://db.netkeiba.com/horse/1994103997/'

soup = BeautifulSoup(urllib2.urlopen(url).read(),"lxml")

tr_arr = soup.select("table.db_h_race_results > tbody > tr")

for tr in tr_arr:
    time.sleep(1)    
    tds=tr.findAll("td")
    race_date=tds[0].a.text    #日付
    kaisai=tds[1].a.text     #開催
    weather=tds[2].text    #天気
    race_number=tds[3].text  #R
    race_name=tds[4].a.text    #レース名
    tousuu=tds[6].text    #頭数
    frame_number=tds[7].text    #枠番
    horse_number=tds[8].text    #馬番
    horse_odds=tds[9].text    #オッズ
    popularity=tds[10].text    #人気
    horse_arrival=tds[11].text    #着順
    jockey_name=tds[12].a.text     #騎手名
    weight=tds[13].text    #斤量
    distance=tds[14].text    #距離
    baba=tds[15].text    #馬場
    race_time=tds[17].text    #タイム
    difference=tds[18].text    #着差
    horse_pass=tds[20].text    #通過
    pace=tds[21].text    #ペース
    nobori=tds[22].text    #上り
    horse_weight=tds[23].text    #馬体重
    win_horse=tds[26].text    

    horse_name_tag=soup.find('div',{'class':'horse_title'}).find('h1')
    horse_name="".join([x for x in horse_name_tag.text if not x == u'\xa0' and not x == u'\n'])

    tr_arr1 = soup.select("table.blood_table > tbody > tr")
    tdh = tr_arr1.findAll("td")    #ここの抽出方法に苦慮しております
    f_horse_name = tdh[0].a.text    
    m_horse_name = tdh[1].a.text     

    print horse_name.strip(),f_horse_name.strip(),m_horse_name.strip(),race_date.strip(),kaisai.strip(),weather.strip(),race_name.strip(),tousuu.strip(),frame_number.strip(),horse_number.strip(),horse_odds.strip(),popularity.strip(),horse_arrival.strip(),jockey_name.strip(),weight.strip(),distance.strip(),baba.strip(),race_time.strip(),difference.strip(),horse_pass.strip(),pace.strip(),nobori.strip(),horse_weight.strip(),win_horse.strip()
    cols = [horse_name,f_horse_name,m_horse_name,race_date,kaisai,weather,race_number,race_name,tousuu,frame_number,horse_number,horse_odds,popularity,horse_arrival,jockey_name,weight,distance,baba,race_time,difference,horse_pass,pace,nobori,horse_weight,win_horse]
    f.write(",".join(cols) + "\n")

f.close()

試したこと

soup.find,soup selectを用いて試みましたが、うまくできませんでした。

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

f_horse_name:父馬(サンデーサイレンス)、m_horse_name:母馬(ワキア)を抽出することが目的でございます。よろしく御教示お願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

soup.select()をしてからわざわざfindAll()をするのは意味がありません。
全部soup.select()でやってしまえば良い話です。
https://teratail.com/questions/43942 でsoup.select()の意味を少しだけ説明しています(冒頭の箇所)ので読み返してみて下さい。

それと、血統情報のテーブルには<tbody>が無いので、それがあると正しくデータが取れないはずです。
ちゃんとHTMLソースを見て確認しましょう。

soup.select()した結果は、printしてどんな結果が取れたのか確認してください。
今回の場合ならtr_arr1printしてみて下さい。
[ ]で囲まれているとしたら、それはlist型です。findAll()tag型のメソッドでlist型のメソッドでは無いです。

...

あと、エラーとは関係ないですが、
血統情報のテーブルはは競走成績とは別のテーブルですよね?なので競争成績のループの中で取得するのは無駄があります。
以前の騎手のときと同じようにループの前で取得するようにしましょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/08/18 21:00

    argius様、いつもありがとうございます。

    今回、抽出したい部分は以下のHTMLソース部分の、サンデーサイレンスという文字と
    ワキアという文字の2つでございます。

    blood_tableを大枠に考えて、<tbody><tr>から<a>の取得を思いましたが、うまくできません。

    1案 tr_arr1 = soup.select("table.blood_table > tbody > tr")
    2案 tr_arr1 = soup.findAll('div',{'class':'db_prof_box'}).find('?') #?:見当もつかない意
    HTMLソースの根本的な見方が分かっていないことが原因とも思います。

    現状では、1案、2案のどちらが良いのかもわかりません。
    御教示のいただいた前回の質問の部分も読み返しましたが、ピンときません。

    乱文であり、恐縮ではございますが、ヒントをいただけますとありがたく思います。

    よろしくお願いいたします。

    http://db.netkeiba.com/horse/1994103997/  より抽出を試みております。

    抽出対象ソース

    <div class="db_prof_box">
    <dl class="fc">
    <dt class="DB_ProfHead_dt_01">
    <div class="fc">
    <p class="db_prof_top_padigree_title png_bg">血統</p>
    </div>
    </dt>
    <dd class="DB_ProfHead_dd_01">
    <table cellpadding="0" cellspacing="0" summary="サイレンススズカの血統表" class="blood_table">
    <tbody><tr>
    <td rowspan="2" class="b_ml">
    <a href="/horse/ped/000a00033a/" title="サンデーサイレンス">サンデーサイレンス</a>
    </td>
    <td class="b_ml">
    <a href="/horse/ped/000a0012bf/">Halo</a>
    </td>
    </tr>
    <tr>
    <td class="b_fml">
    <a href="/horse/ped/000a008c1e/">Wishing Well</a>
    </td>
    </tr>
    <tr>
    <td rowspan="2" class="b_fml">
    <a href="/horse/ped/000a006378/">ワキア</a>
    </td>
    <td class="b_ml">
    <a href="/horse/ped/000a0017b0/">Miswaki</a>
    </td>
    </tr>
    <tr>
    <td class="b_fml">
    <a href="/horse/ped/000a00930c/">Rascal Rascal</a>
    </td>
    </tr>
    </tbody></table>
    </dd>
    </dl>
    <p class="detail_link"><a href="/horse/ped/1994103997/" title="サイレンススズカの血統詳細">血統詳細・兄弟馬</a></p>
    </div>

    キャンセル

  • 2016/08/18 21:59

    私が見る限りでは、当該ページの当該箇所には、<tbody>がありません。
    試しに、
    table_arr = soup.select("table.blood_table")
    print table_arr
    としてみてください。
    その中に<tbody>はありますか?

    キャンセル

  • 2016/08/19 19:35

    argius様、ありがとうございました。[]listの意味がよくわかり問題解決いたしました。
    ヒントを頂いたおかげで、自力でargius様の御指摘がわかり、少し自信がつきました。

    ただ、ひとつ、疑問が残ることがございます。
    上記の御指導の中で
    table_arr = soup.select("table.blood_table")
    print table_arr
    としてみてください。
    その中に<tbody>はありますか?
    について、早速、試してはみましたが、確かに<tbody>はございませんでした。
    しかしながら、小生は、下記のソースコードから、<tbody>は必ず在ると確信して
    スクリプトを書いておりました。

    <tbody><tr>
    <td rowspan="2" class="b_ml">
    <a href="/horse/ped/000a00033a/" title="サンデーサイレンス">サンデーサイレンス

    貴殿の御指導とおり、printしましたら、下記の通りでした。

    C:\Users\satoru\horse>horse-test-kami-1-1.py
    [<td class="b_ml" rowspan="2">\n<a href="/horse/ped/000a00033a/" title="\u30b5\u30f3\u30c7\u30fc\u30
    b5\u30a4\u30ec\u30f3\u30b9">\u30b5\u30f3\u30c7\u30fc\u30b5\u30a4\u30ec\u30f3\u30b9</a>\n</td>, <td c
    lass="b_ml">\n<a href="/horse/ped/000a0012bf/">Halo</a>\n</td>, <td class="b_fml">\n<a href="/horse/
    ped/000a008c1e/">Wishing Well</a>\n</td>, <td class="b_fml" rowspan="2">\n<a href="/horse/ped/000a00
    6378/">\u30ef\u30ad\u30a2</a>\n</td>, <td class="b_ml">\n<a href="/horse/ped/000a0017b0/">Miswaki</a
    >\n</td>, <td class="b_fml">\n<a href="/horse/ped/000a00930c/">Rascal Rascal</a>\n</td>]

    リスト型であることが分かったことと、確かにどこにも<tbody>はございませんでした。

    しかしながら、google-Chromeのビューアーで検証にしてツリー構造を確認しましたら
    <tbody>は確かにありました(上記のソースコードの通り)

    大枠の"table.blood_table"が分かった時点で、
    printして、それを根拠に逆算を今回はいたしまして、無事に取得することが出来ましたが、次回からは、正直なところ、ツリー構造を読む自信がなくなりました。
    小生のツリー構造の見方の何が誤っているのか、御教示頂けますと、幸いでございます。

    とにもかくにも、教育まで見据えた御教示に、感謝いたします。
    重ねてありがとうございました。

    今後とも御指導、よろしくお願いいたします。

    キャンセル

  • 2016/08/19 20:02

    なるほど、デベロッパーツールのツリービューで見ているんですね。
    ツリービューだと、構造が補完されてしまうみたいです。
    私も確認してみましたが、確かにtbodyが出てきました。

    デベロッパーツールのElementsタブでなく、Sourcesタブで見るか、
    ページを右クリックして「ページのソースを表示」をすれば、
    生のHTMLソースが見られます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.45%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Python

    12377questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 2.7

    1473questions

    Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。