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

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

新規登録して質問してみよう
ただいま回答率
85.48%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

519閲覧

pythonでのスクレイピング

mana40

総合スコア12

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

2クリップ

投稿2018/05/17 15:07

前提・実現したいこと

python初心者です。
下記のサイトからチーム毎に各ゴールパターンのゴール数というデータを取得し、リストの形で保持したいと考えています。

http://www.football-lab.jp/summary/team_ranking/j1/?year=2018&data=goal

リスト化したい箇所はサイトでは「得点数」としてグラフ化されている部分の元データです。

[[広島,2,0,6,4,0,3,0,3,4,0],
[FC東京,3,0,3,4,2,4,1,1,2,1],
...]

というようなデータにしたいです。

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

かなり強引にですが、beautifulsoupで該当箇所を文字列として取得する事は出来ました。
得られた文字列はチーム毎に[]で囲まれて、見た目はもう少しでリスト化出来そうなのですが、
そこから先が思いつきません。

該当のソースコード

python

1import requests 2import re 3 4from bs4 import BeautifulSoup,Comment 5 6url = "http://www.football-lab.jp/summary/team_ranking/j1/?year=2018&data=goal" 7 8response = requests.get(url) 9bs = BeautifulSoup(response.content,"lxml") 10 11test=str(bs.find(string=re.compile("function drawChart"))) 12 13test2="["+test[test.find('チーム'):test.find(',\t\t]);\n\n\t\tvar')].replace("\'","").replace("\n\t\t\t","").replace("\t\t","").replace(" ","").replace("[]","")

スクレイピングの部分ももっとスマートなやり方があれば教えて頂きたいです。。
どうぞ宜しくお願い致します。

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

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

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

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

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

guest

回答1

0

ベストアンサー

リスト部の文字列を正規表現で抜き出して eval() 又は ast.literal_eval() にてリスト化するとよいかと思います。

Python

1from pprint import pprint 2import requests 3import re 4import ast 5 6from bs4 import BeautifulSoup,Comment 7 8url = "http://www.football-lab.jp/summary/team_ranking/j1/?year=2018&data=goal" 9 10response = requests.get(url) 11bs = BeautifulSoup(response.content,"lxml") 12test=str(bs.find(string=re.compile("function drawChart"))) 13 14tbl = re.search(r'arrayToDataTable((.*?))', test, flags=re.DOTALL|re.MULTILINE).group(1) 15pprint(ast.literal_eval(tbl)) 16#[['チーム', 17# 'PK', 18# 'セットプレー直接', 19# 'セットプレーから', 20# 'クロスから', 21# 'スルーパスから', 22# 'ショートパスから', 23# 'ロングパスから', 24# 'ドリブルから', 25# 'こぼれ球から', 26# 'その他'], 27# ['広島', 2, 0, 6, 4, 0, 3, 0, 3, 4, 0], 28# ['FC東京', 3, 0, 3, 4, 2, 4, 1, 1, 2, 1], 29# ['札幌', 0, 0, 5, 8, 1, 2, 1, 1, 1, 1], 30# ['神戸', 0, 1, 4, 2, 2, 3, 0, 2, 4, 1], 31# ['清水', 2, 0, 5, 3, 0, 6, 0, 1, 1, 1], 32# ['川崎F', 0, 0, 5, 5, 1, 3, 1, 1, 0, 3], 33# ['長崎', 1, 0, 4, 7, 3, 0, 0, 1, 2, 1], 34# ['横浜FM', 1, 2, 4, 3, 0, 4, 0, 3, 1, 0], 35# ['C大阪', 1, 3, 4, 0, 1, 1, 1, 3, 1, 3], 36# ['柏', 0, 0, 1, 4, 1, 2, 0, 4, 2, 2], 37# ['湘南', 1, 0, 4, 3, 1, 0, 1, 1, 1, 4], 38# ['磐田', 1, 0, 3, 4, 0, 4, 0, 1, 1, 1], 39# ['仙台', 1, 0, 3, 0, 0, 2, 1, 3, 2, 3], 40# ['鳥栖', 3, 0, 3, 1, 0, 5, 0, 0, 0, 2], 41# ['G大阪', 2, 0, 2, 2, 1, 5, 0, 2, 0, 0], 42# ['名古屋', 1, 0, 5, 2, 1, 1, 0, 0, 1, 1], 43# ['浦和', 1, 0, 4, 4, 0, 0, 0, 1, 2, 0], 44# ['鹿島', 2, 1, 1, 2, 2, 1, 0, 0, 2, 0]]

投稿2018/05/18 00:00

magichan

総合スコア15898

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

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

mana40

2018/05/20 15:45

ご回答ありがとうございます! 教えて頂いた内容で意図通りの結果を得られました。 こんなやり方があるとは全く知りませんでした。 宜しければ教えて頂きたいのですが、 1)正規表現で表している「r'arrayToDataTable((.*?))」の意図としては、  「arrayToDataTable((」と「))」を満たす最小の文字列を返させるという事でしょうか?   2)group(1)を外して実行すると該当データの1行目の途中までという結果となったのですが、  このgroup(1)の働きはどのようなものなのでしょうか? 3)「ast」モジュールを今回初めて知ったのですが、公式ドキュメントではその働き・使い方がいまいちよくわかりませんでした。。  参考になるページなどがありましたら教えていただけないでしょうか? 以上、重ねての質問で恐縮ですが、教えて頂けると幸いです。
magichan

2018/05/20 23:54

1.) 2) まず、正規表現 r'arrayToDataTable(.*?)' はおっしゃる通り、 "arrayToDataTable(...)"に最短マッチさせることが目的となるのですが、今回処理で必要となるのはこの中の "..." の部分のみとなります。 そこで正規表現を r'arrayToDataTable((.*?))' のように必用となる部分をさらに括弧で囲います。(これをグループ化といいます) このように検索条件の一部を括弧をつかってグループ化しておくことで、検索結果から re.search(...).group(1) としてそのグループを取得することができます。 (グループが複数ある場合は 引数の数字にて引き当てるグループを選択します)
magichan

2018/05/20 23:55

3) まずは eval() を理解するとよいかと思います。 これは文字列をPython式として評価するための組み込み関数で、例えば >>> s = "1 + 2" >>> eval(s) 3 のように文字列の数式を計算することができるという非常にパワフルな関数で、今回のように単なる文字列をリストとして評価するのに有効に機能します。 しかし残念ながら、外部から取り込んだ文字列を eval() に入力するのは非常に危険が伴います。例えば >>> s = "__import__('os').system('rm -rf *')" >>> eval(s) のように悪意のあるユーザが作成したスクリプトを eval() によって実行されてしまう可能性がある為です。 そこで今回の ast.literal_eval() を使用します。 ast.literal_eval()は評価する対象がタプルやタプル、辞書などに限定されており上記のようなスクリプトを実行することが出来ないため安全に文字列→リスト変換を安全に行うことができます。
mana40

2018/05/22 15:27

追加のご回答ありがとうございます。 自分で考えていた時にも「arrayToDataTable」の後の部分から抽出したいと考えたのですが、このような方法があるのですね。 また、eval/list_evalの用法も理解できました。 とても分かり易いご回答を頂きありがとうございました。大変勉強になりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問