目的
- ICLR2019 OpenReview に上がってる論文の一覧情報を取得し,表形式で管理をしたい
結果
- 全論文情報を含む html を取得し,取得した html から論文の下記情報を取得した.(本記事は htmlの取得まで)
- title
- date
- keyword
- abstract
- tldr
課題
ページのhtmlを beautiful soup を用いてスクレイピングすればよいが,下記課題が存在
- ICRL2019 OpenReview ページは動的コンテンツになっておりスクロールしないとコンテンツが表示されない
- ボタンをクリックしないと abstract が表示されない
-> Selenium を用いてchrome を操作し,全てのコンテンツが表示された状態のhtmlを取得すれば良い
解決手順
- selenium を通じてchromeを操作し,コンテンツを全て表示するまでスクロール
- 全て表示したら,各論文の show detailsボタンを順次クリックすることで abstractを表示させる
- ページのソースを取得し,beautiful soup を通じて論文の情報を取得する
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
CHROME_PATH = 'path/to/chromedriver'
def get_all_source(url):
# 全てのソースを取得する関数
browser = webdriver.Chrome(CHROME_PATH)
browser.get(url) # 指定した url をクロームで開く
scroll_down(browser) # 全てのコンテンツが表示されるまで下にスクロールを行う
toggle_all(browser) # 各論文の show details ボタンをクリックし,abstract を表示させる
source = browser.page_source # 全てのコンテンツ情報が表示された状態のページの html を取得
browser.close()
time.sleep(0.3)
return source
全てのコンテンツが表示されるまで下にスクロール
- コンテンツは有限なので,全てのコンテンツが表示されるまで下にスクロールを続ける
def scroll_down(browser):
prev_source = None
for i in range(0, 1000):
if i == 0:
time.sleep(1)
browser.execute_script('window.scrollBy(0,2000)', '') # ページを下へスクロール
scroll_count += 1
time.sleep(0.3)
print ('Scroll: {}'.format(scroll_count))
if scroll_count % 10 ==0:
if browser.page_source == prev_source: # スクロールしてもページの情報が変わらなければ終了
break
prev_source = browser.page_source
return
各論文の Show details ボタンをクリックして abstract を表示させる
- クリックをさせる際には,クリック対象が画面に表示されていなければならない
- 表示されていない状態でクリックさせようとすると element is not visible エラー
- クリック対象の位置まで画面遷移 & is_displayed() メソッドで表示されていることを確認して対処
- is_displayed()==True でもクリックできない場合が存在
- クリック対象の上に何かしらのオブジェクト等が存在する場合
- 今回は,ページ最上段のクリック対象まで移動してもクリック対象が chrome画面上部に隠れてしまっていてクリックできなかった
- ページ最上の位置までスクロールさせることで対処 Scrolling to top of the page in Python using Selenium
- Selenium: Element not clickable … Other Element Would Receive Click
- クリック対象の上に何かしらのオブジェクト等が存在する場合
def wait_for_element(element):
# クリック対象が画面に表示されているか確認,表示されていなければしばらく待つ関数
if element.is_displayed():
print(element.is_displayed())
return
else:
time.sleep(.1)
return wait_for_element(element)
def toggle_all(browser):
# 全てのShow details ボタンをクリックし,abstract を表示させる関数
# ページ最上部へ移動
browser.find_element_by_tag_name('body').send_keys(Keys.CONTROL + Keys.HOME)
time.sleep(3)
# 全ての Show details ボタンを取得 (note-contents-toggle 属性を持つオブジェクトが show details ボタンに対応することは 別途ソースから確認)
buttons = browser.find_elements_by_class_name('note-contents-toggle')
# 全てのボタンをクリック
for button in buttons:
# ボタンの位置まで画面を移動させる
webdriver.ActionChains(browser).move_to_element(button).perform()
# ボタンが画面に表示されていることを確認
wait_for_element(button)
print('---------------------')
time.sleep(0.2)
# ボタンをクリック
button.click()
def toggle_all(browser):
# 全てのShow details ボタンをクリックし,abstract を表示させる関数
# ページ最上部へ移動
browser.find_element_by_tag_name('body').send_keys(Keys.CONTROL + Keys.HOME)
time.sleep(3)
# 全ての Show details ボタンを取得 (note-contents-toggle 属性を持つオブジェクトが show details ボタンに対応することは 別途ソースから確認)
buttons = browser.find_elements_by_class_name('note-contents-toggle')
# 全てのボタンをクリック
for i, button in enumerate(buttons):
# ボタンの位置まで画面を移動させる
webdriver.ActionChains(browser).move_to_element(button).perform()
# ボタンが画面に表示されていることを確認
wait_for_element(button)
print(f'toggle {i}')
time.sleep(0.2)
# ボタンをクリック
button.click()
return
ソースまとめ
上記のコードまとめたソース
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
CHROME_PATH = 'path/to/chromedriver'
def wait_for_element(element):
if element.is_displayed():
print(element.is_displayed())
return
else:
time.sleep(.1)
return wait_for_element(element)
def toggle_all(browser):
browser.find_element_by_tag_name('body').send_keys(Keys.CONTROL + Keys.HOME)
time.sleep(3)
buttons = browser.find_elements_by_class_name('note-contents-toggle')
for i, button in enumerate(buttons):
webdriver.ActionChains(browser).move_to_element(button).perform()
wait_for_element(button)
print(f'toggle {i}')
time.sleep(0.1)
button.click()
return
def scroll_down(browser):
prev_source = None
for i in range(0, 1000):
if i == 0:
time.sleep(1)
browser.execute_script('window.scrollBy(0,2000)', '')
time.sleep(0.3)
print (f'Scroll: {i}')
if i % 10 ==0:
if browser.page_source == prev_source:
break
prev_source = browser.page_source
return
def get_all_source(url):
browser = webdriver.Chrome(CHROME_PATH)
browser.get(url)
scroll_down(browser)
toggle_all(browser)
source = browser.page_source
browser.close()
time.sleep(0.3)
return source