【Python特化】おすすめのオンラインプログラミングスクール

【Python】ページ遷移型のクローリング&スクレイピング方法

‎python-crawling-and-scraping

ランサーズ等のクラウドソーシングサイトでよく見かけるスクレイピング案件があります。

スクレイピング案件と言っても、膨大なサイト数であるため、適宜対象サイトに沿ったスクレイピングプログラムを作成する必要があります。

本記事では、以下の内容を徹底解説します。

本記事のまとめ
  • クローリングとスクレイピングの違い
  • スクレイピング対象になるサイト例
  • クローリングプログラム
  • スクレイピングプログラム
筆者の経歴
  • SIer/Web系企業での実務経験があるフリーランスエンジニア
  • プログラミングスクールでの講師実績あり
  • HR領域によるエンジニア特化の採用代行を業務委託で兼務
目次

クローリングとスクレイピングの違い

クローリングとは、対象サイトの各ページを巡回することを指します。

いわゆるページ遷移型のスクレイピングプログラムは、クローリングプログラムが作成できるかが重要になります。

また、クローリングプログラムを作成するためには、静的・動的ページサイトのHTML構造を理解する必要があります。

スクレイピングとは、対象ページ内のデータを取得・抽出することを指します。

クローリングプログラムによって各ページの表示結果から企業や店舗の詳細ページURLを取得することで、各URLにアクセスしスクレイピングを実施する必要があります。

そのため、ページ遷移型のスクレイピングプログラムを作成したい場合、クローリングとセットになることを意識しましょう。

ページ遷移型のスクレイピング対象になるサイトとは

ページ遷移は、対象サイトが静的ページと動的ページのどちらにおいても実施する可能性があります。

そのため、静的ページと動的ページの特徴を捉えておくと、プログラムに反映させやすいです。

ページの種類ページごとの特徴
静的ページ・一度読み込めばHTML内の情報が取得できる
・URLの認識がしやすい(扱いやすい)
動的ページ・特定のアクションしないと読み込めないデータがある
・URLの認識がしにくい(扱いにくい)
各ページの特徴

具体的なデータパターンとサイト例は以下になります。

データパターンサイト例
企業データマイナビ・リクナビ等の就職/転職サイト
施設・店舗データGoogleマップ、ホットペッパービューティ、食べログなど
個人のアカウントデータSNSサイト
営業リストが作成しやすいサイト例

やはり大手のポータルサイト・総合サイトは、詳細情報が記載されているページを各種設けており、HTML構造としてもテーブルデータで持たせているケースが多いです。

そのため、有名な情報サイトのスクレイピングプログラムを作成しておけば、大概のリストを収集することが可能になります。

静的ページと動的ページの違い

静的ページは、Webサーバーで用意されたHTMLファイルを読み込み、ブラウザ側で表示されます。

一方で、動的ページはリクエストの度にHTMLファイルを再生成します。

そのため、Webスクレイピングの観点から動的ページより静的ページが処理しやすいです。

なぜなら、リクエストに応じて変化する動的ページは、スクレイピング処理だけでなく、ブラウザ操作もプログラムする必要があるためです。

より詳しく動的ページのスクレイピングコード等を確認したい人は、「【Python】SeleniumによるGoogleマップのスクレイピング」を一読ください。

静的ページ遷移型のおすすめライブラリ

ライブラリ名静的/動的メリット/デメリット
requests静的ページに有効・URLがあれば静的ページに活用しやすい
・件数が多くても収集速度が良い
・ブラウザ操作はできない
BeautifulSoup静的ページに有効・HTML解析(パース)に利用される
・HTML要素から属性値を利用してデータを特定できる
ライブラリ表

requestsはブラウザ操作ができない分、Seleniumに比べると収集速度は速いです。

例えば、URLの中ですでにページ番号が記載されていると、ページ用変数を用意しfor文で回すだけで一気にデータ収集が可能になります。

動的ページ遷移型のおすすめライブラリ

ライブラリ名静的/動的メリット/デメリット
Selenium動的ページに有効・静的/動的に限らず様々なページに活用できる
・ブラウザ操作が含まれるため、時間を要する
ライブラリ表

最近では、静的ページであってもURL内にページ番号を表示せず秘匿にするサイトも増えています。

スクレイピング対策の一つではありますが、URLのみでページ遷移が不可能な場合はSeleniumによるクローリングにて詳細ページURLを大量に取得します。

各詳細ページのリストデータが作成できたらrequests&BeautifulsoupにてHTML解析後スクレイピングで目的のデータを収集といった流れがよいです。

ログイン型のスクレイピング対象になるサイトとは

