本ページはプロモーションが含まれています。
Seleniumのheadless Chromeで作った巡回スクリプトを、毎日決まった時刻に動かしたい。手元のPCでは動くのに、エックスサーバーのような共有レンタルサーバーのcronに載せると動かない。VPSを借りるべきか、余っている古いPCで回すべきかも迷う。この記事では、Celeron 3205U・メモリ4GBのバッテリーを外したノートPCで、ブラウザ自動化を1日2回・各8〜9分回している実測を軸にします。そのうえで、共有サーバー・さくらのVPS 1GB・自宅PCのどれを選ぶか、それぞれがどこで止まるかを整理します。
共有レンタルサーバーのcronでheadless Chromeが動くかは「Chrome本体を置けるか」で決まる
結論から書きます。共有レンタルサーバーでSeleniumが動くかどうかは、cronの有無ではなく、サーバー上でChrome(またはChromium)本体を実行できるかで決まります。Seleniumはブラウザを操作する仕組みなので、操作される側のブラウザがサーバーに入っていなければ動きません。cronが使えても、それだけでは足りません。
共有サーバーで引っかかる3つの条件
- root権限が無い:Chromeは多数の共有ライブラリに依存しています。通常は
apt installで入れますが、共有サーバーではroot(管理者権限)が無いのでこれができません。 - プロセスの実行時間・メモリに制限がある:共有サーバーは1台を多数の利用者で分け合います。そのため、重い処理や長時間の処理は制限される前提で設計されています。headless Chromeはこの「重い処理」の典型です。
- cronの本数・間隔に上限がある:たとえばロリポップ!のエコノミープランはcronが1つまで、最短実行間隔は5分です(2026年10月時点の調査結果)。
エックスサーバーの共有レンタルサーバーで、これらがどう扱われているかは今回の調査範囲に入っていません。そのため断定はせず、契約前・契約直後に自分で確かめる手順を示します。SSHで入って次を実行します。
python3 -V
which google-chrome chromium chromium-browser
python3 -V:使えるPythonのバージョンを確認します。which:Chrome系のコマンドがパス上にあるかを見ます。何も表示されなければ、ブラウザはサーバーに入っていません。
何も出なかった場合、ユーザー領域にChromeを展開して動かす方法もあります。ただし、依存ライブラリが揃っているかはサーバー次第です。さらにマニュアルの「cron」「プロセス」「禁止事項」の項目で、ブラウザのような常駐的に重い処理が許されているかを確認する必要があります。規約で禁じられている重い処理を共有サーバーで続けると、他の利用者に迷惑をかけるうえ、アカウント停止の理由にもなります。
マネージドクラウド型は「常駐しない」前提で考える
ロリポップ!マネージドクラウドは基本料金1,348円/月のコンテナ型サービスです。アクセスがないとコンテナが20分で自動停止する仕組みのため、決まった時刻に自発的に処理を走らせる用途には工夫が要ります。「毎日ブラウザ自動化を動かす」という条件には素直に合いません。
そもそもブラウザが要るかを先に疑う
取得したいページがJavaScriptで後から描画されるのでなければ、requests と BeautifulSoup で足ります。これならChromeが不要なので、共有サーバーのcronでも動かしやすくなります。ブラウザのソースを表示して、欲しい文字列が最初のHTMLに含まれているかを見るのが早い判定方法です。
今のSeleniumの書き方:executable_pathを捨ててheadless=newで書く
サーバーへ持っていく前に、スクリプト自体を今の書き方にしておきます。以前は、ChromeDriver(ブラウザを操作するための中継プログラム)を自分でダウンロードしてパスを渡していました。
# 以前の書き方(今は通らない)
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.headless = True
driver = webdriver.Chrome(executable_path="/home/username/bin/chromedriver", options=options)
Selenium 4系の途中で executable_path 引数と options.headless 属性は廃止されました。現在はSelenium Manager(Selenium同梱のドライバ自動取得機能)が、インストール済みのChromeに合うドライバを自動で用意します。Chromeを更新するたびにドライバを入れ替える作業が要らなくなったので、「放置して毎日動かす」用途ではこの変更の恩恵が大きいです。自分の環境のバージョンは pip show selenium で確認し、引数の扱いはSeleniumの公式ドキュメントで確かめてください。
実行環境
- Python 3.10以上を想定(
python3 -Vで確認) pip install selenium(venvの中で入れる。理由は後述)- Google Chrome または Chromium がサーバーに入っていること
Ubuntu 24.04系でシステムのPythonへ直接 pip install すると拒否されます。この点はexternally-managedはvenvで|26年10月で手順をまとめています。cronやsystemdから呼ぶときも、venvのPythonをフルパスで指定するのが確実です。
毎日動かす前提で書いた巡回スクリプト
import time
import urllib.robotparser
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
BASE = "https://example.com"
PAGES = ["/list?page=1", "/list?page=2"]
WAIT_SEC = 5 # ページ間の待ち時間(相手への配慮)
OUT = Path(__file__).with_name("result.txt")
robots = urllib.robotparser.RobotFileParser(BASE + "/robots.txt")
robots.read()
def make_driver():
opts = webdriver.ChromeOptions()
opts.add_argument("--headless=new")
opts.add_argument("--disable-dev-shm-usage")
opts.add_argument("--window-size=1280,900")
driver = webdriver.Chrome(options=opts)
driver.set_page_load_timeout(60)
return driver
def main():
driver = make_driver()
titles = []
try:
for path in PAGES:
if not robots.can_fetch("*", BASE + path):
print("robots.txt で不許可のため飛ばす:", path)
continue
driver.get(BASE + path)
WebDriverWait(driver, 20).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, "h2.title"))
)
titles += [e.text for e in driver.find_elements(By.CSS_SELECTOR, "h2.title")]
time.sleep(WAIT_SEC)
finally:
driver.quit()
OUT.write_text("\n".join(titles), encoding="utf-8")
print(len(titles), "件")
if __name__ == "__main__":
main()
ブロックごとの役割は次のとおりです。
- 先頭の定数:取得先・巡回するページ・ページ間の待ち時間・出力先をまとめています。出力先を
Path(__file__)基準にしたのは、cronから起動するとカレントディレクトリがホームになり、相対パスで書いたファイルが意図しない場所に出るためです。 robots:起動時に1回だけrobots.txtを読み、ページごとに取得してよいかを判定します。毎ページ読み直すと、それだけで余計なアクセスになります。make_driver():--headless=newは画面を持たないサーバーでChromeを動かす指定です。--disable-dev-shm-usageは共有メモリ領域(/dev/shm)が小さい環境でChromeが落ちるのを避けます。set_page_load_timeout(60)は、相手のページが応答しないまま処理が永遠に止まるのを防ぎます。WebDriverWait:固定時間待つのではなく、目的の要素が出るまで最大20秒待ちます。JavaScriptで後から描画されるページでも空振りしません。finally: driver.quit():無人運用で最も重要な行です。途中で例外が出てもChromeを確実に終了させます。これが無いと、失敗するたびにChromeのプロセスが残ってメモリを食い続け、数日後にサーバーごと動かなくなります。
なお、rootでChromeを動かす場合は --no-sandbox が必要になることがあります。ただしこれはChromeの保護機構を外す指定です。一般ユーザーで動かせる環境なら付けないでください。
さくらのVPS 1GB・XServer VPS・自宅PCの料金と止まる条件を比較する
Chromeを確実に入れられて、cronも自由に書けるのはVPSと自宅PCです。2026年10月時点の調査結果をもとに、ブラウザ自動化の置き場所として比べます。
置き場所 | 月額(調査時点) | root / Chrome導入 | 定時実行 | 止まる条件 |
|---|---|---|---|---|
共有レンタルサーバー(ロリポップ!エコノミー等) | 121円〜(36ヶ月)/231円(1ヶ月) | root無し。Chromeは環境次第 | cron 1つ・最短5分(エコノミー) | Chromeが無い・プロセス制限・規約 |
さくらのVPS 1GB(東京) | 990円(1ヶ月払い) | あり。自由に導入可 | cron・systemd timerとも自由 | メモリ不足・支払い・メンテナンス再起動 |
さくらのVPS 2GB(東京) | 1,958円(1ヶ月払い) | あり | 自由 | 同上(メモリには余裕) |
ConoHa VPS 1GB | 763円〜(36ヶ月まとめトク) | あり | 自由 | 同上 |
XServer VPS 2GB | 1,980円(1ヶ月)/1,265円(36ヶ月) | あり | 自由 | 同上 |
自宅の古いPC | 電気代のみ | あり | 自由 | 停電・スリープ・回線断・異常終了後の設定消失 |
直近の料金改定に注意
- XServer VPS:2026年9月1日に値上げ。2GBプランの36ヶ月契約は月額990円から1,265円になりました。お試しに使えた無料VPSは利用期間が最大24時間に短縮され、10月16日時点で新規受付も一時停止中です。
- シンVPS:2026年9月1日に全プランが約1.4倍に改定されました。
- さくらのVPS:クレジットカード払いなら14日間の無料お試しがあります。自分のスクリプトが1GBで足りるかを実測するにはこれが一番手軽です。
- ConoHa VPS:時間課金(1時間あたり1.3円〜)があり、最低利用期間がありません。数時間だけ試すならこちらも使えます。
1GBで足りるかはメモリの実測で決める
セルフホストではCPUやディスクよりメモリが先に足りなくなる、というのが調査でも繰り返し指摘されている点です。1GBのVPSは「小さなアプリ1つ」が目安とされています。headless Chromeは本体の他に複数の子プロセスを立ち上げるので、Pythonの使用量だけを見ても実態は分かりません。巡回中に別の端末から次を実行し、Chrome系プロセスの合計を見ます。
ps -eo rss,comm | awk '/chrom/ {s+=$1} END {print s/1024 " MB"}'
free -m
- 1行目:プロセス名に
chromを含むもの(chrome・chromium)の物理メモリ使用量を合計し、MB単位で表示します。 - 2行目:サーバー全体の空きメモリを見ます。
availableが巡回中に0近くまで落ちるなら、1GBプランでは不足です。
不足したときにOSが取る行動は、メモリを多く使っているプロセスの強制終了(OOM killer)です。このときスクリプトはエラーを出す間もなく消えるため、ログを見ても原因が分かりにくくなります。巡回ページが多い、画像の多いサイトを開くといった場合は、最初から2GBプランを選ぶか、スワップ(ディスクをメモリの代わりに使う領域)を用意してください。
Celeron 3205U・4GBの故障ノートPCで1日2回・各8〜9分回している構成
私は、バッテリーが故障して取り外したノートPC(Celeron 3205U・メモリ4GB)にXubuntu 24.04を入れ、ブラウザ自動化の巡回を毎日7:00と19:00の2回動かしています。1回あたりの実行時間は8〜9分です。CPUは2コアの古い世代ですが、1日2回・1回10分弱という頻度なら性能は問題になりません。問題になったのは性能ではなく、止まり方でした。
cronではなくsystemd timerを使う理由
cronは、その時刻にマシンが止まっていた回を実行しません。systemd timerは Persistent=true を付けると、停止中に逃した回を起動後に実行してくれます。停電がありうる自宅PCでは、この差が大きくなります。
# ~/.config/systemd/user/crawl.service
[Unit]
Description=browser crawl
[Service]
Type=oneshot
WorkingDirectory=/home/username/crawl
ExecStart=/usr/bin/flock -w 3600 /home/username/crawl.lock /home/username/crawl/.venv/bin/python crawl.py
# ~/.config/systemd/user/crawl.timer
[Unit]
Description=browser crawl twice a day
[Timer]
OnCalendar=*-*-* 07,19:00:00
Persistent=true
[Install]
WantedBy=timers.target
Type=oneshot:一度実行して終わる処理であることを示します。flock -w 3600:ロックファイルを使い、同時に1本しか走らないようにします。停電から復帰すると、逃した回が他の定時処理と一斉に起動します。4GBのPCでChromeが複数並走すると処理が破綻するため、後から来た処理は最大1時間待たせて順番に流します。待つだけなので取りこぼしません。OnCalendar:毎日7時と19時に起動します。Persistent=true:停止中に逃した回を、起動後に実行します。
有効化と確認は次のとおりです。
loginctl enable-linger username
systemctl --user daemon-reload
systemctl --user enable --now crawl.timer
systemctl --user list-timers
enable-linger を入れないと、ログアウトした時点でユーザー単位のタイマーが止まります。画面にログインしていないサーバー運用では必須です。
ノートPCをサーバーにするときの設定
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
# /etc/systemd/logind.conf に HandleLidSwitch=ignore を書いて
sudo systemctl restart systemd-logind
1行目はスリープを完全に無効化し、2行目以降はフタを閉じても動き続けるようにします。両方必要です。片方だけだと、何かのきっかけでスリープに入り、その時刻の処理が飛びます。
自宅PCで実際に止まった・止まりうる条件
- 停電・電源ケーブルの抜け:バッテリーを外しているので、電源が落ちた瞬間に即停止します。
Persistent=trueで取りこぼしは回収できますが、書き込み中のファイルが壊れる可能性は残ります。 - 異常終了後にタイマー登録が消える:ユニットファイルは残っているのに、自動起動のリンクだけが消えて
disabledになっていたことがありました。エラーは何も出ず、処理が黙って止まります。再起動のたびにsystemctl --user list-timersで全タイマーが揃っているかを確かめています。 - 自宅回線の障害:外向きのアクセスだけなのでポート開放は不要ですが、回線が落ちればその回は失敗します。
Macで定期実行する場合はlaunchdになります。ただし、ノートを閉じている間は発火しないので、毎日確実に動かす用途には向きません。設定方法自体はlaunchctl bootstrapで毎日実行|26年10月にまとめています。
VPSでcronを使う場合
VPSは電源の心配がほぼ無いので、cronでも十分です。重複起動の防止だけは入れておきます。
# crontab -e
0 7,19 * * * /usr/bin/flock -n /home/username/crawl.lock /home/username/crawl/.venv/bin/python /home/username/crawl/crawl.py >> /home/username/crawl/cron.log 2>&1
flock -n は、前回がまだ動いていたら今回は諦める指定です(自宅PCの -w は待つ指定)。VPSは停止中の回を回収する必要が薄いので、重なったら飛ばす方が素直です。>> ... 2>&1 で、標準出力とエラーの両方をログに残します。cronは画面が無いので、ここに残さないと失敗の理由を後から追えません。
取得先サイトへの配慮:robots.txt・利用規約・1日2回という頻度
毎日自動で動かす処理は、一度設定すると人の目を通らずにアクセスし続けます。だからこそ、最初に次を確認してください。
- robots.txt:前述のスクリプトのように、取得前に機械的に判定します。不許可のパスは取りに行きません。
- 利用規約:自動取得を禁じているサイトもあります。特にログインが要るサービスでは、規約で自動アクセスを明示的に禁止していることが多いので、必ず読みます。禁止されている場合は、技術的に取れても取りません。公式APIやRSSが用意されていれば、そちらを使います。
- アクセス間隔と頻度:ページ間に数秒の待ちを入れ、並列で開きません。新着の確認が目的なら、1日数回で足りるはずです。私が1日2回にしているのも、結果は夜にまとめて見るので、日中に細かく巡回しても意味がないためです。
- 制限を回避しない:CAPTCHAやbot対策に引っかかったら、それは「来ないでほしい」という相手の意思表示です。回避する方法を探すのではなく、取得自体をやめる判断をしてください。
「毎日ブラウザ自動化を動かす」ならどこを選ぶか
状況 | 選ぶ置き場所 | 理由 |
|---|---|---|
ページがJavaScript無しで読める | 共有レンタルサーバーのcron | requestsで足り、Chromeが不要 |
Chromeが必須・巡回ページが少ない | さくらのVPS 1GB(990円)/ConoHa 1GB | root有り・電源の心配なし。まず無料お試しでメモリを実測 |
Chromeが必須・巡回量が多い | 2GBプラン(さくら1,958円・XServer 1,980円) | OOM killerで黙って落ちるのを避ける |
余っているPCがあり、停電時の数時間の遅れを許容できる | 自宅PC+systemd timer | 月額0円。Persistent=trueとflockで取りこぼしと並走を防ぐ |
関連する選択肢
毎日決まった時刻にスクリプトを動かすだけなら、共有のレンタルサーバーでも足ります。cronが使えるプランを選べば、自分でOSを管理する必要はありません。
※ 広告を含みます(A8.net)。リンク経由でお申し込みがあった場合、手数料を受け取ることがあります。
まとめ:Seleniumの置き場所はChrome・メモリ・電源で決める
Seleniumのheadless Chromeを毎日動かす場所は、cronが使えるかではなく、Chrome本体を置けるかで決まります。共有レンタルサーバーはroot権限が無く、Chromeを入れられるかもプロセス制限も環境次第です。エックスサーバーを含め、契約したらまず which とマニュアルで確かめてください。確実なのはVPSで、さくらのVPS 1GBなら月990円、14日の無料お試しでメモリを実測できます。足りなければ2GBに上げます。自宅の古いPCでも、Celeron 3205U・4GBで1日2回・各8〜9分の巡回は十分に回ります。ただし止まる原因は性能ではなく、停電・スリープ・タイマー登録の消失です。systemd timerの Persistent=true と flock、再起動後の list-timers 確認までを運用に含めてください。そしてどこで動かす場合も、driver.quit() を finally に置くこと、robots.txtと規約を守ることは変わりません。