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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python

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

Q&A

解決済

2回答

1238閲覧

Python Web上のテーブルからtdの値を取得したい

human4423

総合スコア1

Python

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

0グッド

0クリップ

投稿2022/10/12 17:49

編集2022/10/13 15:34

前提

Pythonの初心者で勉強中であるため質問の仕方がおかしかったら申し訳ございません。
本を見ながら試してみたのですが、エラーが出てこれ以上進めることができない状態です。

実現したいこと

Web上にある次のようなテーブルから「年月」「売上」「客数」を取得し、最終的にCSVにしたいと考えています。

年月売上単価客数
2022年1月520,0005,200100
2022年2月600,0005,000120
2022年3月663,0005,100130
2022年4月504,0006,30080
2022年5月638,0005,800110

HTML

1<thead> 2 <tr> 3 <th class="syukei">年月</th> 4 <th class="syukei">売上</th> 5 <th class="syukei">客数</th> 6 </tr> 7</thead> 8<tbody> 9 <tr> 10 <th class="year">2022年1月</th> 11 <td>520,000</td> 12 <td>5,200</td> 13 <td>100</td> 14 </tr> 15 <tr> 16 <th class="year">2022年2月</th> 17 <td>600,000円</td> 18 <td>5,000</td> 19 <td>9,350</td> 20 <td>120</td> 21 </tr> 22</tbody>

完成イメージ

イメージ説明

分からないこと

①"年月"の列が<th>で、取得の仕方が分かりません。
②とりあえず<td>の値だけ取得しようとしたら下部に記載のエラーが出ます。

試したこと

Python

1#空リストの作成 2vals1 = []#売上 3vals2 = []#客数 4 5#テーブルのボディ部分を選択する 6table = driver.find_element_by_tag_name('tbody') 7#ボディ部分からtrタグをすべて取得 8elems = table.find_elements_by_tag_name('tr') 9 10#trタグの数だけループしtdの値を取得 11for elem in elems: 12 val1 = elem.find_elements_by_tag_name('td')[0].text 13 val2 = elem.find_elements_by_tag_name('td')[2].text 14 15#取得した値をvalsリストに順番に追加 16 vals1.append(vals1) 17 vals2.append(vals2) 18 19#CSV作成 20import pandas as pd 21df=pd.DataFrame({'売上':vals1,'客数':vals1}) 22df.to_csv("集計.csv",encoding="shift_jis")

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

IndexError: list index out of range

インデックスが範囲外とのことですが、('td')[0]を[1]や[2]に変えたところでは変わらないです。

該当のソースコード

val1 = elem.find_elements_by_tag_name('td')[0].text

補足(取得したい情報)

これが実際に取得したい対象のテーブルになります。
テーブルの左端から「年月」~「再来」の数字を1年分取得したいと思っています。

イメージ説明
イメージ説明

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

T_F

2022/10/13 05:23 編集

[0]でout of rangeなので、"td"の要素が1つもないようです。 本当にtdタグが入ったhtmlが取れているかどうか、確かめたほうが良いでしょう。 提示してもらったコードの一番上のタイミングで print(driver.page_source) を実行してhtmlを表示するとどうなりますか?
human4423

2022/10/13 15:21

コメントありがとうございます! 一番上にprint(driver.page_source)を入れて実行すると膨大な量のソースが出てきました。 細かく見ていったところ、取得したいtable、tdもありましたが、他にも色んなtableが存在していました。 もしかして、何のtableから取得したいのかが明確になっていないということでしょうか? ※この時間しか勉強ができず、せっかくコメントいただいたのに遅くなり申し訳ございません。
human4423

2022/10/13 15:37

質問欄の最後に補足として実際のテーブルとそのソースの画像を載せました。
T_F

2022/10/13 17:52

はい、tableを絞り込む必要がありそうです。
guest

回答2

0

ベストアンサー

テーブルを選択する部分で、classを使って絞り込む必要があります。
月次売上表が年ごとに分かれているなど、同じクラス名のテーブルが複数ある場合は、上から何番目かも指定する必要があります。

元のコードで

python

1#テーブルのボディ部分を選択する 2table = driver.find_element_by_tag_name('tbody')

のところを

python

1#テーブルのボディ部分を選択する 2monthly_table_number = 0 # いくつかある月次売上表のうち該当のものの番号(0始まり順) 3tables = driver.find_elements_by_class_name("monthlySalesTable") 4table = tables[monthly_table_number].find_element_by_tag_name("tbody")

としてください。
該当の表が月次売上表の中で何番目かを数えて、monthly_table_numberを変更してください。

また、別に1箇所バグがあります。

python

1#取得した値をvalsリストに順番に追加 2 vals1.append(vals1) 3 vals2.append(vals2)

で、appendする右側のvals1, vals2が、本当はval1, val2が正しいです。

これで動くかどうか試してみてください。

投稿2022/10/13 17:51

T_F

総合スコア74

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

human4423

2022/10/14 01:50

できましたできました!! 全てご指摘の通りでありました! ありがとうございます!大変助かりました!!
guest

0

CSV の作成に Pandas を使われていますが、それでしたら Pandas の read_html() で HTML テーブルを読み込んでみてもよいかもしれません。

python

1import pandas as pd 2import sys 3 4url = 'https://teratail.com/questions/6su8tx7uey56y2' 5dfs = pd.read_html(url) # table 要素に id や class が付与されている場合はそれを利用する 6 7cols = ['年月', '売上', '単価', '客数'] 8scols = {*cols} 9dfs = [df for df in dfs if scols == {*df.columns}] 10if not dfs: 11 print('table not found', file=sys.stderr) 12 sys.exit(1) 13 14df = dfs[0][[c for c in cols if c != '単価']] 15df.to_csv("集計.csv",encoding="shift_jis",index=False)

集計.csv

csv

1年月,売上,客数 22022年1月,520000,100 32022年2月,600000,120 42022年3月,663000,130 52022年4月,504000,80 62022年5月,638000,110

投稿2022/10/12 18:07

編集2022/10/12 18:33
melian

総合スコア19803

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

human4423

2022/10/13 15:36

ご回答いただきありがとうございます! 確かに、書いていただいたコードをそのまま試したらこのページに私がサンプルで書いたテーブルの値がCSVとして作成されました! ただ、実際に取得したいwebページ(業務で使っている管理システム)だとダメみたいです。 エラーも出ないので何が原因かもわからないのですが… 今、追加情報として質問の中に実際のテーブルの画像とそのソースを載せてみましたが、<th>が結合されてることとか関係ありますか?
melian

2022/10/13 18:13

一応、class を指定すると読み込む様です。 dfs = pd.read_html(url, attrs={'class': 'monthlySalesTable'}) print(dfs[0]) ただ、カラム名がマルチインデックスになってしまいますが、、、
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問