対象サイトによっては、セッションなしのログイン処理によりセッション切れが発生するケースがあります。

理由は、対象サイト側でこちらが予期していないセキュリティ対策を講じている可能性があります。

考えられるセキュリティ対策の例
  • ユーザーエージェントの問題
  • ログイン画面の表示時点でCookie発行して整合性が取れない
  • トークン情報の付与が求められる

上記のようなケースでログイン処理が実行できない、あるいはセッション切れが発生する場合にセッションインスタンスを作成し、ログイン画面をGETしてCookieやトークン情報を得ておく必要があるでしょう。

.session()メソッドを利用したログイン処理の記述方法を知りたい人は、「【Python】requestsとは?インストールから使い方まで徹底解説!」を一読ください。

requestsのメソッドの使い方

ここでは、特にクローリング後に取得した各URLに対して利用するrequestsについて解説します。

requestsでは、以下の4つが代表的なメソッドになります。

メソッド名説明
requests.get()サーバーから情報を取得
requests.post()サーバーへ情報を送信
requests.put()サーバーの情報を更新
requests.delete()サーバーの情報を削除
requestsの代表的なメソッド

本記事では、企業ごとのURLに対してWebスクレイピングを利用するため、.get()メソッドを重点的に解説します。

requests.get()の引数の使い方

Webスクレイピングといったデータ収集などで頻繁に利用されるのがrequests.get()になります。

res = requests.get(URL, 任意の引数)

.get()メソッドを利用することで直感的に操作することができます。

また、以下が主な引数になります。

メソッド名必須/任意説明
URL必須対象URL
headers任意リクエスト時にヘッダーデータを辞書で指定
params任意リクエスト時にURLのクエリパラメータを辞書で指定
cookies任意リクエスト時にクッキーを辞書で指定
timeout任意リクエスト時のタイムアウトを指定
.get()メソッドの引数

スクレイピング業務では、引数にURLのみを利用することが多いです。

requests.get()によるresponseオブジェクトの確認

リクエスト後の戻り値(応答)として、responseオブジェクトが返ってきます。

以下がresponseオブジェクトの属性値になります。

属性説明
status_codeステータスコード
headersレスポンスヘッダーのデータ
contentレスポンスのバイナリデータ
textレスポンスのテキストデータ
encodingエンコーディング(変換方式:utf-8など)
cookiesクッキーデータ
responseオブジェクトの戻り値

ここでは、responseオブジェクトのtext属性データのみを利用したスクレイピングプログラムになります。

requestsライブラリをさらに理解したい人は、「【Python】requestsとは?インストールから使い方まで徹底解説!」を一読ください。

BeautifulSoupの代表的なメソッドの使い方

HTMLデータを解析した後、指定した箇所のデータを抽出する必要があります

本記事では、スクレイピングの際に利用するBeautifulSoupの代表的なメソッドを記載します。

タイプ1要素だけ返す全要素をリストで返す引数(検索条件指定)
find系find()find_all()要素名, 属性指定(キーワード引数)
select系select_one()select()CSSセレクタ
BeautifulSoupの代表的なメソッド

機能はどちらも同じですが、引数の違いによって探し出すアプローチ方法が異なります

ただし、HTMLデータによってはクラス/idに対して属性値を持たないデータがあるため、その場合はselect系を利用しましょう。

BeautifulSoupをさらに理解したい人は、「【Python】 BeautifulSoup4とは?インストールから使い方まで徹底解説!」を一読ください。

Seleniumのメソッドの使い方

代表的なSeleniumのメソッドは以下の4つです。

メソッド名説明
.get()対象URLを指定しアクセス/データ取得するメソッド
.find_element_by_〇〇(“”)Selenium3にて利用されるfind系メソッド
.find_element(By.〇〇, “xx”)Selenium4にて利用されるfind系メソッド
.send_keys()対象にデータ送信するメソッド
.click()対象をEnterするメソッド
Seleniumの代表的なメソッド

本記事では、ブラウザ操作に利用するため、上記メソッドを重点的に解説します。

Seleniumにおける各メソッドの使い方を詳細に知りたい人は、「【Python】 Seleniumとは?インストールから使い方まで徹底解説!」を一読ください。

特定サイトをページ遷移するクローリング方法

ここでは、マイナビを例に実践します。

プログラム実行までの手順と結果
  • 必要な各種ライブラリをインポート
  • 出力フォルダとCSVファイルを作成
  • Seleniumの設定
  • マイナビへアクセス
  • マイナビにて企業詳細URLを取得
  • Webdriverを閉じる
import os
import csv
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
import time
from datetime import datetime as dt
import traceback

# キーワード入力
search_word = input("業種キーワード=")

