🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
スクレイピング

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

Python

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

selenium

Selenium(セレニウム)は、ブラウザをプログラムで作動させるフレームワークです。この原理を使うことにより、ブラウザのユーザーテストなどを自動化にすることができます。

Q&A

解決済

2回答

6745閲覧

whileを使ってボタンをクリックし続け、ボタンが無くなったら処理をやめたい

yudai109

総合スコア18

スクレイピング

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

Python

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

selenium

Selenium(セレニウム)は、ブラウザをプログラムで作動させるフレームワークです。この原理を使うことにより、ブラウザのユーザーテストなどを自動化にすることができます。

0グッド

3クリップ

投稿2019/11/28 14:31

前提・実現したいこと

https://itp.ne.jp/topic/?topic=225%3B772&sort=01&sbmap=false
こちらのサイトで「さらに表示する」を表示されるだけクリックして、全てクリック仕切ったら次の処理に進みたいです。

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

Traceback (most recent call last): File "itown.py", line 21, in <module> while driver.find_element_by_class_name("m-read-more"): File "/Users/yudai/opt/anaconda3/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 564, in find_element_by_class_name return self.find_element(by=By.CLASS_NAME, value=name) File "/Users/yudai/opt/anaconda3/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 978, in find_element 'value': value})['value'] File "/Users/yudai/opt/anaconda3/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute self.error_handler.check_response(response) File "/Users/yudai/opt/anaconda3/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response raise exception_class(message, screen, stacktrace) selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":".m-read-more"} (Session info: chrome=78.0.3904.108)

該当のソースコード

python

1# itown メールアドレス スクレイピング 完成ばん 2from bs4 import BeautifulSoup 3from selenium import webdriver 4import requests 5import time 6import csv 7import re 8from selenium.common.exceptions import NoSuchElementException 9 10 11url_list = [] 12hpurl_list = [] 13adress_list = [] 14url = "https://itp.ne.jp/genre/?area=27&genre=4&subgenre=1028&sort=01&sbmap=false" 15 16# 「さらに表示」をクリックしまくる。 17driver = webdriver.Chrome(executable_path='chromedriver') 18driver.get(url) 19 20 21while driver.find_element_by_class_name("m-read-more"): 22 show_btn = driver.find_element_by_class_name("m-read-more") 23 show_btn.click() 24 # js実行までいっとき待つ。余裕を持って1ページ4秒の計算。 25 time.sleep(3) 26 27# ブラウザのHTMLを読み込む。 28res = driver.page_source 29soup = BeautifulSoup(res, "html.parser") 30 31for i in soup.find_all("a", class_='m-article-card__header__title__link'): 32 elem = i.get("href") + "shop/" 33 # url_listに格納 34 url_list.append(elem) 35 36 37driver = webdriver.Chrome(executable_path='chromedriver') 38for m in url_list: 39 driver.get(m) 40 res = requests.get(m) 41 res.raise_for_status() 42 time.sleep(1) 43 soup = BeautifulSoup(res.text, "html.parser") 44 45 # 企業名ゲット 46 try: 47 y = driver.find_element_by_css_selector("body > div.container > div > div > div > div.main > div > article.item.item-table > div > section.item-body.basic > dl:nth-child(1) > dd") 48 except NoSuchElementException: 49 adress_list.append("None") 50 else: 51 title = y.text 52 # 配列に格納 53 adress_list.append(title) 54 55 # 会社HPのURLゲット 56 try: 57 z = driver.find_element_by_xpath("/html/body/div[3]/div/div/div/div[1]/div/article[1]/div/section[1]/dl[9]/dd/div[1]/p[2]/a") 58 except NoSuchElementException: 59 adress_list.append("None") 60 else: 61 hp_url = z.get_attribute("href") 62 # 配列に格納 63 adress_list.append(hp_url) 64 65 # アドレスゲット 66 if soup.find_all('a', text=re.compile('@')): 67 for p in soup.find_all('a', text=re.compile('@')): 68 adress = p.text 69 # 配列に格納 70 adress_list.append(adress) 71 else: 72 adress_list.append('None') 73 74# 3列のcsv作成 75with open('itown_name_hp_ad.csv', 'w', newline='')as f: 76 w = csv.writer(f, quotechar='"', quoting=csv.QUOTE_MINIMAL) 77 for i in range(0, len(adress_list), 3): 78 w.writerow(adress_list[i:i+3]) 79

試したこと

while driver.find_element_by_class_name("m-read-more"):
show_btn = driver.find_element_by_class_name("m-read-more")
show_btn.click()
time.sleep(3)

の部分で、driver.find_element_by_class_name("m-read-more")によっての戻り値がなくなった時、なぜ次の処理に行かないのかわかりません。
falseではなく、Noneが戻り値として返ってきているのでしょうか?

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

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

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

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

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

guest

回答2

0

ベストアンサー

本題と全然それますが、4点ほどおせっかいさせてください。


2回目のdriver = webdriver.Chrome(executable_path='chromedriver')の宣言の直前と
プログラムの最終行にdriver.quit()を入れてあげてください。
今のままだと実行の度メモリにガベージがたまります。


