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

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

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

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

if

if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

Python

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

2回答

396閲覧

【Python】find_allで値を取得できない際の処理をしたいです。

umai29

総合スコア19

スクレイピング

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

if

if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

Python

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2019/06/20 16:40

編集2019/06/23 10:29

Python初心者です。

PythonにてWebスクレイピングをしておりまして、その結果をarr1・arr2に格納し、print関数で表示したいのですが、値が格納されていないため、以下のようなエラーが起こります。

IndexError: list index out of range

例えば、次のようなHTMLがあります。
(説明の便宜上、簡易的なものにしてあります。ご了承くださいませ。)

HTML

1http://hoge.co.jp 2<h3> 3 <a href="http://hoge.co.jp/2001">ダイエット方法</a> 4 <p class="profileName">太郎</p> 5 <a href="http://hoge.co.jp/2002">健康になるには</a> 6 <p class="profileName">次郎</p> 7 <a href="http://hoge.co.jp/2003">美容関連</a> 8 <p class="profileName">和郎</p> 9</h3> 10 11http://fuga.co.jp 12<h3> 13 <a href="http://fuga.co.jp/2001">金運上昇</a> 14 <p class="profileName">一郎</p> 15 <a href="http://fuga.co.jp/2002">健康運上昇</a> 16 <a href="http://fuga.co.jp/2003">恋愛運上昇</a> 17 <p class="profileName">三郎</p> 18</h3> 19 20http://piyo.co.jp 21<h3> 22 <a href="http://piyo.co.jp/2001">音楽</a> 23 <a href="http://piyo.co.jp/2002">美術</a> 24 <p class="profileName">健太</p> 25 <a href="http://piyo.co.jp/2003">書道</a> 26 <p class="profileName">康太</p> 27</h3>

これらをスクレイピングし、出力する結果を以下のようなものにしたいです。
1.  ダイエット方法  太郎
2.  健康になるには  次郎
3.  美容関連  和郎
1.  金運上昇  一郎
2.  健康運上昇  
3.  恋愛運上昇  三郎
1.  音楽  
2.  美術  健太
3.  書道  康太

名前がないものがありますが、それはそれで空白として出力するようにしたいのです。
以下のPythonのコードですと、エラーが起きてしまいます。

Python

1 2#URL 3url = ["http://hoge.co.jp", "http://fuga.co.jp", "http://piyo.co.jp"] 4 5#取得する値(配列) 6arr1 = [] 7arr2 = [] 8 9#URL番号 10n = 0 11 12while n < len(url): 13 c = 0 14 15 html = BeautifulSoup(requests.get(url[n]), "lxml") 16 for hoge in html.find_all("h3"): 17 for at in hoge.find_all("a"): 18 arr1[n].append(at.get_text()) 19 20 for fuga in html.find_all("p", class_="profileName"): 21 arr2[n].append(at.get_text()) 22 23 print(c+1, "\t", arr1[n][c], "\t", arr2[n][c]) 24 c += 1 25 26 n += 1 27

処理の中で、find_allで値を取得できなかったため、arr1またはarr2に値が空なのに、print関数で指定してしまっているために起こるエラーと思われるのですが、ループの途中でエラーが起きて処理が停まってしまうのを何とかしたいと思っています。

例えば、if文でarr1やarr2が空の場合、空白文字をappendする…のような処理ができればと思い、

https://qiita.com/yonedaco/items/d0f65ca3dad2e085a51d
↑こちらを参考にして、

上記のコードの、for文とprint関数の間に、以下のコードを追加してみましたが、こちらもダメでした。

Python

1if len(arr1)==0: 2 arr1.append("") 3 4if len(arr2)==0; 5 arr2.append("")

while文でURLの数だけループ(今回ですと3つなので3回)し、それぞれのURLのデータを取得し、配列arr1、arr2にそれぞれ要素を3つずつ格納させたいです。
上記HTMLでいうと、「健康運上昇」「音楽」のところで名前がありませんが、そのようにデータが取得できなかった場合も、空白として配列に格納するには、どのようにすればよろしいでしょうか。

調べてはいるのですが、なかなかできずに困っています。
詳しい方のご教示をお願い致します。

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

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

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

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

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

guest

回答2

0

こっちにも回答したけど
https://teratail.com/questions/196599

python

1from bs4 import BeautifulSoup 2 3html = """ 4<h3> 5 <a href="http://hoge.co.jp/2001">ダイエット方法</a> 6 <p class="profileName">太郎</p> 7 <a href="http://hoge.co.jp/2002">健康になるには</a> 8 <p class="profileName">次郎</p> 9 <a href="http://hoge.co.jp/2003">美容関連</a> 10 <p class="profileName">和郎</p> 11</h3> 12 13<h3> 14 <a href="http://fuga.co.jp/2001">金運上昇</a> 15 <p class="profileName">一郎</p> 16 <a href="http://fuga.co.jp/2002">健康運上昇</a> 17 <a href="http://fuga.co.jp/2003">恋愛運上昇</a> 18 <p class="profileName">三郎</p> 19</h3> 20 21<h3> 22 <a href="http://piyo.co.jp/2001">音楽</a> 23 <a href="http://piyo.co.jp/2002">美術</a> 24 <p class="profileName">健太</p> 25 <a href="http://piyo.co.jp/2003">書道</a> 26 <p class="profileName">康太</p> 27</h3> 28""" 29 30soup = BeautifulSoup(html, 'html.parser') 31 32for i in soup.find_all("a"): 33 34 result = [] 35 36 result.append(i.get_text()) 37 38 j = i.find_next() 39 40 if j: 41 if j.name == "p" and j.get("class") == ["profileName"]: 42 result.append(j.get_text()) 43 else: 44 result.append(None) 45 else: 46 result.append(None) 47 48 print(result)

