←Pythonでスクレイピング(メモ10:n番目指定・思わぬ落とし穴)
→Pythonでスクレイピング(メモ12:次の課題はJavaScriptへの対応)
こんばんは。
Pythonでスクレイピング奮闘メモです。
今回はタグの属性表記の違いによる対応と、これまでの復習になってます。
<この記事の目次>
・新たな問題が発生(続き)・・・これまでに学んだ事で全て対処可能
・タグの属性表記の違い色々・・・大文字と小文字、文字列と数字、「”」の有無
・これまでの復習だった・・・愚直にif文で対処、リストから新たなリスト作成で対処
・n番目指定とfor文でよりスマートに・・・プログラミングに正解はない
※動作環境
macOS High Sierra 10.13.6
プロセッサ 2.7 GHz Intel Core i5
メモリ 8 GB 1867 MHz DDR3
Python 3.6.0 :: Anaconda custom (x86_64)
コマンド実行は「ターミナル」、.py編集は「Xcode」を使用
※参考文献「Python エンジニア ファーストブック」(142ページ以降中心)
以下試行錯誤メモ。
新たな問題が発生(続き)
もう一度通して何がしたいのかおさらい。
JRAの重賞一覧ページから各重賞結果ページにクロールして、単勝人気順と最終オッズをスクレイピングするコードを作成していました。
結果ページのソースが2017年の途中から変わっていたため、それの対応を頑張りました。
前々回(メモ9:文字列の置換とリスト作成)ようやく完了したんですが、念の為さらに遡って調べると・・・
①2015年以前の重賞一覧ページ
②2006年途中以前の結果ページ
以上のソースが違いました。
①2015年以前の重賞一覧ページ
前回(メモ10:n番目指定・思わぬ落とし穴)完遂。
②2006年途中以前の結果ページ
結果ページでスクレイピングしたい情報は「単勝人気・オッズ」の2つです。
2006年12月24日開催の有馬記念の結果ページのソース(一部、2007〜1017途中まで同様)。
<tr bgcolor="#FFFFFF"> <td align="center" nowrap class="gray12"> 1</td> ・・・(枠番・馬名などの情報)・・・ <td align="center" nowrap class="gray12">1</td> </tr> ・・・(以後繰り返し)・・・ <table width="753" border="0" cellpadding="3" cellspacing="1" bgcolor="#BABABA"> <tr class="gray12"> <td bgcolor="#EEEDCE" valign="top">単勝</td> <td align="center" bgcolor="#FFFFFF" valign="top"> 4</td> <td align="right" bgcolor="#FFFFFF" valign="top">120円</td> <td align="right" bgcolor="#FFFFFF" valign="top"> 1番人気</td> ・・・(複勝なども同様)
太字がスクレイピングしたい箇所。
タグの細かい指定など、このソースに対応した話が前々回(メモ7:色々なソースに対応する・メモ8:for文を使う・メモ9:文字列の置換とリスト作成)までの話。
次に2006年1月5日開催の中山金杯の結果ページのソース(一部)。
<table border="1px" nowrap cellspacing="0" id="W01D_D2" cellpadding="1"> ・・・ <tr> <td align=CENTER nowrap><b> 1</b></td> ・・・(枠番・馬名などの情報)・・・ <td align=RIGHT nowrap> 7 </td> </tr> ・・・(以後繰り返し)・・・ <table border="1px" cellspacing="0" cellpadding="0"> <tr> <th align=CENTER valign=TOP nowrap> 単勝</th> <td align=LEFT nowrap>04</td> <td align=RIGHT nowrap> 1,420円</td> <td align=RIGHT> 7番人気 </td> </tr> ・・・(以後繰り返し)・・・
<td>タグの属性はalign=RIGHT。
さらに同日開催の京都金杯の結果ページのソース(一部)。
<table BORDER="1px" nowrap CELLSPACING="0" ID="W01D_D2" CELLPADDING="1"> ・・・ <tr> <td align=center nowrap><B> 1</B></td> ・・・(枠番・馬名などの情報)・・・ <td align=right nowrap> 6 </td> ・・・(以後繰り返し)・・・ <table BORDER="1px" CELLSPACING="0" CELLPADDING="0"> <tr> <th align=center valign=top nowrap> 単勝</th> <td align=left nowrap>05</td> <td align=right nowrap> 1,240円</td> <td align=right> 6番人気 </td> </tr> ・・・(以後繰り返し)・・・
<td>タグの属性はalign=right。
さらにさらに同年2月19日開催のフェブラリーSの結果ページのソース(一部)。
<TABLE BORDER="0" CELLPADDING="1" CELLSPACING="1" bgcolor="#000000" ID="W01D_D2" NOWRAP> ・・・ <TR> <TD ALIGN=CENTER NOWRAP bgcolor="#FFFFFF"><font size="-1"><B> 1</B></font></TD> ・・・(枠番・馬名などの情報)・・・ <TD ALIGN=RIGHT NOWRAP bgcolor="#FFFFFF"><font size="-1"> 1 </font></TD> </TR> ・・・(以後繰り返し)・・・ <TABLE BORDER="0" CELLPADDING="2" CELLSPACING="1" bgcolor="#000000"> <TR bgcolor="#FFFFFF"> <TH ALIGN=CENTER NOWRAP><font size="-1"> 単勝</font></TH> <TD ALIGN=LEFT NOWRAP bgcolor="#FFFFFF"><font size="-1">14</font></TD> <TD ALIGN=RIGHT NOWRAP bgcolor="#FFFFFF"><font size="-1"> 270円</font></TD> <TD ALIGN=RIGHT bgcolor="#FFFFFF"><font size="-1"> 1番人気 </font></TD> </TR> ・・・(以後繰り返し)・・・
<td>タグの属性はalign=RIGHTだが、その直下の<font>タグに情報がある(ただし2005〜2006途中のみ)。
また先の2つとは<table>タグの属性が微妙に違う(border値など)。
前半(単勝人気)は他の<table>タグとの区別が可能な「ID=”W01D_D2“」が同じなので問題無いが、後半(オッズ)はそれが無い。
そのため<table>タグのborder値やcellpadding値などの属性値を細かく指定せざるを得ない。
<td>タグ・<table>タグ同様にまずは愚直に(不格好だが)if文で対処した。
<td>タグ(単勝人気)の方は前回(メモ10:n番目指定・思わぬ落とし穴)学んだn番目指定とfor文を組み合わせればもう少しスマートに対処できる。
ただし<table>タグ(オッズ)の方はfor文と組み合わせても上手くいかず。
なぜなら、2004年以前は<table>タグ内の<tr>タグ直下のタグが微妙に変わっている箇所があり、<td>タグの個数が違う場合があったから。
n番目固定されていないため前々回(メモ9:文字列の置換とリスト作成)学んだリストからリストを作成する形で対処した。
これまでの復習感が強いので、タグの属性表記に関して色々試してみました。
タグの属性表記の違い色々
メモ7:色々なソースに対応するではタグの属性指定方法を学びました。
その時は属性値が同年であれば統一されていたため問題になりませんでした。
今回はその属性値のソース上での表記が違いました。
いろいろと試した結果、以下のことが分かりました。
1 大文字・小文字の区別
1-1 属性値は区別される
1-2 属性名は、属性値やソース上での表記に関係なく区別されない
2 「”」の必要性
2-1 属性値が文字列の場合、ソース上での表記に関係なく「”」は無くても良い
2-2 属性値が数字のみの場合、ソース上での表記に関係なく「”」で必ず囲う
実際に2006年1月5日開催の中山金杯の結果ページでデバッグして見てみましょう。
1 大文字・小文字の区別
1-1 属性値は区別される
ソースでは、<table id=“W01D_D2”>タグ→<tr>タグ→<td align=RIGHT>タグに「馬齢・騎手重量・タイム・馬体重の前走差・単勝人気」の5つの情報が入っています。
まずは「td[align=RIGHT]」(属性値を大文字)で指定。
In [3]: print(response.css('table[id="W01D_D2"] tr td[align=RIGHT]::text').extract()) [' 6', '57.0kg', '1:59.4', '-12', ' 7 ', ' 8', '57.0kg', '1:59.4', '-6', ' 6 ', ' 8', '56.0kg', '1:59.4', '+2', ' 9 ', ' 4', '54.0kg', '1:59.5', '+6', ' 4 ', ' 9', '56.0kg', '1:59.6', '+18', ' 8 ', ' 4', '55.0kg', '1:59.7', '+2', ' 1 ', ' 4', '53.0kg', '1:59.7', ' 0', ' 14 ', ' 4', '56.0kg', '1:59.8', '+2', ' 2 ', ' 4', '55.0kg', '1:59.8', '+10', ' 3 ', ' 6', '54.0kg', '1:59.9', '+2', ' 10 ', ' 9', '57.0kg', '2:00.2', '+4', ' 12 ', ' 4', '53.0kg', '2:00.2', '+6', ' 11 ', ' 7', '57.0kg', '2:00.2', ' 0', ' 5 ', ' 6', '53.0kg', '2:00.3', ' 0', ' 13 ', ' 6', '57.0kg', '\u3000', '+2', ' 発売後取消 ']
当然ながら上手くいきます。
次に「td[align=right]」(属性値を小文字)で指定。
In [4]: print(response.css('table[id="W01D_D2"] tr td[align=right]::text').extract()) []
残念ながら該当なしとなってしまいました。
このように属性値の大文字・小文字は区別されます。
1-2 属性名は、属性値やソース上での表記に関係なく区別されない
まずは「td[ALIGN=RIGHT]」(属性名は全て大文字)で指定。
In [11]: print(response.css('table[id=W01D_D2] tr td[ALIGN=RIGHT]::text').extract()) [' 6', '57.0kg', '1:59.4', '-12', ' 7 ', ' 8', '57.0kg', '1:59.4', '-6', ' 6 ', ' 8', '56.0kg', '1:59.4', '+2', ' 9 ', ' 4', '54.0kg', '1:59.5', '+6', ' 4 ', ' 9', '56.0kg', '1:59.6', '+18', ' 8 ', ' 4', '55.0kg', '1:59.7', '+2', ' 1 ', ' 4', '53.0kg', '1:59.7', ' 0', ' 14 ', ' 4', '56.0kg', '1:59.8', '+2', ' 2 ', ' 4', '55.0kg', '1:59.8', '+10', ' 3 ', ' 6', '54.0kg', '1:59.9', '+2', ' 10 ', ' 9', '57.0kg', '2:00.2', '+4', ' 12 ', ' 4', '53.0kg', '2:00.2', '+6', ' 11 ', ' 7', '57.0kg', '2:00.2', ' 0', ' 5 ', ' 6', '53.0kg', '2:00.3', ' 0', ' 13 ', ' 6', '57.0kg', '\u3000', '+2', ' 発売後取消 ']
問題ありません。
次に「td[AligN=RIGHT]」(属性名を大文字・小文字混在)で指定。
In [12]: print(response.css('table[id=W01D_D2] tr td[AligN=RIGHT]::text').extract()) [' 6', '57.0kg', '1:59.4', '-12', ' 7 ', ' 8', '57.0kg', '1:59.4', '-6', ' 6 ', ' 8', '56.0kg', '1:59.4', '+2', ' 9 ', ' 4', '54.0kg', '1:59.5', '+6', ' 4 ', ' 9', '56.0kg', '1:59.6', '+18', ' 8 ', ' 4', '55.0kg', '1:59.7', '+2', ' 1 ', ' 4', '53.0kg', '1:59.7', ' 0', ' 14 ', ' 4', '56.0kg', '1:59.8', '+2', ' 2 ', ' 4', '55.0kg', '1:59.8', '+10', ' 3 ', ' 6', '54.0kg', '1:59.9', '+2', ' 10 ', ' 9', '57.0kg', '2:00.2', '+4', ' 12 ', ' 4', '53.0kg', '2:00.2', '+6', ' 11 ', ' 7', '57.0kg', '2:00.2', ' 0', ' 5 ', ' 6', '53.0kg', '2:00.3', ' 0', ' 13 ', ' 6', '57.0kg', '\u3000', '+2', ' 発売後取消 ']
やはり問題なし。
このように属性名の大文字・小文字は区別されません。
2 「”」の必要性
2-1 属性値が文字列の場合、ソース上での表記に関係なく「”」は無くても良い
まずは「td[align=“RIGHT”]」(ソースでは表記のない「”」を追加)で指定。
In [7]: print(response.css('table[id="W01D_D2"] tr td[align="RIGHT"]::text').extract()) [' 6', '57.0kg', '1:59.4', '-12', ' 7 ', ' 8', '57.0kg', '1:59.4', '-6', ' 6 ', ' 8', '56.0kg', '1:59.4', '+2', ' 9 ', ' 4', '54.0kg', '1:59.5', '+6', ' 4 ', ' 9', '56.0kg', '1:59.6', '+18', ' 8 ', ' 4', '55.0kg', '1:59.7', '+2', ' 1 ', ' 4', '53.0kg', '1:59.7', ' 0', ' 14 ', ' 4', '56.0kg', '1:59.8', '+2', ' 2 ', ' 4', '55.0kg', '1:59.8', '+10', ' 3 ', ' 6', '54.0kg', '1:59.9', '+2', ' 10 ', ' 9', '57.0kg', '2:00.2', '+4', ' 12 ', ' 4', '53.0kg', '2:00.2', '+6', ' 11 ', ' 7', '57.0kg', '2:00.2', ' 0', ' 5 ', ' 6', '53.0kg', '2:00.3', ' 0', ' 13 ', ' 6', '57.0kg', '\u3000', '+2', ' 発売後取消 ']
問題なし。
次に、ソースでは「id=“W01D_D2”」と「”」付きで表記されている場合で、「table[id=W01D_D2]」のように「”」を取って指定。
In [8]: print(response.css('table[id=W01D_D2] tr td[align=RIGHT]::text').extract()) [' 6', '57.0kg', '1:59.4', '-12', ' 7 ', ' 8', '57.0kg', '1:59.4', '-6', ' 6 ', ' 8', '56.0kg', '1:59.4', '+2', ' 9 ', ' 4', '54.0kg', '1:59.5', '+6', ' 4 ', ' 9', '56.0kg', '1:59.6', '+18', ' 8 ', ' 4', '55.0kg', '1:59.7', '+2', ' 1 ', ' 4', '53.0kg', '1:59.7', ' 0', ' 14 ', ' 4', '56.0kg', '1:59.8', '+2', ' 2 ', ' 4', '55.0kg', '1:59.8', '+10', ' 3 ', ' 6', '54.0kg', '1:59.9', '+2', ' 10 ', ' 9', '57.0kg', '2:00.2', '+4', ' 12 ', ' 4', '53.0kg', '2:00.2', '+6', ' 11 ', ' 7', '57.0kg', '2:00.2', ' 0', ' 5 ', ' 6', '53.0kg', '2:00.3', ' 0', ' 13 ', ' 6', '57.0kg', '\u3000', '+2', ' 発売後取消 ']
問題なし。
このように、属性値が文字列の場合は「”」は有っても無くても問題ありません。
2-2 属性値が数字のみの場合、ソース上での表記に関係なく「”」で必ず囲う
まずは属性値が数字のみで、ソースでの表記では「”」が有る(「cellspacing=“0“」の)場合で、「table[cellspacing=0]」のように「”」を取って指定。
In [9]: print(response.css('table[cellspacing=0] tr td[align="RIGHT"]::text').extract()) File "<string>", line unknown SelectorSyntaxError: Expected string or ident, got <NUMBER '0' at 18>
文法Errorになります。
「”」を付けて指定すれば問題ありません。
In [10]: print(response.css('table[cellspacing="0"] tr td[align="RIGHT"]::text').extract()) ['2000m', '芝・右 ', 'ハンデ', ' 発走 15:25', ' 6', '57.0kg', '1:59.4', '-12', ' 7 ', ' 8', '57.0kg', '1:59.4', '-6', ' 6 ', ' 8', '56.0kg', '1:59.4', '+2', ' 9 ', ' 4', '54.0kg', '1:59.5', '+6', ' 4 ', ' 9', '56.0kg', '1:59.6', '+18', ' 8 ', ' 4', '55.0kg', '1:59.7', '+2', ' 1 ', ' 4', '53.0kg', '1:59.7', ' 0', ' 14 ', ' 4', '56.0kg', '1:59.8', '+2', ' 2 ', ' 4', '55.0kg', '1:59.8', '+10', ' 3 ', ' 6', '54.0kg', '1:59.9', '+2', ' 10 ', ' 9', '57.0kg', '2:00.2', '+4', ' 12 ', ' 4', '53.0kg', '2:00.2', '+6', ' 11 ', ' 7', '57.0kg', '2:00.2', ' 0', ' 5 ', ' 6', '53.0kg', '2:00.3', ' 0', ' 13 ', ' 6', '57.0kg', '\u3000', '+2', ' 発売後取消 ', ' 1,420円', ' 7番人気 ', ' 450円', ' 7番人気 ', ' 380円', ' 6番人気 ', ' 990円', ' 8番人気 ', ' 1,730円', ' 12番人気 ', ' 9,100円', ' 28番人気 ', ' 2,400円', ' 27番人気 ', ' 5,230円', ' 49番人気 ', ' 3,220円', ' 36番人気 ', ' 19,710円', ' 57番人気 ', ' 54,230円', ' 119番人気 ', ' 365,360円', ' 720番人気 ']
次にソースでの表記では「”」が無い(「cellspacing=0」の)場合で、「table[cellspacing=0]」のように「”」を取って指定。
※2004年1月5日開催の京都金杯の結果ページでデバッグ。
In [2]: print(response.css('table[cellspacing=0] tr td[align="RIGHT"]::text').extract()) File "<string>", line unknown SelectorSyntaxError: Expected string or ident, got <NUMBER '0' at 18>
やはり文法Errorになります。
こちらも「”」を付けて指定すれば問題ありません。
In [3]: print(response.css('table[cellspacing="0"] tr td[align="RIGHT"]::text').extract()) ['1600m', '芝・右\u3000外 ', 'ハンデ', '発走 15:45', ' 5', ' 57.0kg', '+8', '9', ' 6', ' 58.0kg', ' 0', '1', ' 4', ' 56.0kg', '+6', '6', ' 4', ' 56.5kg', '-12', '3', ' 4', ' 56.0kg', '+8', '2', ' 5', ' 55.0kg', '-2', '11', ' 4', ' 54.0kg', ' 0', '5', ' 6', ' 55.5kg', ' 0', '7', ' 4', ' 53.0kg', '+6', '10', ' 6', ' 55.0kg', '+4', '4', ' 7', ' 57.0kg', '+6', '14', ' 7', ' 59.0kg', '+6', '8', ' 8', ' 56.0kg', '-6', '12', ' 7', ' 52.0kg', '+6', '15', ' 7', ' 53.0kg', '+2', '16', ' 4', ' 54.0kg', '+2', '13', ' 3,070円', '9番人気', ' 470円', '8番人気', ' 140円', '1番人気', ' 370円', '7番人気', ' 1,280円', '5番人気', ' 4,750円', '18番人気', ' 1,810円', '21番人気', ' 5,170円', '58番人気', ' 920円', '8番人気', ' 12,940円', '45番人気', ' 20,000円', '65番人気']
このように、属性値が数字のみの場合はソース上での表記に関係なく「”」が必要です。
これまでの復習だった
先節で分かったのは、2005年と2006年の結果ページから「単勝人気」をスクレイピングしたいなら、<td>タグの属性値が大文字or小文字or<td>タグ直下の<font>タグの3パターンを別々で対処すれば良いということ。
※2004年以前は<font>タグが無いので2パターン。
とりあえずはif文で対処可能。
属性値さえ正しく指定すれば、単勝人気は取得したリストの5の倍数番目にある(先節の結果から分かる)ので、「メモ8:for文を使う」と同じように対応。
keiba2 = response.css('table[id="W01D_D2"] tr') if keiba2.css('td[align=RIGHT]::text'): keiba2 = keiba2.css('td[align=RIGHT]::text') elif keiba2.css('td[align=right]::text'): keiba2 = keiba2.css('td[align=right]::text') else: keiba2 = keiba2.css('td[align=RIGHT] font::text') l = len(keiba2) a = l/5 + 1 n = [] for b in range(1,int(a)): c = b * 5 - 1 n.append(keiba2[c].extract()) item['ninki'] = n
単純に<td>タグの属性値を3パターン指定すれば大丈夫っていう、なかなかのゴリ押しコードです笑
次節でもう少しスマートに対処しています。
続いて「オッズ」は4パターンありました。
※2004年以前は少し改良して2パターン。
こちらも属性値さえ正しく指定すれば、「メモ9:文字列の置換とリスト作成」と同じように対応可能。
keiba3 = response.css('table[border="1px"][cellspacing="0"][cellpadding="0"]') if keiba3.css('td[align=RIGHT]::text'): keiba3 = keiba3.css('td[align=RIGHT]::text') elif keiba3.css('td[align=right]::text'): keiba3 = keiba3.css('td[align=right]::text') elif response.css('table[border="0"][cellspacing="1"][cellpadding="2"] td[align=RIGHT] font::text'): keiba3 = response.css('table[border="0"][cellspacing="1"][cellpadding="2"] td[align=RIGHT] font::text') else: keiba3 = response.css('table[border="1"][cellspacing="0"][cellpadding="0"] td[align=right]::text') odd = keiba3.extract() item['odds'] = [s.replace('\n', '').replace('\r', '').replace(',' , '').replace('円' , '') for s in odd if '円' in s]
さらにゴリ押し感が出てます笑
<table>タグの属性値以外はここまで絞らなくても、オッズは円表示なので、結局最後の一行の「if ‘円’ in s」で絞り込んでいるので大丈夫だと思います。
その辺は次節でほんの少し改良しています。
今まで苦労してきたことを活かせたことは大きいです。
n番目指定とfor文でよりスマートに
2004年以前の結果ページも基本は同じだったんですが、微妙に<td>タグの属性値が違いました。
それも大文字・小文字レベルではありませんでした。
そこで先節のコードをよりスマートにすることも目的に、少し改良を試みました。
例えば「単勝人気」は、<table id=”W01D_D2″>タグ内にある<tr>タグ内ごとの、15番目の<td>タグにあるので、「メモ10:n番目指定・思わぬ落とし穴」と同じように対処してみました。
keiba5 = response.css('table[id="W01D_D2"]') n = [] for keiba2 in keiba5.css('tr'): if keiba2.css('td:nth-child(15)::text').extract_first(): n.append(keiba2.css('td:nth-child(15)::text').extract_first()) item['ninki'] = [s.replace('\n', '') for s in n]
4行目のif文は、一番目の<tr>タグが表の凡例に該当し(15番目が存在しないため)Noneを出力するので、「AttributeError: ‘NoneType’ object has no attribute ‘replace’」となるのを防いでいます(詳しくは「メモ10:n番目指定・思わぬ落とし穴」)。
これは明らかに改良と言って良いでしょう。
2004年1月5日開催の京都金杯の結果ページでデバッグするとこんな感じ。
In [3]: keiba5 = response.css('table[id="W01D_D2"]') ...: n = [] ...: for keiba2 in keiba5.css('tr'): ...: n.append(keiba2.css('td:nth-child(15)::text').extract_first()) ...: print(n) ...: [None, '9', '1', '6', '3', '2', '11', '5', '7', '10', '4', '14', '8', '12', '15', '16', '13']
※この場合「.replace(‘\n’, ”)」は必要ではないですが、他のページでは必要なので。
同じように「オッズ」も<table>タグまで指定してあとはfor文で対処してみました。
if response.css('table[border="1px"][cellspacing="0"][cellpadding="0"]'): keiba3 = response.css('table[border="1px"][cellspacing="0"][cellpadding="0"]') else: keiba3 = response.css('table[border="1"][cellspacing="0"][cellpadding="0"]') m = [] for keiba4 in keiba3.css('tr'): m.append(keiba4.css('td[align=RIGHT]::text').extract_first()) item['odds'] = [s.replace('\n', '').replace('\r', '').replace(',' , '').replace('円' , '') for s in m]
よくよく見るとあまり改良にはなっていない気がします。
単に<table>タグの属性値パターンが減っただけかもしれません笑
2004年1月5日開催の京都金杯の結果ページでデバッグするとこんな感じ。
In [5]: if response.css('table[border="1px"][cellspacing="0"][cellpadding="0"]'): ...: keiba3 = response.css('table[border="1px"][cellspacing="0"][cellpadding="0"]') ...: else: ...: keiba3 = response.css('table[border="1"][cellspacing="0"][cellpadding="0"]') ...: m = [] ...: for keiba4 in keiba3.css('tr'): ...: m.append(keiba4.css('td[align=RIGHT]::text').extract_first()) ...: print([s.replace('\n', '').replace('\r', '').replace(',' , '').replace('円' , '') for s in m]) ...: [' 3070', ' 470', ' 140', ' 370', ' 1280', ' 4750', ' 1810', ' 5170', ' 920', ' 12940', ' 20000']
ちなみに先節と同じようなコードだとこんな感じ。
In [9]: if response.css('table[border="1px"][cellspacing="0"][cellpadding="0"]'): ...: keiba3 = response.css('table[border="1px"][cellspacing="0"][cellpadding="0"]') ...: else: ...: keiba3 = response.css('table[border="1"][cellspacing="0"][cellpadding="0"]') ...: odd = keiba3.css('::text').extract() ...: print([s.replace('\n', '').replace('\r', '').replace(',' , '').replace('円' , '') for s in odd if '円' in s]) ...: [' 3070', ' 470', ' 140', ' 370', ' 1280', ' 4750', ' 1810', ' 5170', ' 920', ' 12940', ' 20000']
こっちの方がコード量は少ないです。
「単勝人気」の方は明らかに改良だと思いますが、こちらはどうでしょうか。
残念ながらn番目指定で統一出来ないのが痛いです。
プログラミングに正解は無いと思っているので、どちらが良いかは人それぞれ、ということにします。