PythonとSeleniumを使用した最新のWebスクレイピング

公開: 2022-03-11

Webスクレイピングは、World Wide Webが誕生したほぼ時から、Webサイトからデータを抽出するために使用されてきました。 初期の頃は、スクレイピングは主に静的ページ(既知の要素、タグ、データを含むページ)で行われていました。

ただし、最近では、Web開発の高度なテクノロジーにより、タスクが少し難しくなっています。 この記事では、新しいテクノロジーやその他の要因によって標準のスクレイピングが妨げられた場合に、データをスクレイピングする方法について説明します。

従来のデータスクレイピング

ほとんどのWebサイトは、自動読み取りではなく人間が読みやすいようにページを作成するため、Webスクレイピングは主に、Webページのマークアップデータをプログラムでダイジェストし(右クリックしてソースを表示)、プログラムを許可するデータの静的パターンを検出することで構成されていました。さまざまな情報を「読み取り」、ファイルまたはデータベースに保存します。

データスクレイピング

レポートデータが見つかった場合、多くの場合、フォーム変数またはパラメータのいずれかをURLとともに渡すことでデータにアクセスできます。 例えば:

 https://www.myreportdata.com?month=12&year=2004&clientid=24823

Pythonは、そのために作成されたさまざまなWebライブラリのおかげで、最も人気のあるWebスクレイピング言語の1つになりました。 人気のあるライブラリの1つであるBeautifulSoupは、タグ(つまり、解析ツリー)の検索、ナビゲート、および変更を可能にすることにより、HTMLおよびXMLファイルからデータを引き出すように設計されています。

ブラウザベースのスクレイピング

最近、私はかなり簡単に思えるスクレイピングプロジェクトを持っていて、それを処理するために従来のスクレイピングを使用する準備ができていました。 しかし、さらに深く掘り下げていくと、従来の方法では克服できない障害が見つかりました。

3つの主な問題により、標準的なスクレイピング方法ができませんでした。

  1. 証明書。 Webサイトのデータがあった部分にアクセスするには、証明書をインストールする必要がありました。 最初のページにアクセスすると、コンピュータにインストールされているものの適切な証明書を選択するように求めるプロンプトが表示され、[OK]をクリックします。
  2. Iframe。 このサイトではiframeを使用していたため、通常のスクレイピングが台無しになりました。 はい、すべてのiframe URLを見つけてサイトマップを作成することはできましたが、扱いにくいように思われました。
  3. JavaScript。 フォームにパラメータ(顧客ID、日付範囲など)を入力した後、データにアクセスしました。 通常、私はフォームをバイパスし、フォーム変数を(URLを介して、または非表示のフォーム変数として)結果ページに渡し、結果を確認します。 ただし、この場合、フォームにはJavaScriptが含まれているため、通常の方法でフォーム変数にアクセスすることはできませんでした。

そこで、従来の方法をやめて、ブラウザベースのスクレイピングに使用できるツールを検討することにしました。 これは通常とは異なる動作をします。ページに直接移動して解析ツリーをダウンロードし、データ要素を引き出す代わりに、「人間のように振る舞い」、ブラウザを使用して必要なページにアクセスし、スクレイピングします。データ-したがって、前述の障壁に対処する必要性を回避します。

セレン

一般に、SeleniumはWebアプリケーションのオープンソーステストフレームワークとしてよく知られており、QAスペシャリストが自動テストを実行し、再生を実行し、リモートコントロール機能を実装できるようにします(負荷テスト用の多くのブラウザーインスタンスと複数のブラウザータイプを許可します)。 私の場合、これは役に立つように思えました。

私がWebスクレイピングに使用する言語はPythonです。これは、必要なすべての機能を一般的に処理できる、十分に統合されたライブラリを備えているためです。 そして確かに、Python用のSeleniumライブラリが存在します。 これにより、「ブラウザ」(Chrome、Firefox、IEなど)をインスタンス化して、自分でブラウザを使用して探しているデータにアクセスしているふりをすることができます。 また、ブラウザを実際に表示したくない場合は、ブラウザを「ヘッドレス」モードで作成して、どのユーザーにも表示されないようにすることができます。

プロジェクトの設定

実験を開始するには、プロジェクトを設定し、必要なものをすべて入手する必要がありました。 私はWindows10マシンを使用し、比較的更新されたPythonバージョン(v。3.7.3)を使用していることを確認しました。 空白のPythonスクリプトを作成し、ライブラリをまだロードしていない場合は、PIP(Pythonのパッケージインストーラー)を使用して、必要と思われるライブラリをロードしました。 これらは私が始めた主なライブラリです:

  1. リクエスト(HTTPリクエストを行うため)
  2. URLLib3(URL処理)
  3. 美しいスープ(セレンがすべてを処理できなかった場合)
  4. Selenium(ブラウザベースのナビゲーション用)

