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

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

新規登録して質問してみよう
ただいま回答率
85.31%
Python 3.x

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

Q&A

1回答

533閲覧

Pythonでスクレイピングする際に、データをもれなく正確に取得したい。

Kazuhiro-ch

総合スコア85

Python 3.x

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

0グッド

0クリップ

投稿2023/05/06 13:02

実現したいこと

スクレイピングの際に、データをもれなく正確に取得したいです。
ご教授よろしくお願いいたします。

前提

1ページあたり320ほどのデータがあります。現在のコードでは、プログラム動作直後は問題なく動きますが、すこしづつ処理に遅れが生じます。最終的に出来上がったデータフレームは当然漏れだらけという状況です。これを正確にきちんと取得したいです。
サイトについてですが、スクレイピングは許可されており、極力負荷をかけないようにしています。

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

エラーは特に発現していない。

該当のソースコード

python

1from selenium import webdriver 2from selenium.webdriver.chrome.service import Service 3from selenium.webdriver.chrome.options import Options 4from selenium.webdriver.common.keys import Keys 5from selenium.webdriver.common.by import By 6from selenium.webdriver.support.ui import WebDriverWait 7from selenium.webdriver.support import expected_conditions as EC 8 9import time 10import warnings 11 12warnings.simplefilter('ignore', FutureWarning) 13 14#Optionsで画像非読込などの設定 15options = Options() 16options.add_argument('--disable-extensions') 17options.add_argument('--blink-settings=imagesEnabled=false') 18service = Service('C:/Users/detec/pg/chromedriver.exe') 19driver = webdriver.Chrome(service=service, options=options) 20wait = WebDriverWait(driver,60) 21 22#webdriver起動 23TARGET_URL = "#" 24driver.get(TARGET_URL) 25time.sleep(4) 26 27# create an empty DataFrame 28df = pd.DataFrame(columns=['A, 'B', 'C', 'D']) 29 30 31while True: 32 #A,B,C,Dの値を取得するまで待機する 33 wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.#A'))) 34 wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.#B'))) 35 wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.#C'))) 36 wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.#D'))) 37 38 #A,B,C,Dの値を見つけて、変数として格納する 39 A = driver.find_elements(By.CSS_SELECTOR, '.#A') 40 B = driver.find_elements(By.CSS_SELECTOR, '.#B') 41 C = driver.find_elements(By.CSS_SELECTOR, '.#C') 42 D = driver.find_elements(By.CSS_SELECTOR, '.#D') 43 44 # Next Pageのボタンを探して、次のページへ。もしdisableならbreak 45 next_button = driver.find_element(By.CLASS_NAME, 'pagination-next') 46 driver.execute_script("arguments[0].scrollIntoView();", next_button) 47 if next_button.get_attribute('disabled') == 'true': 48 break 49 50 next_url = next_button.get_attribute('href') 51 driver.get(next_url) 52 time.sleep(3) 53

試したこと

  • time.sleep(n)の挿入。nの部分は0.5~10まで変更させました。また、スリープの場所はある程度試し済みです。
  • time.sleep(n)を使わず、wait.untilに置き換えました。前者ではアクセス負荷をかけないためには使えるが、取得などを待つことはできないということで置き換えました。
  • ChatGPTを使って、細かい部分の変更は調整しましたが、解決できていません。

補足情報(FW/ツールのバージョンなど)

Python 3.9

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

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

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

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

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

otn

2023/05/06 13:27

「1ページあたり320ほどのデータ」というのは、どういう風に取得していますか? #A #B 相当が実は4個じゃなくてが320個あると言うことでしょうか?
Kazuhiro-ch

2023/05/06 13:32

コメントありがとうございます。 取得してるデータはA~Bの4つなのですが、その塊が40個~80個あるということです。 ECサイトをイメージしていただければと思いますが、商品が横に4つ並んでいて、その中に価格などのデータがあります。さらにそれが20行~あるというような感じです。
meg_

2023/05/06 14:18

