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

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

詳細はこちら
Beautiful Soup

Beautiful Soupは、Pythonのライブラリの一つ。スクレイピングに特化しています。HTMLデータの構文の解析を行うために、HTMLタグ/CSSのセレクタで抽出する部分を指定することが可能です。

Python

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

selenium

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

Q&A

解決済

2回答

632閲覧

seleniumで新聞のpagenationのある記事をスクレイピングしたい

Joes

総合スコア18

Beautiful Soup

Beautiful Soupは、Pythonのライブラリの一つ。スクレイピングに特化しています。HTMLデータの構文の解析を行うために、HTMLタグ/CSSのセレクタで抽出する部分を指定することが可能です。

Python

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

selenium

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

0グッド

1クリップ

投稿2019/09/16 02:44

Seleniumを使用して新聞記事のpagenationのある箇所をクリックして
続きを取得したいと考えています。

例えば、この新聞の社説の場合、
https://www.yomiuri.co.jp/editorial/

"さらに読み込む"という箇所があり、そこを何度もクリックして記事を閲覧するのですが
これをseleniumで実行してスクレイピングしたいと考えています。
下記のようなコードを考えていましたが、クリック出来ません。

from selenium import webdriver from selenium.webdriver.chrome.options import Options import time import chromedriver_binary from bs4 import BeautifulSoup import re import urllib.request import urllib3 urllib3.disable_warnings() import requests chrome_options = Options() chrome_options.add_argument("--headless") driver = webdriver.Chrome( executable_path='drivers/chromedriver', options=chrome_options) driver.get('https://www.yomiuri.co.jp/editorial/') while True: try: driver.find_element_by_class_name('c-more-btn').find_element_by_link_text("さらに読み込む").click() time.sleep(3) soup = BeautifulSoup(requests.get(driver.current_url).content,'html.parser') for a in soup.find_all(class_="uni-news-editorial-jp"): for b in a.find_all("a"): #見出しとリンク print(b.text, b.get("href")) except: driver.close() driver.close()

質問
・続きを読む、のクリックの仕方をご教授いただきたいです。
・このウェブサイトはクリックしてもURLが変化しません。その場合でも、forループで次々にクリックして
新たに出現した見出しとリンクをスクレイピングすることは可能なのでしょうか。

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

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

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

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

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

guest

回答2

0

ベストアンサー

こんな感じでいかがでしょうか。

python

1from selenium.common.exceptions import NoSuchElementException 2 3while True: 4 5 try: 6 # さらに読み込むをクリック 7 driver.find_element_by_id('ajax_more_button').click() 8 9 # もしくは以下でもクリックできますが、except処理をJSのエラーに変える必要があります 10 # driver.execute_script('document.getElementById(\'ajax_more_button\').click()') 11 12 except NoSuchElementException: 13 # さらに読み込むボタンがない、つまりすべてのページを読み切った 14 15 # ここでBS4処理を行う 16 17 # 終了処理 18 driver.quit() 19 exit() 20 21 time.sleep(3) 22 23 # 画面サイズを最大まで拡大 24 driver.execute_script('scrollTo(1282, document.body.scrollHeight)')

ちなみにこちらはページを最下部までスクロールさせると
自動で次のDOMが読み込まれるタイプの時の解です。
ご参考までに

コメント受けて追記

ではこんな感じでいかがでしょうか。

python

1 2driver.get('https://www.yomiuri.co.jp/editorial/') 3 4# POPが出そうな時間まで待つ 5time.sleep(10) 6 7# 左下のPOPが出ていたら取り除く 8try: 9 driver.execute_script('document.getElementById(\'yolyp_popup\').remove()') 10except Exception: 11 pass 12 13# 画面下のPOPが出ていたら取り除く 14try: 15 driver.execute_script('document.getElementById(\'js-footer-global-guide\').remove()') 16except Exception: 17 pass 18 19for _ in range(5): 20 21 # 画面サイズを最大まで拡大 22 driver.execute_script('scrollTo(1282, document.body.scrollHeight)') 23 24 # さらに読み込むをクリック 25 driver.execute_script('document.getElementById(\'ajax_more_button\').click()') 26 27 # 3秒待機 28 time.sleep(3) 29 30for li_tag in driver.find_elements_by_class_name('p-list-item'): 31 a_tag = li_tag.find_element_by_tag_name('a') 32 print(a_tag.text, a_tag.get_attribute('href')) 33 34# 終了処理 35driver.quit() 36exit()

5回読み込んだら終了、かつ、DOMをbsではなく直接Seleniumで取得してみました。

さらに追記

まさにその通りですね。その配下にaタグは存在しないのでNoSuchElementExceptionが起きてます。
for文だけ変えてみましょう。

python

1from selenium.common.exceptions import NoSuchElementException 2 3for li_tag in driver.find_elements_by_class_name('p-list-item'): 4 try: 5 a_tag = li_tag.find_element_by_tag_name('a') 6 print(a_tag.text, a_tag.get_attribute('href')) 7 except NoSuchElementException: 8 pass

投稿2019/09/16 02:59

編集2019/10/01 00:27
shirai

総合スコア1290

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

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

Joes

2019/09/18 21:31