また、(argparseライブラリを使用して)スクリプトにいくつかの呼び出しパラメーターを追加して、さまざまなデータセットを試して、さまざまなオプションを使用してコマンドラインからスクリプトを呼び出すことができるようにしました。 それらには、顧客ID、from-month / year、およびto-month/yearが含まれていました。

問題1-証明書

私が最初に選択する必要があったのは、Seleniumに使用するように指示するブラウザーでした。 私は通常Chromeを使用しており、オープンソースのChromiumプロジェクト(Edge、Opera、Amazon Silkブラウザーでも使用されています)に基づいて構築されているため、最初に試してみることにしました。

必要なライブラリコンポーネントを追加し、いくつかの簡単なコマンドを発行することで、スクリプトでChromeを起動できました。

 # Load selenium components from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait, Select from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException # Establish chrome driver and go to report site URL url = "https://reportdata.mytestsite.com/transactionSearch.jsp" driver = webdriver.Chrome() driver.get(url)

ヘッドレスモードでブラウザを起動しなかったので、実際にブラウザが表示され、何をしているのかがわかりました。 すぐに証明書(以前にインストールしたもの)を選択するように求められました。

取り組むべき最初の問題は証明書でした。 ウェブサイトにアクセスするために適切なものを選択して受け入れるにはどうすればよいですか? スクリプトの最初のテストで、次のプロンプトが表示されました。

データスクレイピング

これは良くありませんでした。 スクリプトを実行するたびに手動で[OK]ボタンをクリックしたくありませんでした。

結局のところ、プログラミングなしで、この回避策を見つけることができました。 Chromeに起動時に証明書名を渡す機能があることを期待していましたが、その機能は存在しませんでした。 ただし、Windowsレジストリに特定のエントリが存在する場合、Chromeには証明書を自動選択する機能があります。 最初に表示される証明書を選択するように設定することも、より具体的に設定することもできます。 証明書を1つだけロードしたので、汎用形式を使用しました。

データスクレイピング

したがって、そのセットでは、SeleniumにChromeを起動するように指示し、証明書プロンプトが表示されたときに、Chromeは証明書を「自動選択」して続行します。

問題2–Iframe

さて、今私はサイトにいて、フォームが表示され、顧客IDとレポートの日付範囲を入力するように求められました。

データスクレイピング

開発ツール(F12)でフォームを調べると、フォームがiframe内に表示されていることがわかりました。 そのため、フォームへの入力を開始する前に、フォームが存在する適切なiframeに「切り替える」必要がありました。 これを行うために、次のようにSeleniumの切り替え機能を呼び出しました。

 # Switch to iframe where form is frame_ref = driver.find_elements_by_tag_name("iframe")[0] iframe = driver.switch_to.frame(frame_ref)

これで、適切なフレームで、コンポーネントを特定し、顧客IDフィールドに入力して、日付のドロップダウンを選択することができました。

 # Find the Customer ID field and populate it element = driver.find_element_by_name("custId") element.send_keys(custId) # send a test id # Find and select the date drop-downs select = Select(driver.find_element_by_name("fromMonth")) select.select_by_visible_text(from_month) select = Select(driver.find_element_by_name("fromYear")) select.select_by_visible_text(from_year) select = Select(driver.find_element_by_name("toMonth")) select.select_by_visible_text(to_month) select = Select(driver.find_element_by_name("toYear")) select.select_by_visible_text(to_year)

問題3– JavaScript

フォームに残っているのは、[検索]ボタンを「クリック」することだけだったので、検索が開始されます。 [検索]ボタンはJavaScriptによって制御されているようで、通常の[送信]タイプのボタンではなかったため、これは少し注意が必要でした。 開発者ツールで調べたところ、ボタンの画像が見つかり、右クリックしてXPathを取得できました。

データスクレイピング

次に、この情報を用意して、ページ上の要素を見つけてクリックしました。

 # Find the 'Find' button, then click it driver.find_element_by_xpath("/html/body/table/tbody/tr[2]/td[1]/table[3]/tbody/tr[2]/td[2]/input").click()

そして出来上がり、フォームが送信され、データが表示されました! これで、結果ページのすべてのデータをスクレイプして、必要に応じて保存することができました。 または私はできますか?

データの取得

まず、検索で何も見つからなかった場合に対処する必要がありました。 それはかなり簡単でした。 検索フォームに「レコードが見つかりません」のようなメッセージを残さずに表示します。 その文字列を検索し、見つかったらそこで停止しました。

ただし、結果が得られた場合は、トランザクションを開き、そのすべての詳細を表示するために、データがプラス記号(+)付きのdivで表示されました。 開かれたトランザクションはマイナス記号(-)を示し、クリックするとdivが閉じます。 プラス記号をクリックすると、URLが呼び出され、そのdivが開き、開いているdivが閉じられます。

