Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
70
Help us understand the problem. What are the problem?
Organization

Selenium-Pythonでクローラーを作るときの雛形

私はデータ収集やブラウザ自動操縦による業務効率化を担当することが多く、セレニウムを利用したクローラーを何度も開発してきた。
どのような用途のクローラーであっても、htmlの取得やページ遷移などの基礎的な処理はほぼ共通していて、
ユーザーエージェントなどchromeオプションの設定は毎度変わるものではないため、
これらを雛形化してコピーしながら使い回すというのが開発効率をと動作の信頼性高める上で効果的だった。
本記事ではその雛形の一部をシェアしたい。

selenium雛形

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import WebDriverException
import time


class SeleniumCrawler:
    def __init__(self, *, sleep_time=1.0, headless=True):
        self.sleep_time = sleep_time

        ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36"
        options = Options()
        options.add_argument('--user-agent=#{ua}')
        options.add_argument('--window-size=1024,768')
        options.add_argument('--no-sandbox')
        options.add_argument('--disable-setuid-sandbox')
        options.add_argument('--disable-gpu')
        options.add_argument('--headless') if headless else None

        self.driver = webdriver.Chrome(options=options)

        # Sets the amount of time to wait for a page load to complete before throwing an error.
        self.driver.set_page_load_timeout(15)
        # Set the amount of time the driver should wait when searching for elements.
        self.driver.implicitly_wait(15)
        # Sets the amount of time to wait for an asynchronous script to finish execution before throwing an error.
        self.driver.set_script_timeout(15)

    def crawl(self, url):
        self.sleep_before_crawl()
        self.driver.get(url)

    def sleep_before_crawl(self):
        time.sleep(self.sleep_time)

    def get_title(self, url):
        self.crawl(url)
        return self.driver.title

    def get_html(self, url):
        self.crawl(url)
        return self.current_page_html()

    def current_page_html(self):
        html = self.driver.execute_script("return document.getElementsByTagName('html')[0].outerHTML")
        return html

    def send_value(self, css_selector, value):
        javascript_statement = f"""document.querySelector('{css_selector}').value = '{value}'"""
        self.driver.execute_script(javascript_statement)

    def query_click(self, css_selector):
        self.sleep_before_crawl()
        javascript_statement = f"""document.querySelector('{css_selector}').click()"""
        self.driver.execute_script(javascript_statement)

ポイントは
- sleep_before_crawlのようにページ遷移前のsleepは共通化しておく。(sleepを長くしたいという要求が後に起こる)
- crawlのようにページ遷移の処理を共通化している。(ページ遷移後にある処理を挟みたいという要求が後に起こる)
- send_valuequery_clickのように敢えてjs実行しているのは、クリックしたいボタンが別のオブジェクトで隠れている場合はseleniumのメソッドではクリックできないため。

新規クローラー

新規でクローラーを作成するときはこの雛形をクラスを継承して、都度メソッドを追加していくという方式で開発すると良い。

from selenium_crawler import *


class ExampleCrawler(SeleniumCrawler):
    def __init__(self, **args):
        super().__init__(**args)

    # def some_method(self):
    #     do something


url = "http://example.com/"
crawler = ExampleCrawler(sleep_time=2.0, headless=True)
html = crawler.get_html(url)
print(html)
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
70
Help us understand the problem. What are the problem?