回答ありがとうございます。教えていただいた方法を試しましたが下記のようなエラーになってしまい 原因がよく分かりません。ウィンドウサイズが原因かと考えていますが解決方法が分かりませんでした。 WebDriverException: Message: unknown error: Element <a href="javascript:void(0)" id="ajax_more_button">...</a> is not clickable at point (372, 19). Other element would receive the click: <ul class="p-header-global-category-nav__list">...</ul> (Session info: headless chrome=76.0.3809.132) (Driver info: chromedriver=2.38.552518 (183d19265345f54ce39cbb94cf81ba5f15905011),platform=Mac OS X 10.14.6 x86_64)
shirai

2019/09/20 16:12

tryの直前にprint(1)などと打ってみてください。 while文が何回回った時にこのエラーが出ていますか?
Joes

2019/09/23 17:18

1回または2回です。 driver.find_element_by_id('ajax_more_button').click() は実行できるときと出来ないときがあり、実行出来ても2回目でエラーになり前回の私のコメントと同じメセージが表示されます。 こちらの記事を参考にして https://tanuhack.com/python/selenium/ 下記のように書いたところエラーはでなくなりました。 element = driver.find_element_by_id('ajax_more_button') driver.execute_script("arguments[0].click();", element) しかし、このクリックを実行してbs4でニュース記事を取得しても、クリックしていないときと 同じ内容でした。while文でもtryの箇所がずっとループしていて、取り出せていません。 tryの中でbs4を書いてもクリックして得られるはずの、記事が取得出来ていませんでした。 引き続き原因を考えたいと思います。 [bs4の箇所] soup = BeautifulSoup(requests.get(driver.current_url).content,'html.parser') for a in soup.find_all(class_="uni-news-editorial-jp"): for b in a.find_all("a"): if b.text == "記事へ": pass else: print(b.text, b.get("href"))
shirai

2019/09/24 16:48

追記しました
Joes

2019/10/01 19:04 編集

ご丁寧に対応いただきありがとうございます。 最初の12個のニュース項目は取得できましたが、最初に表示されたページの項目を取得できないままエラーが出てしまいました。 ニュース項目の空欄にあった <li class="p-list-item p-ad-list-item">のせいかなと考えています。 NoSuchElementException Traceback (most recent call last) <ipython-input-21-646f850d058a> in <module> 28 29 for li_tag in driver.find_elements_by_class_name('p-list-item'): ---> 30 a_tag = li_tag.find_element_by_tag_name('a') 31 print(a_tag.text, a_tag.get_attribute('href')) 32 ~/anaconda3/lib/python3.6/site-packages/selenium/webdriver/remote/webelement.py in find_element_by_tag_name(self, name) 303 element = element.find_element_by_tag_name('h1') 304 """ --> 305 return self.find_element(by=By.TAG_NAME, value=name) 306 307 def find_elements_by_tag_name(self, name): ~/anaconda3/lib/python3.6/site-packages/selenium/webdriver/remote/webelement.py in find_element(self, by, value) 657 658 return self._execute(Command.FIND_CHILD_ELEMENT, --> 659 {"using": by, "value": value})['value'] 660 661 def find_elements(self, by=By.ID, value=None): ~/anaconda3/lib/python3.6/site-packages/selenium/webdriver/remote/webelement.py in _execute(self, command, params) 631 params = {} 632 params['id'] = self._id --> 633 return self._parent.execute(command, params) 634 635 def find_element(self, by=By.ID, value=None): ~/anaconda3/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py in execute(self, driver_command, params) 319 response = self.command_executor.execute(driver_command, params) 320 if response: --> 321 self.error_handler.check_response(response) 322 response['value'] = self._unwrap_value( 323 response.get('value', None)) ~/anaconda3/lib/python3.6/site-packages/selenium/webdriver/remote/errorhandler.py in check_response(self, response) 240 alert_text = value['alert'].get('text') 241 raise exception_class(message, screen, stacktrace, alert_text) --> 242 raise exception_class(message, screen, stacktrace) 243 244 def _value_or_default(self, obj, key, default): NoSuchElementException: Message: no such element: Unable to locate element: {"method":"tag name","selector":"a"} (Session info: headless chrome=77.0.3865.90) (Driver info: chromedriver=2.38.552518 (183d19265345f54ce39cbb94cf81ba5f15905011),platform=Mac OS X 10.14.6 x86_64)
shirai

2019/10/01 00:28

さらに追記しました。
Joes

2019/10/04 04:52

大変勉強になりました。教えていただきありがとうございました。
guest

0

最終的なコードがどのようになっているのかわかりませんが、ボタンクリック後に適度にwaitをすると良いのではないでしょうか。

python3

1def wait_classes(drv, sec, selector, base): 2 3 def checker(selector, base): 4 elem = drv.find_elements(By.CSS_SELECTOR, selector) 5 if not elem : 6 return False 7 8 print("found elem: ", len(elem)) 9 if base < len(elem): 10 return elem 11 return False 12 13 try: 14 elem = WebDriverWait(drv, sec).until( 15 lambda _: checker(selector, base) 16 ) 17 return elem 18 except TimeoutException: 19 print(f"wait timeout.. {selector} not found") 20 return None 21 22litem_cls = '#latest_list li.p-list-item' 23litem = wait_classes(driver, 30, litem_cls, 0) 24num = len(litem) 25print('num: ', num) 26 27element = driver.find_element_by_id('ajax_more_button') 28driver.execute_script("arguments[0].click();", element) 29 30litem = wait_classes(driver, 30, litem_cls, num) 31num = len(litem) 32print('num: ', num)

投稿2019/09/30 03:53

t_obara

総合スコア5488

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

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

Joes

2019/10/04 17:21

回答ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問