データスクレイピング

したがって、ページ上でプラス記号を見つけ、それぞれの横にあるURLを収集してから、それぞれをループして、すべてのトランザクションのすべてのデータを取得する必要がありました。

 # Loop through transactions and count links = driver.find_elements_by_tag_name('a') link_urls = [link.get_attribute('href') for link in links] thisCount = 0 isFirst = 1 for url in link_urls: if (url.find("GetXas.do?processId") >= 0): # URL to link to transactions if isFirst == 1: # already expanded + isFirst = 0 else: driver.get(url) # collapsed +, so expand # Find closest element to URL element with correct class to get tran type tran_type=driver.find_element_by_xpath("//*[contains(@href,'/retail/transaction/results/GetXas.do?processId=-1')]/following::td[@class='txt_75b_lmnw_T1R10B1']").text # Get transaction status status = driver.find_element_by_class_name('txt_70b_lmnw_t1r10b1').text # Add to count if transaction found if (tran_type in ['Move In','Move Out','Switch']) and (status == "Complete"): thisCount += 1

上記のコードでは、取得したフィールドはトランザクションタイプとステータスであり、カウントに追加されて、指定されたルールに適合するトランザクションの数が決定されました。 ただし、日付と時刻、サブタイプなど、トランザクションの詳細内の他のフィールドを取得することもできます。

このプロジェクトでは、カウントは呼び出し元のアプリケーションに戻されました。 ただし、それと他のスクレイピングされたデータは、フラットファイルまたはデータベースに保存されている可能性もあります。

その他の考えられる障害と解決策

独自のブラウザインスタンスで最新のWebサイトをスクレイピングすると、他にも多くの障害が発生する可能性がありますが、ほとんどは解決できます。 ここにいくつかあります:

  • 表示される前に何かを見つけようとしています

    自分自身を閲覧しているときに、ページが表示されるのを、時には何秒も待っていることに気付く頻度はどれくらいですか。 プログラムでナビゲートしているときにも同じことが起こります。 あなたはクラスまたは他の要素を探します-そしてそれはそこにありません!

    幸い、Seleniumには特定の要素が表示されるまで待機する機能があり、次のように要素が表示されない場合はタイムアウトする可能性があります。

 element = WebDriverWait(driver, 10). until(EC.presence_of_element_located((By.ID, "theFirstLabel")))


  • キャプチャを通過する

    一部のサイトでは、不要なロボット(あなたと見なされる可能性があります)を防ぐためにキャプチャなどを採用しています。 これにより、ウェブスクレイピングにダンパーがかかり、速度が低下する可能性があります。

単純なプロンプト(「2 + 3とは何ですか?」など)の場合、これらは通常、簡単に読み取って理解できます。 ただし、より高度なバリアについては、それを破るのに役立つライブラリがあります。 例としては、2Captcha、Death by Captcha、BypassCaptchaなどがあります。

  • ウェブサイトの構造変更

    ウェブサイトは変化することを意図しています–そして彼らはしばしば変化します。 そのため、スクレイピングスクリプトを作成するときは、このことを念頭に置いておくのが最善です。 データを見つけるためにどのメソッドを使用し、どのメソッドを使用しないかを検討する必要があります。 フレーズ全体を照合するのではなく、部分的な照合手法を検討してください。 たとえば、Webサイトでメッセージが「レコードが見つかりません」から「レコードが見つかりません」に変更される場合がありますが、一致するものが「レコードなし」の場合は問題ありません。 また、XPATH、ID、名前、リンクテキスト、タグまたはクラス名、またはCSSセレクターで一致するかどうかを検討してください。どちらが変更される可能性が最も低いかを検討してください。

概要:PythonとSelenium

これは、使用されているテクノロジーや複雑さに関係なく、ほとんどすべてのWebサイトをスクレイピングできることを示す簡単なデモンストレーションでした。 基本的に、自分でサイトを閲覧できれば、一般的にはスクレイプすることができます。

さて、警告として、それはすべてのウェブサイトが削られるべきであるという意味ではありません。 いくつかは合法的な制限があり、特定のサイトをスクレイピングすることの合法性を決定する多くの訴訟がありました。 一方、一部のサイトは、自社のWebサイトからデータを取得することを歓迎および奨励しており、場合によっては、作業を容易にするAPIを提供しています。

いずれにせよ、プロジェクトを開始する前に利用規約を確認することをお勧めします。 しかし、先に進む場合は、仕事を成し遂げることができるので安心してください。

複雑なWebスクレイピングの推奨リソース:

  • 高度なPythonWebスクレイピング:ベストプラクティスと回避策
  • スケーラブルな日曜大工のスクレイピング:大規模なスクレイパーを構築して実行する方法