# 作成日のフォルダとファイル作成
today = dt.now()
folder_name = today.strftime('%Y-%m-%d')
os.makedirs(folder_name, exist_ok=True)

# CSVファイル生成
csv_file_path = os.path.join(folder_name, f'{search_word}.csv')
with open(csv_file_path, 'w', newline='', encoding='utf8') as csv_file:
    csv_writer = csv.writer(csv_file)
    csv_writer.writerow(['会社名', '住所', '電話番号'])

# Chromedriverの設定
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(r"path/to/driver", options=options)

# マイナビ
url = f'https://job.mynavi.jp/24/pc/corpinfo/searchCorpListByGenCond/index?actionMode=searchFw&srchWord={search_word}&q={search_word}&SC=corp'
driver.get(url)

# 企業詳細URL格納リスト
company_urls = []

# 企業の詳細URLの取得
while True:
    company_list = WebDriverWait(driver, 10).until(EC.visibility_of_all_elements_located((By.CLASS_NAME, 'boxSearchresultEach')))
    company_urls.extend([company.find_element_by_tag_name("a").get_attribute("href") for company in company_list])

    try:
        next_page = driver.find_element_by_xpath('//*[@id="lowerNextPage"]')
        next_page.click()
        time.sleep(3)
    except:
        traceback.print_exc()
        break

driver.close()

特定サイトにおける各ページURLのデータスクレイピング方法

プログラム実行までの手順と結果
  • クローリングして取得した各詳細URLにアクセス
  • 各詳細ページにてデータをスクレイピング
  • 実行結果
for url in company_urls:
    response = requests.get(url)
    soup = BeautifulSoup(response.text, "html.parser")

    try:
        name = soup.select_one("#companyHead > div.heading1 > div > div > div.heading1-inner-left > h1").text
        address = soup.select_one("#corpDescDtoListDescTitle50").text
        number = soup.select_one("#corpDescDtoListDescText220").text
        with open(csv_file_path, 'a', newline='', encoding='utf8') as csv_file:
            csv_writer = csv.writer(csv_file)
            csv_writer.writerow([name, address, number])

    except:
        print("next")
全体コード
import os
import csv
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
import time
from datetime import datetime as dt
import traceback

# キーワード入力
search_word = input("業種キーワード=")

# 作成日のフォルダとファイル作成
today = dt.now()
folder_name = today.strftime('%Y-%m-%d')
os.makedirs(folder_name, exist_ok=True)

# CSVファイル生成
csv_file_path = os.path.join(folder_name, f'{search_word}.csv')
with open(csv_file_path, 'w', newline='', encoding='utf8') as csv_file:
    csv_writer = csv.writer(csv_file)
    csv_writer.writerow(['会社名', '住所', '電話番号'])

# Chromedriverの設定
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(r"path/to/driver", options=options)

# マイナビ
url = f'https://job.mynavi.jp/24/pc/corpinfo/searchCorpListByGenCond/index?actionMode=searchFw&srchWord={search_word}&q={search_word}&SC=corp'
driver.get(url)

# 企業詳細URL格納リスト
company_urls = []

# 企業の詳細URLの取得
while True:
    company_list = WebDriverWait(driver, 10).until(EC.visibility_of_all_elements_located((By.CLASS_NAME, 'boxSearchresultEach')))
    company_urls.extend([company.find_element_by_tag_name("a").get_attribute("href") for company in company_list])

    try:
        next_page = driver.find_element_by_xpath('//*[@id="lowerNextPage"]')
        next_page.click()
        time.sleep(3)
    except:
        traceback.print_exc()
        break

driver.close()

for url in company_urls:
    response = requests.get(url)
    soup = BeautifulSoup(response.text, "html.parser")

    try:
        name = soup.select_one("#companyHead > div.heading1 > div > div > div.heading1-inner-left > h1").text
        address = soup.select_one("#corpDescDtoListDescTitle50").text
        number = soup.select_one("#corpDescDtoListDescText220").text
        with open(csv_file_path, 'a', newline='', encoding='utf8') as csv_file:
            csv_writer = csv.writer(csv_file)
            csv_writer.writerow([name, address, number])

    except:
        print("next")
実行結果

メールアドレスや別項目データも取得できる形が目指せるため、企業リスト案件ではマイナビを利用できると助かるケースが多いです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

sugiのアバター sugi SUGI

【経歴】玉川大学工学部卒業→新卒SIer企業入社→2年半後に独立→プログラミングスクール運営/受託案件→フリーランスエンジニア&SEOコンサル→Python特化のコンテンツサイトJob Code運営中

コメント

コメント一覧 (1件)

コメントする

目次