> すこしづつ処理に遅れが生じます。 上記はどういうことでしょうか?”遅れ”とはseleniumの動作が重くなる?ということでしょうか?(メモリの問題?) > 最終的に出来上がったデータフレームは当然漏れだらけという状況です。 すみませんが何が”当然”なのか説明いただけますでしょうか?サイトの情報更新速度がとても速いのでしょうか??
otn

2023/05/06 14:33

失礼しました。#が目立ったので、てっきりidかと思ったのですが、よく見るとピリオドがあるので、クラスでしたね。
otn

2023/05/06 14:36

データを取得し始めてから取得し終わるまでに、ページが更新されているとかですかね。 wait.untilが全部終わった時点と、次ページに遷移する直前のそれぞれで、 page_souceを取得して比べてみるとかでしょうか。 それが原因だとすると、ページ更新状況を把握しながらデータを取得しないといけなさそうです。 もしくは検索条件で時間指定が出来れば、ちょっと前までのデータだけ見るとか。
Kazuhiro-ch

2023/05/06 15:00

print(data)やprint(len(df))で出力したデータや数字を比較すると明らかに少ない数が表示されます。 その後、CSV出力などをしてもデータ数が少ないため、漏れがあると考えられます。 動作が重くなるというよりは、データを取得する処理もしくはdfに格納する処理が遅れていると思います。 「当然」という言葉を使ったのは、処理が遅れておりprintされるデータが少ないため、最終的に取得できるデータも当然少ないという意味で使っておりましたが、わかりづらく表現してしまい申し訳ありません。
Kazuhiro-ch

2023/05/06 15:23

page_sourceをしてみたところ、かなり容量が重いようで読み込みに時間がかかってしまっているのかもしれません。
meg_

2023/05/06 15:40

漏れているというか、単純に欲しい要素が取得できていないという可能性は無いのでしょうか?
Kazuhiro-ch

2023/05/06 15:45

調べてみたところ、HTMLファイルが大きいのでmeg_様のおっしゃる通り取得できていないという可能性が高そうです。
otn

2023/05/06 15:54

ループのそれぞれの回で、それぞれ2つのpage_souceは全部一致したのでしょうか、一致しなかった回があったのでしょうか?まだ調査中ですか?
Kazuhiro-ch

2023/05/06 16:18

すいません。HTMLファイルが大きく、Jupiterではさばききれないみたいです、、、
otn

2023/05/06 18:36

> HTMLファイルが大きく、Jupiterではさばききれないみたいです、、、 もしかして、画面に表示して、目検で比較しようとしていた??目検では無理では? コードを書くために回答にに書きます。
meg_

2023/05/07 03:21 編集

> 1ページあたり320ほどのデータがあります。 上記はスクレイピングで取得した情報から得た数値でしょうか?(目視の情報と合っているかの確認です)
Kazuhiro-ch

2023/05/07 05:24

いえ、ウェブサイトを訪問し、目視で確認した情報です。 そしてスクレイピングで取得した情報から得た数値はおよそその80%(1ページ目)でした。 処理が進むにつれて、その数値の%は減っていきます。
meg_

2023/05/07 05:31

> スクレイピングで取得した情報から得た数値はおよそその80%(1ページ目)でした。 1ページ目で既に欠損が発生しているのですね。 そのページをローカルに保存してスクレイピングした場合は欲しいデータを全て取得出来ますか?
Kazuhiro-ch

2023/05/07 05:54

ダウンロードするとデータがきちんと表示されないみたいです。 「ご指定のページが見つかりませんでした」となります。
guest

回答1

0

追記

すいません。昨夜寝ぼけてたのか、「idで検索している」という誤解からの脱却が不十分でした。

wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.#A')))

は、そのクラスの要素が存在すればwaitは完了しますので、320個の要素がJavaScriptで順次追加されているのだとすると、「1つでも存在すれば」で待つのは不十分です。
「情報を取得している最中にどんどんページが書き換わる」よりはこちらが原因としてありそうです。

何らかの手段で、ページが全部更新終わったことを確認する必要があります。
先ほど取得した、初めの頃のHTMLと、終わりの方のHTMLを比較すれば何か見つかるかも。
個数がわかればその個数そろうまで待てば良い等。
確認手段が見つからないようなら、最悪、十分な時間待つとかですね。30秒とか1分とか。