一覧にサムネイルが合ったり、遷移先のGUIの違いから察するに、
このページの上の方はiタウンにお金を払って掲載している美容室が並び、
下の方にはお金を払わずに簡易な情報だけを掲載している美容室が並んでいます。
あなたのプログラムを見る限り有料掲載の情報のみ
取得したいようなので、無料掲載店舗の項目まで来たら
終了にするといいでしょう。
これは全店舗一覧ページのサムネイルの有り無しで判断できそうです。


Selenium、BeautifulSoup、requestと煩雑に使いすぎています。
後から見直したときに分かりやすいように、
出来る限り簡素にまとめてあげてください。
そんなに規模の大きなプログラムではないので
Seleniumだけあればまず事足ります。


値を丸ごとリストに格納していますが、
HPやメールアドレスが掲載されていないお店は
穴抜けができるので不自然です。
pythonにはこういう時の為に辞書型が用意されているので
利用してください。2重に辞書を使う形が適切だと思います。

python

1driver.get(url) 2 3# 全て開く 4while True: 5 try: 6 show_btn = driver.find_element_by_class_name("m-read-more") 7 show_btn.click() 8 time.sleep(3) 9 10 # 現状一番最後に並んでいる店舗にサムネイルが無かったら終了 11 if len(driver.find_elements_by_class_name('o-result-article-list__item')[-1].find_elements_by_tag_name('img')) == 0: 12 break 13 14 # これ以上読み込めなくても終了 15 except NoSuchElementException: 16 break 17 18# 店名と個別ページの辞書を取得 19shops_url = {} 20for li_tag in driver.find_elements_by_class_name('o-result-article-list__item'): 21 22 # サムネの無い店舗まで来たら取得終了 23 if len(li_tag.find_elements_by_tag_name('img')) == 0: 24 break 25 26 # 情報が入った要素を取得 27 a_tag = li_tag.find_element_by_class_name('m-article-card__header__title__link') 28 29 # 辞書に店舗名とurlを格納 30 shop_url[a_tag.text] = a_tag.get_attribute('href') + 'shop/' 31 32 33# この時点でshops_urlには 34# {'ビューティサロンマリ':'https://itp.ne.jp/info/277391709081780640/shop/', 'サロン・ド・シーマ':'https://itp.ne.jp/info/275752231114381200/shop/', ...}という形で格納されている 35 36# 空の辞書を宣言 37shops_info = {} 38 39# 各遷移先について情報を取得しに行く 40for shop_name, shop_url in shops_url.items(): 41 42 # 空の辞書を宣言 43 shop_info = {} 44 45 # 遷移 46 driver.get(shop_url) 47 48 # HPを取得 49 try: 50 hp_address = driver.find_element_by_xpath('//a[contains(text(), "http")]').text 51 except NoSuchElementException: 52 hp_address = '' 53 54 # メールアドレスを取得 55 try: 56 mail_address = driver.find_element_by_xpath('//a[contains(text(), "@")]').text 57 except NoSuchElementException: 58 mail_address = '' 59 60 # HPとメールアドレスを辞書に格納 61 shop_info['HP'] = hp_address 62 shop_info['メルアド'] = mail_address 63 64 # 全ての情報を大元の辞書に格納 65 shops_info[shop_name] = shop_info 66 67# driverを終了 68driver.quit() 69 70# 以下csv書き込み処理 71# shops_infoには{'ビューティサロンマリ':{'HP':'https://itp.ne.jp/info/277391709081780640/', 'メルアド':''}, 'サロン・ド・シーマ':{'HP':'http://www.seema.cc/index.html', 'メルアド':'seema514@zeus.eonet.ne.jp'}, ...}という形で格納されている

ちゃんとテストしていないので間違いがあったらすみません。

投稿2019/11/29 07:11

shirai

総合スコア1290

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

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

yudai109

2019/11/29 11:20

ご回答ありがとうございます! 頂いたアドバイスとガベージなどを調べてさらに理解が深まりました。 完全にプログラミング勉強を始めて1か月、『動けばいい』の思考であり、コードレビューを受けることもなかったので、すべてのアドバイスがとても新鮮でした! また、わかりやすくコメントで解説して頂き本当にありがとうございます! とても分かり易かったです!! 誰かが見たときやパソコンの負担や、カードの煩雑さに配慮したコードを書いていけるよう学んでいきます! これからもこの場で質問させて頂く機会も増えるかと思います。 今後ともよろしくお願い致します!!
guest

0

driver.find_element_by_class_name()などの要素を探すメソッドは、要素が見つからなかったらNoneを返すのではなく、エラーを出します。

以下のようにすると良いでしょう。

python

1from selenium.common.exceptions import NoSuchElementException 2 3try: 4 while driver.find_element_by_class_name("m-read-more"): 5 show_btn = driver.find_element_by_class_name("m-read-more") 6 show_btn.click() 7 # js実行までいっとき待つ。余裕を持って1ページ4秒の計算。 8 time.sleep(3) 9except NoSuchElementException: 10 pass

ちなみにNoneのbool値はFalseです

python

1bool(None) 2# False

投稿2019/11/28 15:08

ChaosRepainter

総合スコア108

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

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

yudai109

2019/11/29 11:11

こちらでも解決できました! ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問