本ページはプロモーションが含まれています。
Seleniumとheadless Chromeで書いたスクレイピングを、毎朝決まった時刻に動かしたい。けれど手元のPCはスリープするし、レンタルサーバーで動くのかも分からない。VPSは何GB必要なのかも見当がつかない。この記事では、Seleniumの毎日実行に条件を絞って3つの環境を比べます。比べるのは、エックスサーバー(共有)、さくらのVPS 1GBプラン、そして私がバッテリーを外した故障ノートPCで17本の定時ジョブを回している自宅サーバーです。止まる条件から逆算して、どれを1つ選ぶべきかを示します。
Selenium+headless Chromeを毎日動かす3環境の比較(2026年10月の料金)
最初に結論の材料を表にまとめます。料金は2026年10月時点の公表値です。キャンペーンは期間限定なので、契約前に各社の公式ページで確認してください。
項目 | エックスサーバー(共有) | さくらのVPS 1GB | 自宅の故障ノートPC |
|---|---|---|---|
月額 | スタンダード36ヶ月契約で990円(2026年10月5日〜11月4日のキャンペーンで693円から) | 807円から(リージョンで差あり) | サーバー代0円(電気代のみ) |
cron | 使える | 自由(root権限あり) | 自由(systemd timerも可) |
常駐プロセス | 原則不可 | 可 | 可 |
root権限 | なし | あり | あり |
Chromeの導入 | root無しで入れる必要があり、可否は要検証 | パッケージで入れられる | パッケージで入れられる |
主に止まる条件 | 共有資源の制限・Chromeが起動できない | メモリ不足・OS更新の放置 | 停電・タイマー消失・スリープ |
比較の前提にしている自宅サーバーの構成
- FUJITSUのノートPC(Celeron 3205U・メモリ4GB)に Xubuntu 24.04
- バッテリーは故障したので取り外し、ACアダプタ直結で稼働
- systemd の user timer で定時ジョブを17本運用(Seleniumを使う巡回もその中に含む)
VPSの1GB帯は他社とも比べておく
同じ1GB前後でも料金差があります。調査時点の公表値は次のとおりです。
- WebARENA Indigo 1GB:月額449円から(CPU 1Core・SSD 20GB)
- KAGOYA CLOUD VPS 1コア1GB:月額550円から(日額20円から)
- さくらのVPS 1GB:月額807円から
- XServer VPS 2GB:月額830円から(2026年9月8日に「XServer API」へ対応)
Chromeを使う場合は、料金よりも「メモリに余裕があるか」が効いてきます。そのため、次の節で自分のスクリプトの消費量を実測してから決めてください。
headless Chromeのメモリを実測するSeleniumの書き方
Chromeのメモリ消費は、ページの重さやタブの数、取得の手順によって大きく変わります。他人の数字を当てにせず、自分のスクリプトを測るのが確実です。ここでは「今の書き方」で起動しつつ、Chrome全体のメモリのピークを記録するコードを載せます。
実行環境
- Python 3(
python3 -Vで確認) pip install selenium psutil- Google Chrome または Chromium がOSに入っていること
Seleniumのバージョンは pip show selenium で確認できます。ドライバの自動解決(後述)に対応しているかは、公式ドキュメントの Selenium Manager の項を参照してください。
以前の書き方と今の書き方
以前は次の手順が定番でした。
webdriver_managerでchromedriverを落とす- そのパスを
executable_pathで渡す - headlessは
options.headless = Trueで指定する
今のSeleniumは同梱の Selenium Manager がドライバを自動で解決するので、パスの受け渡しは要りません。また executable_path 引数と options.headless は使えなくなっています。headlessの指定は、起動オプションとして渡します。
# 以前(今は動かない書き方)
# from webdriver_manager.chrome import ChromeDriverManager
# driver = webdriver.Chrome(executable_path=ChromeDriverManager().install())
# options.headless = True
# 今の書き方
import time
import threading
import urllib.robotparser
import psutil
from selenium import webdriver
from selenium.webdriver.common.by import By
TARGET = "https://example.com/list"
UA = "Mozilla/5.0 (compatible; my-crawler; +https://example.com/about)"
def allowed(url):
rp = urllib.robotparser.RobotFileParser()
rp.set_url("https://example.com/robots.txt")
rp.read()
return rp.can_fetch(UA, url)
def watch_memory(root_pid, peak, stop):
proc = psutil.Process(root_pid)
while not stop.is_set():
total = 0
for p in [proc] + proc.children(recursive=True):
try:
total += p.memory_info().rss
except psutil.NoSuchProcess:
pass
peak[0] = max(peak[0], total)
time.sleep(0.5)
def main():
if not allowed(TARGET):
print("robots.txt で拒否されているので取得しない")
return
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--window-size=1280,900")
options.add_argument(f"--user-agent={UA}")
driver = webdriver.Chrome(options=options)
peak, stop = [0], threading.Event()
t = threading.Thread(
target=watch_memory,
args=(driver.service.process.pid, peak, stop),
daemon=True,
)
t.start()
try:
driver.get(TARGET)
titles = [e.text for e in driver.find_elements(By.CSS_SELECTOR, "h2")]
print(len(titles), "件取得")
time.sleep(3) # 次のページへ進む場合はここで間隔を空ける
finally:
driver.quit()
stop.set()
t.join()
print(f"Chrome全体のピーク: {peak[0] / 1024 / 1024:.0f} MB")
if __name__ == "__main__":
main()ブロックごとの説明
allowed():robots.txtを読み、取得してよいURLかを確かめます。拒否されていればChromeを起動する前に終わります。watch_memory():chromedriverのプロセスを起点に、子孫プロセス(Chromeは描画・GPU・タブごとにプロセスを分けます)のメモリ使用量(RSS=実際に物理メモリ上にある量)を0.5秒ごとに合計し、最大値を残します。/usr/bin/time -vで測る方法もありますが、表示されるのはプロセス1個ぶんの最大値です。Chrome全体の合計にはなりません。
- ChromeOptions:
--headless=new:画面なしで起動します。--disable-dev-shm-usage:共有メモリ領域(/dev/shm)が小さい環境でChromeが落ちるのを避けます。
webdriver.Chrome(options=options):ドライバのパスを渡していません。Selenium Managerが解決します。try / finallyのdriver.quit():例外で落ちてもChromeを確実に終了させます。これを書き忘れると、毎日の実行ごとにChromeのプロセスが残ります。数日でメモリを食い尽くすのが、定時実行で最も多い止まり方です。
このピーク値を、契約しようとしているVPSのメモリ量と並べてください。1GBプランの場合、OS自体もメモリを使います。ピークがその残りに収まらないなら、2GBプランを選ぶかスワップを用意する、という判断になります。
止まる条件で比べる:共有サーバー・VPS 1GB・故障ノートPC
エックスサーバー(共有):cronはあるがChromeが壁になる
- cronは使えますが、root権限が無く、常駐プロセスも原則として使えません。
- Chromeは、root無しで自分のホームディレクトリに展開して動かすことになります。
- 他の利用者と資源を分け合うため、長時間・高メモリのプロセスは制限の対象になりえます。制限値は公式マニュアルで確認してください。
- 実際に動くかどうかの検証は Seleniumはエックスサーバーのcronで動く?26年10月 にまとめています。
- Seleniumを使わず
requestsだけで取れるサイトなら、共有サーバーのcronが一番手軽で安上がりです。
さくらのVPS 1GB:自由だが、管理の責任も自分に来る
- root権限があるので、Chromeのインストール、cronやsystemd timerの設定、常駐プロセスまで自由に扱えます。
- 止まる条件は主に2つです。
- 前節のピーク値がメモリに収まらないこと
- OSを更新せず放置すること
- 2026年10月21日にはPHPとNode.jsで重大な脆弱性の修正版が公開されました。共有サーバーは事業者側で対応が進みますが、VPSは利用者自身がOSやミドルウェアを更新する必要があります。
- 同じ日には、GMOインターネットグループがFX自動売買向けのサーバーサービス「お名前.com デスクトップクラウド」への不正アクセスを発表しています。外から触れる場所で自動処理を回すなら、更新とログイン経路の管理は省けない作業だと考えてください。
自宅の故障ノートPC:月額0円だが、静かに止まる
私の構成で実際に起きた止まり方を挙げます。
- 停電・ケーブル抜け:バッテリーを外しているので、電源が落ちた瞬間に止まります。書き込み途中のファイルが壊れる可能性もあります。データベースのような壊れると困るものを置くなら、UPS(無停電電源装置)が前提になります。
- タイマーの登録消失:異常終了から復帰したあと、ユニットファイルは残っているのに、
timers.target.wants/のリンクだけが消えていました。その結果、タイマーがdisabledになっていました。エラーは何も出ないので、気づくまで止まり続けます。 - スリープ:ノートPCは、フタを閉じたときや電源管理の判定でサスペンドします。サーバー用途では明示的に無効化しないと、夜間に寝てしまいます。
- まとめ実行の競合:
Persistent=trueのタイマーは、停止中に逃した回を復帰時に一斉に実行します。メモリ4GBでSeleniumを複数同時に起動すると処理が詰まるので、ロックで1本ずつ走らせています。
Macを手元のPCとして使う場合も、スリープ中は定時に発火しない点は同じです。設定方法は launchctl bootstrapで毎日実行|26年10月 にまとめています。
自宅サーバーでSeleniumを毎日止めずに回すsystemd設定
自宅のPCを選ぶ場合、私が最低限入れている設定は次のとおりです。ユーザー名は username に読み替えてください。
1. スリープを完全に止める(sudoが必要)
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
# /etc/systemd/logind.conf に HandleLidSwitch=ignore を書き、再起動する
# 戻すときは sudo systemctl unmask 〜 と設定行の削除maskとフタの設定は両方必要です。片方だけでは、もう片方の経路でサスペンドします。
2. ログアウトしてもuser timerを動かす
sudo loginctl enable-linger username3. ロック付きのサービスとタイマー
# ~/.config/systemd/user/scrape.service
[Unit]
Description=daily selenium job
[Service]
Type=oneshot
WorkingDirectory=/home/username/scrape
ExecStart=/usr/bin/flock -w 3600 /home/username/.agent.lock /home/username/scrape/.venv/bin/python job.py
# ~/.config/systemd/user/scrape.timer
[Unit]
Description=run scrape daily
[Timer]
OnCalendar=*-*-* 07:00:00
Persistent=true
[Install]
WantedBy=timers.targetflock -w 3600:同じロックファイルを使うジョブは1本ずつしか走りません。後から来たジョブは最大1時間待ちます。復帰直後の一斉実行でも、取りこぼさずに順番待ちになります。Persistent=true:電源が落ちていて逃した回を、起動後に実行します。- 有効化は
systemctl --user daemon-reloadの後にsystemctl --user enable --now scrape.timerです。
4. タイマーが消えていないかを外から確かめる
systemctl --user list-timers --all
systemctl --user is-enabled scrape.timer- ジョブ自身を異常終了させて知らせる方法は、取らない方が安全です。異常終了をきっかけにタイマーのリンクが外れると、それ以降は何も通知されません。
- 私は、全タイマーが
enabledか、周期どおりに走っているかを別のタイマーで毎晩点検し、結果を通知しています。 - 点検するタイマーは、点検されるジョブと同じ仕組みで壊れうるので、通知が来ないこと自体にも気づける形にしておきます。
取得先サイトへの配慮:robots.txt・利用規約・アクセス間隔
毎日自動で動くということは、相手のサーバーにも毎日アクセスするということです。
- robots.txt:上のコードのように、取得前に
urllib.robotparserで確認します。拒否されていれば取得しません。 - 利用規約:自動取得を禁止しているサイトもあります。公式APIがあるならそちらを使います。
- アクセス間隔:ページ遷移ごとに数秒空け、同時に複数のブラウザで同じサイトを叩きません。
- 識別できるUser-Agent:自分のクローラーだと分かる名前と、連絡先ページのURLを入れておきます。
- 制限への対応:ログイン認証やbot対策を回避する工夫はしません。止められたら、取得の方法か対象そのものを見直します。
関連する選択肢
毎日決まった時刻にスクリプトを動かすだけなら、共有のレンタルサーバーでも足ります。cronが使えるプランを選べば、自分でOSを管理する必要はありません。
※ 広告を含みます(A8.net)。リンク経由でお申し込みがあった場合、手数料を受け取ることがあります。
まとめ
Seleniumとheadless Chromeを毎日定時に動かすなら、まず上のコードで自分のスクリプトのChrome全体のメモリのピークを測ってください。
- requestsだけで取れる場合:エックスサーバーのcronで足ります。月額693円からです(キャンペーン適用時)。
- Chromeが必要な場合:常時通電できる予備PCが無ければ、VPSを1つ選びます。ピークが1GBに収まるなら、さくらのVPS 1GB(807円から)やKAGOYA・WebARENA Indigoの1GB帯で足ります。足りなければXServer VPS 2GB(830円から)を検討します。
- 自宅のPCを選ぶ場合:月額0円ですが、停電・タイマー消失・スリープの3つで、エラーも出さずに止まります。スリープ無効化・linger・flock・タイマーの外部点検までをセットで入れられる人向けです。
どの環境でも、driver.quit() を finally に置くことと、OSの更新は欠かさないでください。