ここから最初のアドバイス

HTMLファイルが大きく、Jupiterではさばききれないみたいです、、、

もしかして、画面に表示して、目で見て比較しようとしていましたか?目検で比較は無理では?
コード例を示します。(実行したわけじゃ無いのでタイプミスなどあれば直して下さい)

Python

1loop_count = 0 ###追加 2while True: 3 loop_count += 1 ###追加 4 #A,B,C,Dの値を取得するまで待機する 5 wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.#A'))) 6 wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.#B'))) 7 wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.#C'))) 8 wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.#D'))) 9 source1 = driver.page_source ###追加 10 11 #A,B,C,Dの値を見つけて、変数として格納する 12 A = driver.find_elements(By.CSS_SELECTOR, '.#A') 13 B = driver.find_elements(By.CSS_SELECTOR, '.#B') 14 C = driver.find_elements(By.CSS_SELECTOR, '.#C') 15 D = driver.find_elements(By.CSS_SELECTOR, '.#D') 16 17 # Next Pageのボタンを探して、次のページへ。もしdisableならbreak 18 next_button = driver.find_element(By.CLASS_NAME, 'pagination-next') 19 driver.execute_script("arguments[0].scrollIntoView();", next_button) 20 if next_button.get_attribute('disabled') == 'true': 21 break 22 23 next_url = next_button.get_attribute('href') 24 source2 = driver.page_source ###追加 25 if source1 != source2: ###追加 26 print(f"{loop_count}回目の繰り返しで、最初と最後でHTMLが異なる") ###追加 27 with open(f"source1-{loop_count}.html","w") as f: ###追加 28 f.write(source1) ###追加 29 with open(f"source2-{loop_count}.html","w") as f: ###追加 30 f.write(source2) ###追加 31 else: ###追加 32 print(f"{loop_count}回目の繰り返しで、最初と最後でHTMLが同じ") ###追加 33 driver.get(next_url) 34 time.sleep(3)

最初と最後で不一致ならファイルに書くので、後で中を比較します。

投稿2023/05/06 18:51

編集2023/05/07 11:31
otn

総合スコア86293

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

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

Kazuhiro-ch

2023/05/07 05:49

1回目の繰り返しで、最初と最後でHTMLが異なる 2回目の繰り返しで、最初と最後でHTMLが異なる 3回目の繰り返しで、最初と最後でHTMLが異なる 4回目の繰り返しで、最初と最後でHTMLが同じ 5回目の繰り返しで、最初と最後でHTMLが異なる 6回目の繰り返しで、最初と最後でHTMLが同じ 7回目の繰り返しで、最初と最後でHTMLが同じ 8回目の繰り返しで、最初と最後でHTMLが同じ 9回目の繰り返しで、最初と最後でHTMLが同じ 10回目の繰り返しで、最初と最後でHTMLが同じ 11回目の繰り返しで、最初と最後でHTMLが同じ 12回目の繰り返しで、最初と最後でHTMLが同じ 13回目の繰り返しで、最初と最後でHTMLが同じ 14回目の繰り返しで、最初と最後でHTMLが同じ 15回目の繰り返しで、最初と最後でHTMLが同じ 16回目の繰り返しで、最初と最後でHTMLが同じ 17回目の繰り返しで、最初と最後でHTMLが同じ 18回目の繰り返しで、最初と最後でHTMLが同じ 19回目の繰り返しで、最初と最後でHTMLが同じ 20回目の繰り返しで、最初と最後でHTMLが同じ 21回目の繰り返しで、最初と最後でHTMLが同じ 22回目の繰り返しで、最初と最後でHTMLが同じ ... というような結果になりました。
Kazuhiro-ch

2023/05/07 14:47

始めのget_urlで60秒、next_urlで10秒待機したところ、1回目の繰り返しで、最初と最後でHTMLが同じ以降すべ手同じになりました。ただ、ではその通り実際に待機して動かしてみても、取得できた件数は40行分の35行でした。
otn

2023/05/07 15:03

時間待ちで行くなら、全件取得できるまで、思い切り待って見るのでしょうね。 不一致HTMLの前後比較の差分はどうだったのでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問