結果

['ダイエット方法', '太郎']
['健康になるには', '次郎']
['美容関連', '和郎']
['金運上昇', '一郎']
['健康運上昇', None]
['恋愛運上昇', '三郎']
['音楽', None]
['美術', '健太']
['書道', '康太']

投稿2019/07/01 15:03

barobaro

総合スコア1286

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

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

0

コードは書いておられますが「得られたHTMLの構造に対してあなたが得たい出力」が書かれていません。それゆえ「実際にどのような論理にしたらよさそうか」閲覧者側に予測がつきにくいため回答しづらいと思います。

例えばurl[0]のHTMLの内容が以下のとき

html

1<h3><a>A11</a><a>A12</a><h3> 2<h3><a>A21</a></h3> 3<h4><a>B11</a></h4> 4<h4><a>B21</a><a>B22</a></h4>

あなたが得たい出力は以下のいずれでしょうか?

# (1) A11 B11 # (2) A11 B11 A12 B21 A21 B22 # (3) A11 B11 A12 A21 B21 B22

find_allを使っていることから(1)ではないように思えるのですが、コードを拝見しますとurl[0]に対する出力を1ペアしか要しないような論理になっています。ここで自分は「何がしたいかわからない」状態になりました。おそらく多くの閲覧者の方も同様に感じたのではないでしょうか?

せめて(2)あるいは(3)とすべきではないでしょうか?もしそうなら出力の際のarr1, arr2のインデックスはurlのインデックスとは何の関係もないことになります。それゆえそもそも
print(arr1[n], '\t', arr2[n])
のようにarr1, arr2のインデックスにnを用いていること自体がおかしいと思います。

もし(2)でよいとするとh3とh4の構造を無視した組をペアとして表示することになりますが本当にそれでよいのかどうか(どういう出力が望みなのかがわからない自分には)判断できません。想像をたくましくすれば(2)よりは(3)であることの方がありそうな気がします。

さて、このあたりで質問者さんが望む仕様を想像することは止めます。あやふやな推測をしたところでそれが質問者さんが望む回答になるかわからないからです。


アドバイス:

「望む結果を具体的に正確に示す」ようにしましょう。質問を編集し「こういうHTMLの場合、こういう結果を得たい」というように具体的に例示すること、および自分が上に挙げた(2),(3)の違いのように「得たい出力の仕様が相手に確実に伝わるような例を提示する」ことに留意してください。

多分そういうことを的確に説明するには「仕様を論理的に整理すること」が必要になります。またそれができれば質問前にご自分で戦略・戦術をもう少し先まで考えることもできましょう。
自分は「質問者さんの課題」が仕様の明確化が不十分なままコードを書き始めている点に思えるのです。


追記:質問編集を受けて。

なるほど。期待する仕様が大分わかるようになりましたが・・・自分が思うにHTMLが例示しておられる構造だとすると戦術に難ありだと思います。それは

aタグとpタグのそれぞれに対して別々にfind_allしてしまうとaとpの対応関係がわかりません。特定のaタグの次にpタグが挟まれているかどうかがわからないので例えば「健康運上昇」に対するpタグが存在しないことがわからないはずです。こうしたタグのペア関係は大抵の場合

html

1<h3> 2 <div><a>...</a><p>...</p></div> 3 <div><a>...</a><p>...</p></div> 4 ... 5</h3>

のようにaとpをグループ化するような上位のタグ(上の例ではdiv)があったりすると思うのですが・・・もしそれがあるならaやpをfind_allで探すのではなくdivをfind_allで列挙し、各々のdivの子供要素からa, pを探すべきだと思います。

python

1for h3 in html.find_all("h3"): 2 for div in h3.find_all("div"): 3 a = div.find("a") 4 p = div.find("p") 5 ...

もしご質問にあるようにh3タグの直下にaとpが無秩序に並ぶ構造ならfind_all("a")やfind_all("p")ではなく、h3タグの子要素を一つづつ列挙してその要素がaなのかpなのか(あるいはそれ以外なのか)といった論理を組まなければならないと思います。

投稿2019/06/20 18:07

編集2019/06/23 13:51
KSwordOfHaste

総合スコア18394

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

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

umai29

2019/06/23 10:32

ご回答ありがとうございます。 説明不足で大変恐縮でございます。 ご指摘のとおり、HTMLと望む出力結果を掲載し、説明文も追記致しました。 HTMLも実際のサイトのものよりもだいぶ簡略化してあるため、伝わるかどうか不安ではありますが…。 このような形でよろしいでしょうか。 よろしくお願い致します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問