<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Selenium</title>
	<atom:link href="https://javeo.jp/tag/selenium/feed/" rel="self" type="application/rss+xml" />
	<link>https://javeo.jp</link>
	<description>ほどほどレベルのプログラミング</description>
	<lastBuildDate>Wed, 19 Nov 2025 22:31:34 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://javeo.jp/wp-content/uploads/2025/08/cropped-ExcelPython_future-32x32.jpg</url>
	<title>Selenium</title>
	<link>https://javeo.jp</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>お手軽なプロキシサービス「jpProxy」を使ってみる</title>
		<link>https://javeo.jp/jpproxy-guide/</link>
					<comments>https://javeo.jp/jpproxy-guide/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Sat, 08 Nov 2025 17:27:09 +0000</pubDate>
				<category><![CDATA[雑記・その他]]></category>
		<category><![CDATA[jpProxy]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Selenium]]></category>
		<category><![CDATA[スクレイピング]]></category>
		<category><![CDATA[プロキシ]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=3721</guid>

					<description><![CDATA[目次 プロキシサーバーとは？jpProxyについてjpProxyの主な利用シーンクローリング時のアクセス回数制限を回避したい複数のアカウントを持ちたい海外から国内のサイトにアクセスしたい無料だと不安jpProxyの設定・ [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<div class="wp-block-cocoon-blocks-info-box block-box primary-box">
<p>RPA・スクレイピングをしているとIPアドレス変えたいなと思うことありませんか？</p>



<p>理由や目的は様々ですがプロキシサーバを使うことで本来のIPアドレスを隠してブラウザ操作することが可能になります</p>



<p>プロキシサーバー中で「jpProxy」についてご紹介します</p>
</div>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">プロキシサーバーとは？</a></li><li><a href="#toc2" tabindex="0">jpProxyについて</a></li><li><a href="#toc3" tabindex="0">jpProxyの主な利用シーン</a><ol><li><a href="#toc4" tabindex="0">クローリング時のアクセス回数制限を回避したい</a></li><li><a href="#toc5" tabindex="0">複数のアカウントを持ちたい</a></li><li><a href="#toc6" tabindex="0">海外から国内のサイトにアクセスしたい</a></li><li><a href="#toc7" tabindex="0">無料だと不安</a></li></ol></li><li><a href="#toc8" tabindex="0">jpProxyの設定・使い方</a><ol><li><a href="#toc9" tabindex="0">契約プロキシ一覧</a></li><li><a href="#toc10" tabindex="0">接続元IP登録</a></li><li><a href="#toc11" tabindex="0">ユーザID・パス確認</a></li></ol></li><li><a href="#toc12" tabindex="0">プロキシサーバー経由でインターネットアクセスする方法</a></li><li><a href="#toc13" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">プロキシサーバーとは？</span></h2>



<p>プロキシサーバーはインターネットへの接続を中継してくれるサービスで、WEBサイトから見ればプロキシサーバーがアクセスしていることになるので結果としてIPアドレスが秘匿されることになります</p>



<p>絵にすると↓の通りパソコンとインターネットの間にプロキシサーバーがいる状態になります</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/プロキシサーバー-1.jpg"><img fetchpriority="high" decoding="async" width="1024" height="576" src="https://javeo.jp/wp-content/uploads/2025/11/プロキシサーバー-1-1024x576.jpg" alt="" class="wp-image-3727" srcset="https://javeo.jp/wp-content/uploads/2025/11/プロキシサーバー-1-1024x576.jpg 1024w, https://javeo.jp/wp-content/uploads/2025/11/プロキシサーバー-1-300x169.jpg 300w, https://javeo.jp/wp-content/uploads/2025/11/プロキシサーバー-1-150x84.jpg 150w, https://javeo.jp/wp-content/uploads/2025/11/プロキシサーバー-1-768x432.jpg 768w, https://javeo.jp/wp-content/uploads/2025/11/プロキシサーバー-1-1536x864.jpg 1536w, https://javeo.jp/wp-content/uploads/2025/11/プロキシサーバー-1.jpg 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>プロキシサーバーは無料もあれば有料もあり、優良なものもあれば粗悪なものあるということで実際に私が利用しているサービスの一つ「<a rel="noreferrer noopener" target="_blank" href="https://jpproxy.com/">jpProxy</a><span class="marker-under"><strong><img decoding="async" border="0" width="1" height="1" src="https://www15.a8.net/0.gif?a8mat=45GC5K+2HB32A+3YFI+674EQ" alt=""></strong></span>」についてまとめてみます</p>



<h2 class="wp-block-heading"><span id="toc2">jpProxyについて</span></h2>



<p>まず一番大事なことからお伝えするとjpProxyは<span class="marker-under"><strong>有料サービス</strong></span>です</p>



<p>ですが、<span class="marker-under"><span class="bold-red">構築費（初回にかかる費用）200円、月額295円</span></span>と非常にお安く利用できるサービスなので気になるほどではないかと（※費用は2025年11月現在）</p>



<p>また、特徴として日本国内のプロキシサーバー（≒IPアドレス）なのでWEBサイトにも国内からアクセスすることになります</p>



<h2 class="wp-block-heading"><span id="toc3">jpProxyの主な利用シーン</span></h2>



<p>jpProxyのトップページにもありますがjpProxyはこのような方に使われています</p>



<ul class="wp-block-list has-watery-yellow-background-color has-background is-style-icon-list-check has-list-style">
<li><strong>クローリング時のアクセス回数制限の回避</strong></li>



<li><strong>複数アカウントを使いたい</strong></li>



<li><strong>IPアドレスを秘匿したい</strong></li>



<li><strong>海外から国内のサイトにアクセスしたい</strong></li>
</ul>



<h3 class="wp-block-heading"><span id="toc4">クローリング時のアクセス回数制限を回避したい</span></h3>



<p>AmazonやGoogleなどのほとんどのサイトサーバーでは単位時間内のアクセス回数に制限を設けています</p>



<p>アクセス元のIPアドレスからのアクセス回数をカウントし、その回数が一定の基準を超えるとアクセスを制限するので、IPアドレスを分散させることで制限を回避することが可能です<br><br>また、この場合も日本のサイトをクローリングするなら日本国内のプロキシIPアドレスが最適です</p>



<h3 class="wp-block-heading"><span id="toc5">複数のアカウントを持ちたい</span></h3>



<p>サイト利用時に複数のアカウントを持ちたい場合がありますが、その場合にIPアドレスで同一ユーザであることを判定されます</p>



<p>判定されるとアカウントを作れなかったりアクセスに不都合が生じる場合があります<br><br>jpProxyのIPアドレスを使えばIPアドレスによる同一ユーザ判定を回避できるようになります<br>また、この場合も日本のサイトで複数アカウントを利用するなら日本国内のプロキシIPアドレスが最適です<br></p>



<h3 class="wp-block-heading"><span id="toc6">海外から国内のサイトにアクセスしたい</span></h3>



<p>最近ではIPアドレスでアクセス元の国を判断するサイトが増えています<br>アクセス元のIPアドレスが日本でない場合、接続を拒否するサイトがあります</p>



<p>jpProxyのIPアドレスは<strong>日本国内の固定IPアドレス</strong>ですので安心です</p>



<h3 class="wp-block-heading"><span id="toc7">無料だと不安</span></h3>



<p>無料のプロキシは公開されているので、トラフィック量が異常なほど多いです<br>そのため、接続できなかったり、遅かったりと使い物にならないものがほとんです</p>



<p>また、無料のプロキシはセキュリティの面でもおすすめできません</p>



<p>動画の閲覧には安定したネットワークが必要となりますので、多人数が同時に接続するプロキシは動画の閲覧には不向きです</p>



<p>jpProxyは通信内容をロギングおよび閲覧していません</p>



<h2 class="wp-block-heading"><span id="toc8">jpProxyの設定・使い方</span></h2>



<p>基本的にボタンポチポチしかすることはないんですが、簡単に設定方法や使い方のご紹介です</p>



<h3 class="wp-block-heading"><span id="toc9">契約プロキシ一覧</span></h3>



<p>今契約しているプロキシサーバーの情報を見ることができます</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_46-1.png"><img decoding="async" width="1024" height="537" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_46-1-1024x537.png" alt="" class="wp-image-3731" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_46-1-1024x537.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_46-1-300x157.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_46-1-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_46-1-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_46-1.png 1437w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h3 class="wp-block-heading"><span id="toc10">接続元IP登録</span></h3>



<p>プロキシサーバーに接続するIPアドレスを登録できます</p>



<p>サーバーへのアクセス方法はBasic認証かこのページでホワイトリストとして登録することで利用できるようになります</p>



<p>登録するために必要な自分のIPアドレスは画面中央に表示されれている（黄塗り箇所）のでコピペで大丈夫な親切設計</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_51-2.png"><img decoding="async" width="1024" height="537" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_51-2-1024x537.png" alt="" class="wp-image-3734" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_51-2-1024x537.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_51-2-300x157.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_51-2-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_51-2-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_51-2.png 1439w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h3 class="wp-block-heading"><span id="toc11">ユーザID・パス確認</span></h3>



<p>こちらがBasic認証するときに必要なユーザIDとパスワードを確認できる画面</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_57.png"><img decoding="async" width="1024" height="537" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_57-1024x537.png" alt="" class="wp-image-3733" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_57-1024x537.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_57-300x157.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_57-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_57-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_01h00_57.png 1439w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>Basic認証とはなんぞや、って方に簡単な説明すると画面上部に表示されるユーザー名とパスワードを入力するフォームでの認証</p>



<p>このフォームにユーザID・パスを入力することでプロキシサーバーに接続できます</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h03_00-1.png"><img decoding="async" width="1024" height="537" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h03_00-1-1024x537.png" alt="" class="wp-image-3738" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h03_00-1-1024x537.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h03_00-1-300x157.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h03_00-1-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h03_00-1-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h03_00-1.png 1198w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h2 class="wp-block-heading"><span id="toc12">プロキシサーバー経由でインターネットアクセスする方法</span></h2>



<p>ネットワーク設定周りを変更するのが正攻法であるものの、起動オプションでプロキシを指定してあげる方法がおそらく一番簡単かつ影響が少ないはず</p>



<p>まずはChromeをプロキシサーバ経由の通信でする起動オプション込みのコマンドがコチラ</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-plain"><code>&quot;C:\Program Files\Google\Chrome\Application\chrome.exe&quot; --proxy-server=&quot;http://{IPアドレス}:{ポート}&quot;</code></pre></div>



<p>Windwos+Rのファイル名を指定して実行、Chromeのショートカットプロパテのリンク先、タスクバーの検索ウィンドウなどでコマンドを使うとプロキシ接続した状態でChromeを利用できます</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h14_30.png"><img decoding="async" width="399" height="206" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h14_30.png" alt="" class="wp-image-3740" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h14_30.png 399w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h14_30-300x155.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h14_30-150x77.png 150w" sizes="(max-width: 399px) 100vw, 399px" /></a></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h12_18.png"><img decoding="async" width="470" height="580" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h12_18.png" alt="" class="wp-image-3739" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h12_18.png 470w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h12_18-243x300.png 243w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h12_18-122x150.png 122w" sizes="(max-width: 470px) 100vw, 470px" /></a></figure>
</div>
</div>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h17_20.png"><img decoding="async" width="1024" height="768" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h17_20-1024x768.png" alt="" class="wp-image-3741" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h17_20-1024x768.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h17_20-300x225.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h17_20-150x113.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h17_20-768x576.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-09_02h17_20.png 1080w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h2 class="wp-block-heading"><span id="toc13">まとめ</span></h2>



<p>個人的にはスクレイピングするときによく使う<a rel="noreferrer noopener nofollow" target="_blank" href="https://jpproxy.com/">jpProxy</a> <img decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=45GC5K+2HB32A+3YFI+674EQ" alt="">のご紹介でした</p>



<p>使い方としてはVPNサービスと大差はありませんがPython+Seleniumのスクレイピングプログラムでも簡単に利用できて何気に重宝しますし、お安いサービスなのでおススメです！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/jpproxy-guide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VPNサービス「NordVPN」を使ってみる</title>
		<link>https://javeo.jp/nordvpn-guide/</link>
					<comments>https://javeo.jp/nordvpn-guide/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Sat, 08 Nov 2025 08:23:51 +0000</pubDate>
				<category><![CDATA[雑記・その他]]></category>
		<category><![CDATA[NordVPN]]></category>
		<category><![CDATA[Selenium]]></category>
		<category><![CDATA[VPN]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=3677</guid>

					<description><![CDATA[目次 VPNサービスとは？NordVPNとはNordVPNを利用するまでアカウント作成ライセンス購入アプリインストール拡張機能インストール使い方アプリの使い方拡張機能の使い方NordVPNの特徴まとめ VPNサービスとは [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<div class="wp-block-cocoon-blocks-info-box block-box primary-box">
<p>RPA・スクレイピングをしているとIPアドレス変えたいなと思うことありませんか？</p>



<p>理由や目的は様々ですがVPNサービスを使うことで本来のIPアドレスを隠してブラウザ操作することが可能になります</p>



<p>今回は数あるVPNサービスの中で「NordVPN」についてご紹介します</p>
</div>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">VPNサービスとは？</a></li><li><a href="#toc2" tabindex="0">NordVPNとは</a></li><li><a href="#toc3" tabindex="0">NordVPNを利用するまで</a><ol><li><a href="#toc4" tabindex="0">アカウント作成</a></li><li><a href="#toc5" tabindex="0">ライセンス購入</a></li><li><a href="#toc6" tabindex="0">アプリインストール</a></li><li><a href="#toc7" tabindex="0">拡張機能インストール</a></li></ol></li><li><a href="#toc8" tabindex="0">使い方</a><ol><li><a href="#toc9" tabindex="0">アプリの使い方</a></li><li><a href="#toc10" tabindex="0">拡張機能の使い方</a></li></ol></li><li><a href="#toc11" tabindex="0">NordVPNの特徴</a></li><li><a href="#toc12" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">VPNサービスとは？</span></h2>



<p>VPNをちゃんと理解しようとすると通信技術やセキュリティの話が必要になってくるんですが、今回はPythonなどプログラムででRPA・スクレイピングするときに使うVPNに特化して説明をするので端的には</p>



<p class="has-text-align-center is-style-parenthetic-box has-box-style"><span class="fz-18px"><span class="fz-22px"><span class="marker-under"><span class="bold-red">自分のIPアドレスを隠してくれるサービス</span></span></span></span></p>



<p>です（かなり極端な表現なので気になる人はちゃんと調べてください）</p>



<p>目的だけでいえばプロキシサーバーなんかもありますので気になる人は同じく調べてみてみるとお勉強になります</p>



<p>無料もあれば有料もあり、優良なものもあれば粗悪なものあるということで実際に私が利用しているサービスの一つ「<span class="marker-under"><strong><a rel="noreferrer noopener nofollow" target="_blank" href="https://nordvpn.com/ja/">NordVPN</a><img decoding="async" border="0" width="1" height="1" src="https://www15.a8.net/0.gif?a8mat=45GC5K+2HB32A+3YFI+674EQ" alt=""></strong></span>」についてまとめてみます</p>



<h2 class="wp-block-heading"><span id="toc2">NordVPNとは</span></h2>



<p>まず一番大事なことからお伝えするとNordVPNは<span class="marker-under"><strong>有料サービス</strong></span>です</p>



<p>基本的に無料VPNサービスは通信速度が遅かったりセキュリティに不安があったりするのでVPNを使う時は惜しまず有料サービスがおススメです</p>



<p>費用やセキュリティについては<a rel="noreferrer noopener" target="_blank" href="https://nordvpn.com/ja/blog/vpn-cost" data-type="link" data-id="https://nordvpn.com/ja/blog/vpn-cost">NordVPNのサイト</a>の中でもまとめてあるので参考にしてみてください</p>



<div style="text-align: center;">
<a rel="nofollow noopener noreferrer" target="_blank" href="https://px.a8.net/svt/ejp?a8mat=45GC5K+2HB32A+3YFI+5ZU29">
<img decoding="async" border="0" width="300" height="250" alt="" src="https://www25.a8.net/svt/bgt?aid=251025032150&#038;wid=003&#038;eno=01&#038;mid=s00000018459001007000&#038;mc=1"></a>
<img decoding="async" border="0" width="1" height="1" src="https://www13.a8.net/0.gif?a8mat=45GC5K+2HB32A+3YFI+5ZU29" alt="">
</div>



<h2 class="wp-block-heading"><span id="toc3">NordVPNを利用するまで</span></h2>



<p>NordVPNの利用開始に必要な手順は下記3つ</p>



<p>特に難しいことはありませんが順番に解説していきます</p>



<ul class="wp-block-list">
<li>アカウント作成</li>



<li>ライセンス購入</li>



<li>アプリ or 拡張子インストール</li>
</ul>



<h3 class="wp-block-heading"><span id="toc4">アカウント作成</span></h3>



<p>アカウントの作成はGoogleアカウント or Appleアカウント or その他メアドがあれば簡単に作成可能です</p>



<figure class="wp-block-image size-medium"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_11h31_25.png"><img decoding="async" width="200" height="300" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_11h31_25-200x300.png" alt="" class="wp-image-3692" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_11h31_25-200x300.png 200w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_11h31_25-100x150.png 100w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_11h31_25.png 429w" sizes="(max-width: 200px) 100vw, 200px" /></a></figure>



<h3 class="wp-block-heading"><span id="toc5">ライセンス購入</span></h3>



<p>続いてライセンスの購入</p>



<p>どの期間で購入しても+110/月～130/月で上位プランにアップできますが、VPNを使いたいだけならベーシックプランで十分</p>



<p>期間は月単価が半額以下になるので1年プラン以上を推奨で、2年プランの方が最も安いですが、個人的にはちょっと長すぎなので1年プランの方がおススメです</p>



<p>※以下は2025年11月時点の料金なので参考に</p>



<figure class="wp-block-gallery has-nested-images columns-1 is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_04-1.png"><img decoding="async" width="1920" height="1032" data-id="3696" src="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_04-1.png" alt="" class="wp-image-3696" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_04-1.png 1920w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_04-1-300x161.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_04-1-1024x550.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_04-1-150x81.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_04-1-768x413.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_04-1-1536x826.png 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></a><figcaption class="wp-element-caption">1カ月プラン</figcaption></figure>



<figure class="wp-block-image size-full"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_09-1.png"><img decoding="async" width="1920" height="1032" data-id="3697" src="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_09-1.png" alt="" class="wp-image-3697" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_09-1.png 1920w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_09-1-300x161.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_09-1-1024x550.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_09-1-150x81.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_09-1-768x413.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_09-1-1536x826.png 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></a><figcaption class="wp-element-caption">1年プラン</figcaption></figure>



<figure class="wp-block-image size-full"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_13.png"><img decoding="async" width="1920" height="1032" data-id="3698" src="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_13.png" alt="" class="wp-image-3698" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_13.png 1920w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_13-300x161.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_13-1024x550.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_13-150x81.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_13-768x413.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h20_13-1536x826.png 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></a><figcaption class="wp-element-caption">2年プラン</figcaption></figure>
</figure>



<h3 class="wp-block-heading"><span id="toc6">アプリインストール</span></h3>



<p>各OS用に<a rel="noreferrer noopener" target="_blank" href="https://nordvpn.com/ja/download/windows/" data-type="link" data-id="https://nordvpn.com/ja/download/windows/">ダウンロード画面</a>がありますのでサイト上で対象OSを選択</p>



<p>直感的にわかる簡単仕様ですが、Windows用のインストーラーの手順は↓↓</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h05_50.png"><img decoding="async" width="1024" height="504" data-id="3679" src="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h05_50-1024x504.png" alt="" class="wp-image-3679" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h05_50-1024x504.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h05_50-300x148.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h05_50-150x74.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h05_50-768x378.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h05_50-1536x756.png 1536w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h05_50.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_09.png"><img decoding="async" width="800" height="650" data-id="3680" src="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_09.png" alt="" class="wp-image-3680" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_09.png 800w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_09-300x244.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_09-150x122.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_09-768x624.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></a></figure>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_31.png"><img decoding="async" width="800" height="650" data-id="3681" src="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_31.png" alt="" class="wp-image-3681" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_31.png 800w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_31-300x244.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_31-150x122.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h07_31-768x624.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></a></figure>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_11h58_22.png"><img decoding="async" width="800" height="650" data-id="3702" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_11h58_22.png" alt="" class="wp-image-3702" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_11h58_22.png 800w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_11h58_22-300x244.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_11h58_22-150x122.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_11h58_22-768x624.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></a></figure>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_20.png"><img decoding="async" width="800" height="650" data-id="3682" src="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_20.png" alt="" class="wp-image-3682" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_20.png 800w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_20-300x244.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_20-150x122.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_20-768x624.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></a><figcaption class="wp-element-caption">拡張機能もインストールできる</figcaption></figure>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_49.png"><img decoding="async" width="800" height="650" data-id="3683" src="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_49.png" alt="" class="wp-image-3683" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_49.png 800w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_49-300x244.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_49-150x122.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h08_49-768x624.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></a></figure>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h11_17.png"><img decoding="async" width="800" height="650" data-id="3684" src="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h11_17.png" alt="" class="wp-image-3684" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h11_17.png 800w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h11_17-300x244.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h11_17-150x122.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h11_17-768x624.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></a></figure>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h12_10.png"><img decoding="async" width="906" height="735" data-id="3685" src="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h12_10.png" alt="" class="wp-image-3685" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h12_10.png 906w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h12_10-300x243.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h12_10-150x122.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-10-25_18h12_10-768x623.png 768w" sizes="(max-width: 906px) 100vw, 906px" /></a><figcaption class="wp-element-caption">インストール完了するとログインorアカウント作成画面に</figcaption></figure>
</figure>



<h3 class="wp-block-heading"><span id="toc7">拡張機能インストール</span></h3>



<p>Chrome or Edge用の拡張機能はそれぞれのストアからインストールするだけ</p>



<p>chromeウェブストア：<a rel="noopener noreferrer" target="_blank" href="https://chromewebstore.google.com/detail/vpn-for-chrome-nordvpn-pr/fjoaledfpmneenckfbpdfhkmimnjocfa?pli=1">VPN for Chrome: NordVPN proxy protection</a></p>



<p>Edgeアドオン：<a rel="noopener noreferrer" target="_blank" href="https://microsoftedge.microsoft.com/addons/detail/nordvpn-the-fastest-vpn/fphgeikpdcdcheaochkhldmnfblfogla?hl=ja">NordVPN &#8211; the Fastest VPN proxy for privacy &#8211; Microsoft Edge Addons</a></p>



<h2 class="wp-block-heading"><span id="toc8">使い方</span></h2>



<p>インストールしたアプリと拡張機能では使い方は当然ながら適用範囲も違うので簡単にご紹介</p>



<h3 class="wp-block-heading"><span id="toc9">アプリの使い方</span></h3>



<p>NordVPNは日本語に対応しているのでまずはアプリの中で言語設定を・・</p>



<p class="has-text-align-left is-style-info-box has-box-style">左下の歯車　→　General　→　Language</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_13h17_59.png"><img decoding="async" width="1024" height="555" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_13h17_59-1024x555.png" alt="" class="wp-image-3705" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_13h17_59-1024x555.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_13h17_59-300x163.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_13h17_59-150x81.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_13h17_59-768x417.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_13h17_59.png 1202w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>使い方はかなりシンプル</p>



<p>VPNを利用するには画面下部の接続先を選ぶだけでいいし、自分のIPアドレスを隠匿したいだけなら&#8221;<span class="marker-under"><strong>国：Japan</strong></span>&#8220;を選ぶか、上部の&#8221;<span class="marker-under"><strong>VPNで接続を保護</strong></span>&#8220;をクリックしてあげれば日本のIPアドレスで外部接続するようになります</p>



<p>切り替えが終わるとアプリの画面でお知らせしてくれて、ヘッダーメニュー個所にIPアドレスも表示されています</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h20_46.png"><img decoding="async" width="1024" height="537" data-id="3706" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h20_46-1024x537.png" alt="" class="wp-image-3706" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h20_46-1024x537.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h20_46-300x157.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h20_46-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h20_46-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h20_46.png 1439w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h24_40.png"><img decoding="async" width="1024" height="537" data-id="3707" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h24_40-1024x537.png" alt="" class="wp-image-3707" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h24_40-1024x537.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h24_40-300x157.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h24_40-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h24_40-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h24_40.png 1439w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>
</figure>



<p>そしてこのアプリを使った場合の影響範囲として<span class="marker-under"><span class="bold-red">PC自体のIPアドレスが変わったような状態</span></span>になります（正確には違いますが）</p>



<p>なのでどのブラウザ、どのアプリを使ってもNordVPNによって確立したIPアドレスに変わります</p>



<p>他にもアプリにはセキュリティ対策やADブロックなどの機能もあるのでお好みで</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h33_20.png"><img decoding="async" width="1024" height="537" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h33_20-1024x537.png" alt="" class="wp-image-3708" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h33_20-1024x537.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h33_20-300x157.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h33_20-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h33_20-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h33_20.png 1439w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h3 class="wp-block-heading"><span id="toc10">拡張機能の使い方</span></h3>



<p>拡張機能は残念ながら日本語に対応していないので英語のままです</p>



<p>基本的にはアプリの時と同じく&#8221;<span class="marker-under"><strong>国：Japan</strong></span>&#8220;を選ぶか、上部の&#8221;<span class="marker-under"><strong>Quick Connect</strong></span>&#8220;をクリックでVPN接続されます</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h42_24.png"><img decoding="async" width="1024" height="537" data-id="3709" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h42_24-1024x537.png" alt="" class="wp-image-3709" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h42_24-1024x537.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h42_24-300x157.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h42_24-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h42_24-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h42_24.png 1439w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h43_57.png"><img decoding="async" width="1024" height="537" data-id="3710" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h43_57-1024x537.png" alt="" class="wp-image-3710" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h43_57-1024x537.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h43_57-300x157.png 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h43_57-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h43_57-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_15h43_57.png 1439w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>
</figure>



<p>そしてこの拡張機能は<span class="marker-under"><span class="bold-red">対象のブラウザだけIPアドレスが変わったような状態</span></span>になります</p>



<p>少し見にくいですが、手前のEdgeは通常のIPアドレスのままに対して奥のChromeはNordVPNで接続したIPで検知されていることがわかります</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_16h01_49.jpg"><img decoding="async" width="1024" height="550" src="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_16h01_49-1024x550.jpg" alt="" class="wp-image-3711" srcset="https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_16h01_49-1024x550.jpg 1024w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_16h01_49-300x161.jpg 300w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_16h01_49-150x81.jpg 150w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_16h01_49-768x413.jpg 768w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_16h01_49-1536x826.jpg 1536w, https://javeo.jp/wp-content/uploads/2025/11/2025-11-08_16h01_49.jpg 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>もう一つ、拡張機能の設定でブラウザ起動時に自動でVPN接続する設定があります</p>



<p>この設定をすることでSeleniumなどで&#8221;<span class="marker-under"><strong>ブラウザ起動時に自動でVPN接続する</strong></span>&#8220;ことが可能になります</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/11/image.png"><img decoding="async" width="1024" height="537" src="https://javeo.jp/wp-content/uploads/2025/11/image-1024x537.png" alt="" class="wp-image-3715" srcset="https://javeo.jp/wp-content/uploads/2025/11/image-1024x537.png 1024w, https://javeo.jp/wp-content/uploads/2025/11/image-300x157.png 300w, https://javeo.jp/wp-content/uploads/2025/11/image-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/11/image-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/11/image.png 1439w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h2 class="wp-block-heading"><span id="toc11">NordVPNの特徴</span></h2>



<p>VPNを利用するときあると嬉しい&#8221;セッション中でも定期的にIPが変わるIPローテーション&#8221;機能ですが、残念ながら<span class="marker-under-blue">NordVPNには搭載されていません</span></p>



<p>ですが、アプリにしても拡張機能にしてもVPN接続する度にIPアドレスが変わるので特に拡張機能なら<strong>定期的にブラウザ再起動</strong>すれば簡易的なIPローテーションを実現できます</p>



<h2 class="wp-block-heading"><span id="toc12">まとめ</span></h2>



<p>個人的にはスクレイピングするときによく使う<a rel="nofollow noopener noreferrer" target="_blank" href="https://px.a8.net/svt/ejp?a8mat=45GC5K+2HB32A+3YFI+674EQ">NordVPN</a>
<img decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=45GC5K+2HB32A+3YFI+674EQ" alt="">のご紹介でした</p>



<p>他にも利用しているVPNサービスがありますので順次紹介していきます</p>
]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/nordvpn-guide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Python】Seleniumの基本操作はラップしよ</title>
		<link>https://javeo.jp/selenium-wrapper/</link>
					<comments>https://javeo.jp/selenium-wrapper/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Sun, 28 Sep 2025 07:49:00 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Selenium]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=3604</guid>

					<description><![CDATA[目次 前提内部関数たちdriverのオープンとクローズページ読み込み完了の検知ページ遷移文字入力情報（文字や要素の値）を取得クリックするプルダウンから選ぶ画面を少しずつスクロールあとがき 前提 後続のプログラムは下記前提 [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<div class="wp-block-cocoon-blocks-info-box block-box primary-box">
<p>ブラウザ操作と言えばのSeleniumですが、便利だけど絶妙に使いにくくないですか？</p>



<p>素直に使おうとするとブラウザ処理をPythonの処理が追い越してしまってエラーになるなんてよくある話</p>



<p>そんな悩みを解決するためにもラッパーを作って快適に利用したいね、ってことて最近個人的に作ってみたラッパーのご紹介です</p>



<p>素人作りなのでそのまま使うと言うよりこれらをベースにいい感じに改良してくれれば（そしてコメントで教えてくれると嬉しいです）</p>
</div>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-6" checked><label class="toc-title" for="toc-checkbox-6">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">前提</a></li><li><a href="#toc2" tabindex="0">内部関数たち</a></li><li><a href="#toc3" tabindex="0">driverのオープンとクローズ</a></li><li><a href="#toc4" tabindex="0">ページ読み込み完了の検知</a></li><li><a href="#toc5" tabindex="0">ページ遷移</a></li><li><a href="#toc6" tabindex="0">文字入力</a></li><li><a href="#toc7" tabindex="0">情報（文字や要素の値）を取得</a></li><li><a href="#toc8" tabindex="0">クリックする</a></li><li><a href="#toc9" tabindex="0">プルダウンから選ぶ</a></li><li><a href="#toc10" tabindex="0">画面を少しずつスクロール</a></li><li><a href="#toc11" tabindex="0">あとがき</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">前提</span></h2>



<p>後続のプログラムは下記前提で作成していますので</p>



<p>classと__init__などの初期値は下記の通り</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>import logging
import time
import os
import sys
import atexit
from typing import Optional, Callable
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait, Select
from enum import Enum


# selectをわかりやすくするだけ
class SelectBy(Enum):
    Index = &#39;index&#39;
    Value = &#39;value&#39;
    VisibleText = &#39;visible_text&#39;

class SeleniumWrapper:
    def __init__(self, timeout=10, log_level=logging.INFO):
        # ログ設定
        logging.basicConfig(
            format=&#39;[%(asctime)s] %(levelname)s: %(message)s&#39;,
            level=log_level
        )
        self.logger = logging.getLogger(__name__)
        self.timeout = timeout
        self.logger.info(&quot;SeleniumWrapper initialized&quot;)
        self.selenium_flg = False
        atexit.register(self.driver_close) </code></pre></div>



<h2 class="wp-block-heading"><span id="toc2">内部関数たち</span></h2>



<p></p>



<ul class="wp-block-list">
<li>対象の要素を画面の中央に持ってくる（_scroll_to_center）</li>



<li>Timeoutの値チェック（_resolve_timeout）</li>



<li>クリック処理をSeleniumでエラーになったときjsでもう一回試みる（_safe_click）</li>



<li>WebElementをIndex指定で取得する（_get_element_by_index）</li>
</ul>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>    def _scroll_to_center(self, element: WebElement) -&gt; bool:
        &#39;&#39;&#39;
        memo:
        -----------
        - jsで指定の要素を画面中央にする
        &#39;&#39;&#39;
        try:
            self.driver.execute_script(&quot;arguments[0].scrollIntoView({ behavior: &#39;smooth&#39;, block: &#39;center&#39; });&quot;, element)
            # 最後に画面表示確認する
            self.selenium_wait(condition=EC.element_to_be_clickable(element))
        except Exception as e:
            self.logger.error(f&#39;[ScrollError] Failed to scroll element: {str(e)}&#39;, exc_info=True)
            return False
        return True

    def _resolve_timeout(self, timeout: float) -&gt; float:
        &#39;&#39;&#39;
        memo:
        -----------
        - タイムアウトを引数初期値（-1）ならinitの値にする
        &#39;&#39;&#39;
        return timeout if timeout != -1 else self.timeout

    def _safe_click(self, element: WebElement) -&gt; bool:
        &#39;&#39;&#39;
        memo:
        -----------
        - selenium標準のclickが失敗したらjsでクリックをする2段構えclick
        &#39;&#39;&#39;
        try:
            element.click()
        except Exception as e:
            try:
                self.driver.execute_script(&#39;arguments[0].click();&#39;, element)
            except Exception as e2:
                self.logger.error(f&#39;[ClickError] JS click failed: {str(e2)}&#39;, exc_info=True)
                return False
        return True

    def _get_element_by_index(self, css_selector: str, idx: int = 0, timeout: float = -1) -&gt; Optional[WebElement]:
        &#39;&#39;&#39;
        Parameters:
        -----------
        css_selector:遷移先のURL
        timeout:WebDriverWaitの最大待機秒数
        condition:expected_conditions

        memo:
        -----------
        - elementをidx指定で取得するのでEC.presence_of_all_elements_locatedを使う
        - css_selectorがconditionの状態になるまで待機
        &#39;&#39;&#39;
        timeout = self._resolve_timeout(timeout)
        try:
            elements = WebDriverWait(self.driver, timeout).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, css_selector)))
            if len(elements) &lt;= idx:
                self.logger.warning(f&#39;[NoSuchElement] selector={css_selector}, index={idx}&#39;)
                return None
        except TimeoutException:
            self.logger.warning(f&#39;[Timeout] selector={css_selector}, timeout={timeout}&#39;)
            return None
        except Exception as e:
            self.logger.error(f&#39;[Exception] selector={css_selector}, index={idx}, error={str(e)}&#39;, exc_info=True)
            return None
        return elements[idx]</code></pre></div>



<h2 class="wp-block-heading"><span id="toc3">driverのオープンとクローズ</span></h2>



<p>兎にも角にもchromedriverを動かさないと話にならないので</p>



<p>オプションはかなりの量があるのでお好みでカスタマイズを</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>    def driver_open(self, headless: bool = False) -&gt; None:
        &#39;&#39;&#39;
        Parameters:
        -----------
        headless:ヘッドレスモードで実行するか

        memo:
        -----------
        - chromedriverを起動する
        - なるべくchromedriver感を隠す
        &#39;&#39;&#39;
        options = Options()
        ##### 共通オプション
        options.add_argument(&#39;--start-maximized&#39;)                                   # 初期のウィンドウ最大化
        options.add_argument(&quot;--disable-blink-features=AutomationControlled&quot;)       # navigator.webdriver=false となる設定。確認⇒　driver.execute_script(&quot;return navigator.webdriver&quot;)
        options.add_experimental_option(&quot;excludeSwitches&quot;, [&quot;enable-automation&quot;])   # Chromeは自動テスト ソフトウェア~~　を非表示
        prefs = {
            &quot;credentials_enable_service&quot;: False,                                    # パスワード保存のポップアップを無効
            &quot;download_bubble.partial_view_enabled&quot;: False,                          # ダウンロードが完了したときの通知(吹き出し/下部表示)を無効にする。
            &quot;plugins.always_open_pdf_externally&quot;: True,                             # Chromeの内部PDFビューアを使わない(＝URLにアクセスすると直接ダウンロードされる)
        }
        ##### 引数で指定するオプション
        # ダウンロード先フォルダが指定されてればフォルダを作ってパラメータを追加する
        # ヘッドレスモードの判定
        if headless is True:
            options.add_argument(&#39;--headless=new&#39;) 
        options.add_experimental_option(&quot;prefs&quot;, prefs)
        service = Service()
        service.creation_flags = 0x08000000                                         # ヘッドレスモードで DevTools listening on ws:~~ を表示させない
        self.driver = webdriver.Chrome(service=service, options=options)
        self.driver.maximize_window()
        self.selenium_flg = True
        self.logger.info(&quot;WebDriver started&quot;)

    def driver_close(self):
        &#39;&#39;&#39;
        chromedriverを終わらせる処理
        &#39;&#39;&#39;
        self.logger.info(&quot;Quitting WebDriver&quot;)
        if self.selenium_flg:
            try:
                self.driver.close()
                self.driver.quit()
            except Exception:
                pass
        self.selenium_flg = False</code></pre></div>



<h2 class="wp-block-heading"><span id="toc4">ページ読み込み完了の検知</span></h2>



<p>全ての動作に入れるべき処理がこれ</p>



<p>動的ページが当然なのでjsの完了を検知してあげたり、要素の出現や変化を検知してあげる必要があります</p>



<p>さらに、、、理屈は分かりませんが、明示的な待機をしても低確率でPython側の処理が先行する謎事象が発生するので固定でほんの少しだけ待機してあげると安定します</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="selenium_wait" data-lang="Python"><code>    def selenium_wait(self, condition: Any = EC.presence_of_element_located((By.CSS_SELECTOR, &#39;body&#39;)),
                      timeout: float = 10.0, 
                      final_wait_time: float = COMMON_WAIT_SECONDS                      
                     ) -&gt; bool:
        &#39;&#39;&#39;
        Parameters:
        -----------
        condition:expected_conditions ※指定がなければbodyがあることを確認する
        timeout:WebDriverWaitの最大待機秒数
        final_wait_time:最後にsleepする秒数

        memo:
        -----------
        - getだけじゃなくclickとかの後でも使えるようにwait部分だけの関数にする
        &#39;&#39;&#39;
        timeout = self._resolve_timeout(timeout=timeout)
        try:
            # JavaScriptを使ってページ全体が読み込まれるまで待機
            wait = WebDriverWait(self.driver, timeout)
            # JavaScriptの読み込み完了を待つ
            wait.until(lambda d: d.execute_script(&quot;return document.readyState&quot;) == &quot;complete&quot;)
            # ロード完了後に指定のCSSが読み込まれたか確認する ※初期値のbodyはさすがにあるでしょ
            wait.until(condition)
            # 最後に無条件待機を入れる
            time.sleep(final_wait_time)
        except Exception as e:
            # おそらく発生しないException
            self.logger.error(f&#39;[WaitError] Failed during wait: {str(e)}&#39;, exc_info=True)
            return False
        return True</code></pre></div>



<h2 class="wp-block-heading"><span id="toc5">ページ遷移</span></h2>



<p>わざわざ関数にする必要あるのかって気もしますが・・・</p>



<p>getの後に先ほどのselenium_waitをしてあげるだけ</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="selenium_page_load" data-lang="Python"><code>    def selenium_page_load(self, url: str, condition: Any = EC.presence_of_element_located((By.CSS_SELECTOR, &#39;body&#39;)), timeout: float = 10.0, final_wait_time: float = COMMON_WAIT_SECONDS) -&gt; bool:
        &#39;&#39;&#39;
        Parameters:
        -----------
        url:遷移先のURL
        timeout:WebDriverWaitの最大待機秒数
        final_wait_time:最後にsleepする秒数
        load_completion_css:読み込み完了を認知するCSS
        condition:expected_conditions

        memo:
        -----------
        - 結局selenium_waitの前にgetしているだけだけど一番頻度が高いので個別に関数化する
        &#39;&#39;&#39;
        try:
            self.driver.get(url=url)
            self.selenium_wait(condition=condition, timeout=timeout, final_wait_time=final_wait_time)
        except Exception:
            return False
        return True</code></pre></div>



<h2 class="wp-block-heading"><span id="toc6">文字入力</span></h2>



<p>Seleniumで文字入力をするsend_keyは追記処理なので一度クリアする必要があるのと、入力完了後にjs発火が前提のWebサイトがあるので前後処理が大事</p>



<p>あとはタグを&#8221;input&#8221; or &#8220;textarea&#8221;でチェックしていますがイレギュラーがあったら修正するかも</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="selenium_input" data-lang="Python"><code>    def selenium_input(self, target: Union[str, WebElement], idx: int = 0, value: str = &#39;&#39;, timeout: float = -1.0) -&gt; bool:
        &#39;&#39;&#39;
        Parameters:
        -----------
        target: CSSセレクタ（str）または WebElement
        idx: セレクタで複数要素がある場合のインデックス
        value: 入力する文字列
        timeout: タイムアウト秒数

        memo:
        -----------
        - targetがstrなら要素取得して入力、WebElementならそのまま入力
        &#39;&#39;&#39;
        timeout = self._resolve_timeout(timeout=timeout)
        # 要素取得
        element: Optional[WebElement] = None
        if isinstance(target, str):
            element = self._get_element_by_index(target, idx, timeout)
        elif isinstance(target, WebElement):
            element = target
        else:
            self.logger.error(f&#39;[InputError] Invalid target type: {type(target)}&#39;)
            return False

        # 要素が見つからなかった場合はFalseを返す
        if element is None:
            return False

        try:
            # 入力可能状態まで待機
            self.selenium_wait(condition=EC.element_to_be_clickable(element), timeout=timeout)

            # タグチェック
            if element.tag_name not in [&#39;input&#39;, &#39;textarea&#39;]:
                self.logger.error(f&#39;[InputError] Invalid tag for input: {element.tag_name}&#39;)
                return False

            # jsで要素を画面中央にスクロール
            self._scroll_to_center(element)
            # 一旦クリアして念のためクリックして入力
            element.clear()
            element.click()
            time.sleep(COMMON_WAIT_SECONDS)
            element.send_keys(value)
            # 入力後にTabキーを送ってフォーカスを外す
            element.send_keys(Keys.TAB)
            time.sleep(COMMON_WAIT_SECONDS)

        except TimeoutException:
            self.logger.error(f&#39;[Timeout] Element not clickable for input: timeout={timeout}&#39;)
            return False
        except Exception as e:
            self.logger.error(f&#39;[Exception] Error in selenium_input: {str(e)}&#39;, exc_info=True)
            return False
        return True</code></pre></div>



<h2 class="wp-block-heading"><span id="toc7">情報（文字や要素の値）を取得</span></h2>



<p>個人的には情報取得部分はBeautifulsoupでやることが多いのであまりSeleniumでは利用頻度低いのですが、、基本操作だろうということでこれも</p>



<p>利用シーンとして文字取得が主になりますが、属性の値を取得することもあると思うので属性を指定できつつ、初期値はtext or valueの値を指定しているので使い勝手は悪くないはず</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="selenium_get" data-lang="Python"><code>    def selenium_get(self, target: Union[str, WebElement], idx: int = 0, att: str = &#39;text_or_value&#39;, timeout: float = -1.0,  default_value: str = &#39;&#39;) -&gt; str:
        &#39;&#39;&#39;
        Parameters:
        -----------
        target: CSSセレクタ（str）または WebElement
        idx:インデックスの指定が必要な場合 ※初期値は0
        att:取得する対象 ※textかattributeに指定する値
        timeout:タイムアウトまでの秒数 ※初期値は別途設定
        default_value: elementが見つからなかった時の返値

        memo:
        -----------
        - 文字だけでなく指定要素の値も取得できるようにする
        - hidden要素の取得もあるのでpresence_of_element_locatedを使う
        - 要素がない時は引数で制御して初期値空白を返すようにしている
        &#39;&#39;&#39;
        timeout = self._resolve_timeout(timeout=timeout)
        # 要素取得
        element: Optional[WebElement] = None
        if isinstance(target, str):
            element = self._get_element_by_index(target, idx, timeout)
        elif isinstance(target, WebElement):
            element = target
        else:
            self.logger.error(f&#39;[InputError] Invalid target type: {type(target)}&#39;)
            return default_value

        # 要素が見つからなかった場合はdefault_valueを返す
        if element is None:
            return default_value                

        try:
            # 引数の属性に合わせて取得
            ret: str
            if att == &#39;text_or_value&#39;:
                # textが空ならvalueを返す
                ret = element.text.strip()
                if not ret:
                    ret = str(element.get_attribute(&#39;value&#39;)).strip()
            elif att == &#39;text&#39;:
                # 明示的にtextが指定された場合はtextしか確認しない
                ret = element.text.strip()
            else:
                # text以外はattの指定にする
                ret = str(element.get_attribute(att)).strip()
        
        except Exception as e:
            self.logger.error(f&#39;[GetError] Failed to get attribute {att}: {str(e)}&#39;, exc_info=True)
            return default_value
        return ret</code></pre></div>



<h2 class="wp-block-heading"><span id="toc8">クリックする</span></h2>



<p>Seleniumでクリックするには画面上に対象要素がないとエラーになるので事前に画面スクロールしてあげる必要があります</p>



<p>あとは稀にSeleniumのクリックが謎エラーになることがあるのでSelenium標準クリックで失敗したら念のためjsでクリック処理をもう一度してみる2段階構造</p>



<p>ボタン、ラジオ、チェックボックスなどクリック処理は全てこれでOKだけどis_selectedとかでで現在状態を事前チェックしてあげたほうがベターかも</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="selenium_click" data-lang="Python"><code>    def selenium_click(self, target: Union[str, WebElement], idx: int = 0, timeout: float = -1.0) -&gt; bool:
        &#39;&#39;&#39;
        Parameters:
        -----------
        target: CSSセレクタ（str）または WebElement
        idx:インデックスの指定が必要な場合 ※初期値は0
        timeout:タイムアウトまでの秒数 ※初期値は別途設定

        memo:
        -----------
        - クリックするため事前に画面中央に移動してクリックする
        - seleniumのクリックが失敗したらjsでクリックするように内部関数を呼び出す
        &#39;&#39;&#39;
        timeout = self._resolve_timeout(timeout=timeout)
        # 要素取得
        element: Optional[WebElement] = None
        if isinstance(target, str):
            element = self._get_element_by_index(target, idx, timeout)
        elif isinstance(target, WebElement):
            element = target
        else:
            self.logger.error(f&#39;[InputError] Invalid target type: {type(target)}&#39;)
            return False

        # 要素が見つからなかった場合はFalseを返す
        if element is None:
            return False          

        try:
            # clickしようとしてるから element_to_be_clickable を使う
            self.selenium_wait(condition=EC.element_to_be_clickable(element), timeout=timeout)
        except TimeoutException:
            self.logger.warning(f&#39;[Timeout] Element not clickable: tag={element.tag_name}, timeout={timeout}&#39;)
            return False
        except Exception as e:
            # おそらく発生しないException
            self.logger.error(f&#39;[Exception] Unexpected error in selenium_click_elm: {str(e)}&#39;, exc_info=True)
            return False

        # jsで要素を画面中央にスクロール
        self._scroll_to_center(element=element)
        # clickでエラーになったらjsを試してみる
        return self._safe_click(element)</code></pre></div>



<h2 class="wp-block-heading"><span id="toc9">プルダウンから選ぶ</span></h2>



<p>条件選択をする際によく利用するプルダウンの変更もSeleniumで操作できます</p>



<p>index、value、textのいずれかで指定できますがtextがわかりやすい気がします</p>



<p>指定を誤らないように事前準備していた列挙型の&#8221;SelectBy&#8221;で制御してあげるとこがポイント</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="selenium_select" data-lang="Python"><code>    def selenium_select(self, target: Union[str, WebElement], idx: int = 0, select_by: SelectBy = SelectBy.VisibleText, value: str = &#39;&#39;, timeout: float = -1.0) -&gt; bool:
        &#39;&#39;&#39;
        Parameters:
        -----------
        target: CSSセレクタ（str）または WebElement
        idx:インデックスの指定が必要な場合 ※初期値は0
        select_by: select_byの値
        value: select_byで指定した値
        timeout:タイムアウトまでの秒数 ※初期値は別途設定

        memo:
        -----------
        入力可能状態まで待機するのでelement_to_be_clickableを使う
        &#39;&#39;&#39;
        timeout = self._resolve_timeout(timeout=timeout)
        # 要素取得
        element: Optional[WebElement] = None
        if isinstance(target, str):
            element = self._get_element_by_index(target, idx, timeout)
        elif isinstance(target, WebElement):
            element = target
        else:
            self.logger.error(f&#39;[InputError] Invalid target type: {type(target)}&#39;)
            return False

        # 要素が見つからなかった場合はFalseを返す
        if element is None:
            return False

        # selectタグ以外は使わないはず ※select以外で正常タグを見つけたときは修正する
        if element.tag_name != &#39;select&#39;:
            self.logger.error(f&#39;[SelectError] Invalid tag for select: {element.tag_name}&#39;)
            return False

        # jsで要素を画面中央にスクロール
        self._scroll_to_center(element=element)

        # 選択可能状態まで待機
        self.selenium_wait(condition=EC.element_to_be_clickable(element))

        # ここから正常時の操作
        select = Select(element)
        try:
            # 引数のselect_byに合わせて選択
            match select_by:
                case SelectBy.Index:
                    select.select_by_index(int(value))
                case SelectBy.Value:
                    select.select_by_value(str(value))
                case SelectBy.VisibleText:
                    select.select_by_visible_text(str(value))
                case _:
                    self.logger.error(f&quot;[SelectError] Invalid select_by value: {select_by}&quot;)
                    return False

        except ValueError as e:
            self.logger.error(f&quot;[SelectError] ValueError during selection by {select_by.name}: {e}&quot;)
            return False

        except Exception as e:
            self.logger.error(f&quot;[SelectError] Failed to select option by {select_by.name}: {e}&quot;, exc_info=True)
            return False

        time.sleep(COMMON_WAIT_SECONDS)
        return True</code></pre></div>



<h2 class="wp-block-heading"><span id="toc10">画面を少しずつスクロール</span></h2>



<p>WEBサイトによってはlazyなどで遅延読み込みされる仕様になっていることがあるのでスクロースして要素を全て表示させる処理</p>



<p>必要になるシーンは多くはないですがあれば便利</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>    def window_scroll(self, step: int=10, delay: float=0.1):
        &#39;&#39;&#39;
        js対応のためにゆっくり画面を一番下にスクロールする
        &#39;&#39;&#39;
        try:
            top = 1
            last_height = self.driver.execute_script(&#39;return document.body.scrollHeight&#39;)
            while top &lt; last_height:
                top = top + step
                self.driver.execute_script(f&#39;window.scrollBy(0, &quot;{str(step)}&quot;)&#39;)
                last_height = self.driver.execute_script(&#39;return document.body.scrollHeight&#39;)
                time.sleep(delay)
        except Exception as e:
            self.logger.error(f&#39;[ScrollError] Failed during window scroll: {str(e)}&#39;, exc_info=True)</code></pre></div>



<h2 class="wp-block-heading"><span id="toc11">あとがき</span></h2>



<p>Seleniumがあればブラウザ関係はなんでもできるんですが、標準機能だけで戦うにはちょっと足りないので冒頭の繰り返しになりますがラッパーを準備しておくことはかなり重要かと</p>



<p>クラウドワークスでRPA/スクレイピングツール作成の案件を多く受注しているので定期的にアップデートしたいと思います</p>
]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/selenium-wrapper/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【VBA】VBAでもWebDriverWaitを使いたい</title>
		<link>https://javeo.jp/vba-webdriverwait/</link>
					<comments>https://javeo.jp/vba-webdriverwait/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Sun, 07 Sep 2025 14:44:23 +0000</pubDate>
				<category><![CDATA[VBA・Excel]]></category>
		<category><![CDATA[EXCEL]]></category>
		<category><![CDATA[Selenium]]></category>
		<category><![CDATA[SeleniumBasic]]></category>
		<category><![CDATA[VBA]]></category>
		<category><![CDATA[スクレイピング]]></category>
		<category><![CDATA[マクロ]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=3569</guid>

					<description><![CDATA[目次 待機処理が必要な理由WebDriverWaitクラスでできることVBA版WebDriverWaitの実装例使い方サンプルまとめ 待機処理が必要な理由 SeleniumでWebサイトを操作するときにありがちな内容がこ [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<div class="wp-block-cocoon-blocks-info-box block-box primary-box">
<p>PythonでSeleniumを利用するときに利用必須ともいえるWebDriverWaitとexpected_conditionsですが、残念ながらVBAにはありません</p>



<p>この記事では、<strong>VBAでWebDriverWait</strong>+expected_conditions<strong>を再現するクラス</strong>を作り、有用な待機処理を実現します</p>



<p>※Pythonの場合はこちらをどうぞ</p>



<figure class="wp-block-embed is-type-wp-embed is-provider-excel-python wp-block-embed-excel-python"><div class="wp-block-embed__wrapper">

<a rel="noopener follow noreferrer" target="_blank" href="https://javeo.jp/python_wait/" title="【Python】Seleniumの待機処理はWebDriverWaitを使おう" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="320" height="198" src="https://javeo.jp/wp-content/uploads/2023/07/python-320x198.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://javeo.jp/wp-content/uploads/2023/07/python-320x198.png 320w, https://javeo.jp/wp-content/uploads/2023/07/python-240x148.png 240w, https://javeo.jp/wp-content/uploads/2023/07/python-640x396.png 640w" sizes="(max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【Python】Seleniumの待機処理はWebDriverWaitを使おう</div><div class="blogcard-snippet internal-blogcard-snippet">PythonのSeleniumには条件を満たすまで待機する便利なWebDriverWaitがあります。ですが実質的に重要なのはexpected_conditionsの方でこちらの詳細をまとめてみました。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://javeo.jp" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">javeo.jp</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2025.09.22</div></div></div></div></a>
</div></figure>
</div>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-8" checked><label class="toc-title" for="toc-checkbox-8">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">待機処理が必要な理由</a></li><li><a href="#toc2" tabindex="0">WebDriverWaitクラスでできること</a></li><li><a href="#toc3" tabindex="0">VBA版WebDriverWaitの実装例</a></li><li><a href="#toc4" tabindex="0">使い方サンプル</a></li><li><a href="#toc5" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">待機処理が必要な理由</span></h2>



<p>SeleniumでWebサイトを操作するときにありがちな内容がこちら</p>



<ul class="wp-block-list">
<li>ページロードが完了していないうちに要素を取得してエラー</li>



<li>JavaScriptで動的に生成されるボタンや入力欄がまだ非表示</li>



<li>ボタンが表示されてもクリック可能になる前に操作しようとしてエラー</li>
</ul>



<p>これらを解決するには「要素が存在する・表示される・有効になる」まで待機処理が必要です</p>



<h2 class="wp-block-heading"><span id="toc2">WebDriverWaitクラスでできること</span></h2>



<p>今回作ったVBAクラス <code>WebDriverWait</code> は、PythonのWebDriverWaitに近い操作性で以下の条件を待機できます</p>



<figure class="wp-block-table"><div class="scrollable-table"><table><thead><tr><th>メソッド</th><th>説明</th></tr></thead><tbody><tr><td><code>UntilPresence(By)</code></td><td>DOM上に指定した <code>By</code> が存在するまで待機</td></tr><tr><td><code>UntilVisibleLocated(By)</code></td><td>画面上に <code>By</code> で指定した要素が表示されるまで待機 (<code>IsDisplayed</code>)</td></tr><tr><td><code>UntilVisible(element)</code></td><td>指定した <code>WebElement</code> が表示されるまで待機</td></tr><tr><td><code>UntilEnableLocated(By)</code></td><td>画面上に <code>By</code> で指定した要素が利用可能になるまで待機 (<code>IsDisplayed &amp; IsEnabled</code>)</td></tr><tr><td><code>UntilEnable(element)</code></td><td>指定した <code>WebElement</code> が利用可能になるまで待機</td></tr></tbody></table></div></figure>



<p>ポイント：</p>



<ul class="wp-block-list">
<li>成功時は <code>WebElement</code> を返す</li>



<li>タイムアウト時は <code>Nothing</code> を返す</li>



<li>Pythonのように例外処理に頼らずVBAらしい安全な設計</li>
</ul>



<h2 class="wp-block-heading"><span id="toc3">VBA版WebDriverWaitの実装例</span></h2>



<p>以下のクラスモジュールをVBAに追加してください※クラス名は <strong><code>WebDriverWait</code></strong> にしています</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/09/image.jpg"><img decoding="async" width="1024" height="538" src="https://javeo.jp/wp-content/uploads/2025/09/image-1024x538.jpg" alt="" class="wp-image-3570" srcset="https://javeo.jp/wp-content/uploads/2025/09/image-1024x538.jpg 1024w, https://javeo.jp/wp-content/uploads/2025/09/image-300x158.jpg 300w, https://javeo.jp/wp-content/uploads/2025/09/image-150x79.jpg 150w, https://javeo.jp/wp-content/uploads/2025/09/image-768x403.jpg 768w, https://javeo.jp/wp-content/uploads/2025/09/image.jpg 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<div class="wp-block-cocoon-blocks-toggle-box-1 toggle-wrap toggle-box block-box not-nested-style cocoon-block-toggle"><input id="toggle-checkbox-202509242213270" class="toggle-checkbox" type="checkbox"/><label class="toggle-button" for="toggle-checkbox-202509242213270">プログラムを見る</label><div class="toggle-content">
<div class="hcb_wrap"><pre class="prism undefined-numbers lang-vba" data-file="WebDriverWait " data-lang="Visual Basic + VBA"><code>&#39;--- クラス名: WebDriverWait ---
Option Explicit
&#39;====================================================================================================
&#39; PythonのWebDriverWaitの一部を再現したクラス
&#39; ※条件に合致した場合はWebElementを返して一致しなかった場合はNothingを返す
&#39;   - UntilPresenceeLocated・DOM上に指定したelementが表示されるまで待機は発生し得ないから準備していない
&#39;   - UntilPresence・・・・・DOM上に指定したByが表示されるまで待機
&#39;   - UntilVisibleLocated・・画面上に指定したelementが表示されるまで待機（IsDisplayed）
&#39;   - UntilVisible ・・・・・画面上に指定したByが表示されるまで待機（IsDisplayed）
&#39;   - UntilEnableLocated・・画面上に指定したelementが利用できるまで待機（IsDisplayed & IsEnabled）
&#39;   - UntilEnable ・・・・・画面上に指定したByが利用できるまで待機（IsDisplayed & IsEnabled）
&#39;====================================================================================================
Private pDriver As Selenium.WebDriver
Private pTimeout As Double
Private pInterval As Double

Public Sub Init(driver As Selenium.WebDriver, Optional timeoutSeconds As Double = 10, Optional intervalSeconds As Double = 0.5)
    Set pDriver = driver
    pTimeout = timeoutSeconds
    pInterval = intervalSeconds
End Sub

&#39; Presence
Public Function UntilPresence(By As Selenium.By) As Selenium.WebElement
    Dim start As Double: start = Timer
    Dim elem As Selenium.WebElement
    
    Do
        On Error Resume Next
        Set elem = pDriver.FindElement(By)
        On Error GoTo 0
        
        If Not elem Is Nothing Then
            Set UntilPresence = elem
            Exit Function
        End If
        
        DoEvents
        Application.wait Now + TimeSerial(0, 0, pInterval)
    Loop While Timer - start &lt; pTimeout
    
    Set UntilPresence = Nothing
End Function

&#39; Visibility (By指定)
Public Function UntilVisibleLocated(By As Selenium.By) As Selenium.WebElement
    Dim start As Double: start = Timer
    Dim elem As Selenium.WebElement
    
    Do
        On Error Resume Next
        Set elem = pDriver.FindElement(By)
        On Error GoTo 0
        
        If Not elem Is Nothing Then
            If elem.IsDisplayed Then
                Set UntilVisibleLocated = elem
                Exit Function
            End If
        End If
        
        DoEvents
        Application.wait Now + TimeSerial(0, 0, pInterval)
    Loop While Timer - start &lt; pTimeout
    
    Set UntilVisibleLocated = Nothing
End Function

&#39; Visibility (element指定)
Public Function UntilVisible(elem As Selenium.WebElement) As Selenium.WebElement
    Dim start As Double: start = Timer
    
    Do
        If Not elem Is Nothing Then
            If elem.IsDisplayed Then
                Set UntilVisible = elem
                Exit Function
            End If
        End If
        
        DoEvents
        Application.wait Now + TimeSerial(0, 0, pInterval)
    Loop While Timer - start &lt; pTimeout
    
    Set UntilVisible = Nothing
End Function

&#39; Enable (By指定)
Public Function UntilEnableLocated(By As Selenium.By) As Selenium.WebElement
    Dim start As Double: start = Timer
    Dim elem As Selenium.WebElement
    
    Do
        On Error Resume Next
        Set elem = pDriver.FindElement(By)
        On Error GoTo 0
        
        If Not elem Is Nothing Then
            If elem.IsDisplayed And elem.IsEnabled Then
                Set UntilEnableLocated = elem
                Exit Function
            End If
        End If
        
        DoEvents
        Application.wait Now + TimeSerial(0, 0, pInterval)
    Loop While Timer - start &lt; pTimeout
    
    Set UntilEnableLocated = Nothing
End Function

&#39; Enable (element指定)
Public Function UntilEnable(elem As Selenium.WebElement) As Selenium.WebElement
    Dim start As Double: start = Timer
    
    Do
        If Not elem Is Nothing Then
            If elem.IsDisplayed And elem.IsEnabled Then
                Set UntilEnable = elem
                Exit Function
            End If
        End If
        
        DoEvents
        Application.wait Now + TimeSerial(0, 0, pInterval)
    Loop While Timer - start &lt; pTimeout
    
    Set UntilEnable = Nothing
End Function
</code></pre></div>
</div></div>



<h2 class="wp-block-heading"><span id="toc4">使い方サンプル</span></h2>



<p>このブログの練習用ページでテストできるようにしていますので自由にテストしてください</p>



<p>ポイントはInit部分で引数は下記の通りです</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-vba" data-lang="Visual Basic + VBA"><code>wait.Init driver, {最大待機秒数}, {判定間隔}</code></pre></div>



<div class="wp-block-cocoon-blocks-toggle-box-1 toggle-wrap toggle-box block-box not-nested-style cocoon-block-toggle"><input id="toggle-checkbox-202509242213271" class="toggle-checkbox" type="checkbox"/><label class="toggle-button" for="toggle-checkbox-202509242213271">プログラムを見る</label><div class="toggle-content">
<div class="hcb_wrap"><pre class="prism undefined-numbers lang-vba" data-lang="Visual Basic + VBA"><code>Sub test()
    Dim driver As New Selenium.ChromeDriver
    Dim By As New Selenium.By
    
    driver.Get &quot;https://javeo.jp/practice_scraping/&quot;

    Dim wait As New WebDriverWait
    wait.Init driver, 10, 0.5

    &#39; presence_of_element_located(By)
    Dim elemUser As Selenium.WebElement
    Set elemUser = wait.UntilPresence(By.Css(&quot;#input_test&quot;))
    

    &#39; visibility_of_element_located(By)
    Dim elemPass As Selenium.WebElement
    Set elemPass = wait.UntilVisibleLocated(By.Css(&quot;#textarea_test&quot;))

    &#39; element_to_be_clickable(By)
    Dim elemBtn As Selenium.WebElement
    Set elemBtn = wait.UntilClickableLocated(By.Css(&quot;[name=&quot;&quot;checkbox_test&quot;&quot;]&quot;))

    
    elemUser.SendKeys &quot;testuser&quot;
    elemPass.SendKeys &quot;secret&quot;
    elemBtn.Click
End Sub
</code></pre></div>
</div></div>



<h2 class="wp-block-heading"><span id="toc5">まとめ</span></h2>



<p>個人的にPythonでもSeleniumを使うのでWebDriverWaitが使えない不便さを感じていました</p>



<p>PythonとVBAでは思想も違うので適当にいじってますが、ほぼ同じように使えてスッキリです！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/vba-webdriverwait/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【VBA】VBA-JSON不要！VBAでChromedriverを自動更新</title>
		<link>https://javeo.jp/vba-chromedriver-auto-update-lite/</link>
					<comments>https://javeo.jp/vba-chromedriver-auto-update-lite/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Sun, 07 Sep 2025 13:09:12 +0000</pubDate>
				<category><![CDATA[VBA・Excel]]></category>
		<category><![CDATA[EXCEL]]></category>
		<category><![CDATA[Selenium]]></category>
		<category><![CDATA[SeleniumBasic]]></category>
		<category><![CDATA[VBA]]></category>
		<category><![CDATA[スクレイピング]]></category>
		<category><![CDATA[マクロ]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=3564</guid>

					<description><![CDATA[目次 やっていること必要な参照設定ファイルへの反映手順プロパティウィンドウを表示しておく標準モジュールを追加モジュール名を変更するプログラムの使い方Chromedriverの書き込み権限がない時サンプルファイル最後に実際 [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<div class="wp-block-cocoon-blocks-info-box block-box primary-box">
<p>以前に別で作成したVBAのChromedriver自動更新プログラムですが色々見直すと実はVBA-JSONなしでも十分ってことに気づいて別途作成しました</p>



<p>条件付きの簡略版ではありますのでご自身の環境に合わせて使い分けてください</p>



<figure class="wp-block-embed is-type-wp-embed is-provider-excel-python wp-block-embed-excel-python"><div class="wp-block-embed__wrapper">

<a rel="noopener follow noreferrer" target="_blank" href="https://javeo.jp/vba-chromedriver-auto-update/" title="【VBA】SeleniumBasicのchromedriverを自動更新する" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="320" height="198" src="https://javeo.jp/wp-content/uploads/2024/07/ExcelVBA-320x198.jpg" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://javeo.jp/wp-content/uploads/2024/07/ExcelVBA-320x198.jpg 320w, https://javeo.jp/wp-content/uploads/2024/07/ExcelVBA-240x148.jpg 240w, https://javeo.jp/wp-content/uploads/2024/07/ExcelVBA-640x396.jpg 640w" sizes="(max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【VBA】SeleniumBasicのchromedriverを自動更新する</div><div class="blogcard-snippet internal-blogcard-snippet">Pythonではよくあるchromedriverの自動更新をVBAで再現できるように独自に作成したプログラムを紹介します！私も利用しているのでより良くなるご指摘あればコメントお願いします</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://javeo.jp" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">javeo.jp</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2025.08.15</div></div></div></div></a>
</div></figure>
</div>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-10" checked><label class="toc-title" for="toc-checkbox-10">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">やっていること</a></li><li><a href="#toc2" tabindex="0">必要な参照設定</a></li><li><a href="#toc3" tabindex="0">ファイルへの反映手順</a><ol><li><a href="#toc4" tabindex="0">プロパティウィンドウを表示しておく</a></li><li><a href="#toc5" tabindex="0">標準モジュールを追加</a></li><li><a href="#toc6" tabindex="0">モジュール名を変更する</a></li><li><a href="#toc7" tabindex="0">プログラムの使い方</a></li></ol></li><li><a href="#toc8" tabindex="0">Chromedriverの書き込み権限がない時</a></li><li><a href="#toc9" tabindex="0">サンプルファイル</a></li><li><a href="#toc10" tabindex="0">最後に実際のソース</a></li><li><a href="#toc11" tabindex="0">あとがき</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">やっていること</span></h2>



<ol class="wp-block-list has-watery-yellow-background-color has-background">
<li>chromedriverの保存先は端末環境によって違うので候補となる3箇所のフォルダ有無を確認</li>



<li>chromeの保存先も端末環境によって違うので候補となる3箇所のフォルダ有無を確認</li>



<li>PowerShellでchromeのバージョンを取得する<br>※なので一瞬PowerShellの画面がチラつきます</li>



<li>APIでChrome.exeのビルドまで一致している最新chromedriverのダウンロードパスを取得</li>



<li>ダウンロードしたzipファイルを解凍してをseleniumbasic用のフォルダへコピーする</li>
</ol>



<p>以前作成したVBAはJSON API endpointsを総当たりで取得していたのでJSONをパースする必要がありましたが、APIでドライバのバージョンを直接取得できることに気づいて少し手順を簡略化できました</p>



<p>処理としては数秒しか変わりませんがVBA-JSOＮ不要になったのは個人的にGoodポイント</p>



<p class="is-style-information-box has-box-style">ここからは以前と同じことを書いてますが単独でこのページを見ていただいた方向けです</p>



<h2 class="wp-block-heading"><span id="toc2">必要な参照設定</span></h2>



<p>このプログラムを実行するために設定した参照設定</p>



<figure class="wp-block-image size-full"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2023/07/image-4.png"><img decoding="async" width="455" height="317" src="https://javeo.jp/wp-content/uploads/2023/07/image-4.png" alt="" class="wp-image-3282" srcset="https://javeo.jp/wp-content/uploads/2023/07/image-4.png 455w, https://javeo.jp/wp-content/uploads/2023/07/image-4-300x209.png 300w, https://javeo.jp/wp-content/uploads/2023/07/image-4-150x105.png 150w" sizes="(max-width: 455px) 100vw, 455px" /></a></figure>



<p>追加したのは下記3つ</p>



<ul class="wp-block-list has-watery-yellow-background-color has-background">
<li>Microsoft Scripting Runtime</li>



<li>Microsoft XML, v6.0</li>



<li>Selenium Type Library</li>
</ul>



<p>ここは旧バージョンと変わりありません</p>



<h2 class="wp-block-heading"><span id="toc3">ファイルへの反映手順</span></h2>



<p>サンプルファイルとソースは下部に準備していますがファイルへの反映方法がわからない方向けに反映と使い方です</p>



<p>そんなことわかってるからはよソースを！って方は<a href="#program-source" data-type="internal" data-id="#program-source">下部のソース</a>まで飛んじゃってください</p>



<h3 class="wp-block-heading"><span id="toc4">プロパティウィンドウを表示しておく</span></h3>



<p>あとからモジュール名を変更したいので、もし表示されていない時は表示しておく</p>



<div class="wp-block-cocoon-blocks-blank-box-1 blank-box block-box">
<p>ヘッダーメニュー：表示　→　プロパティウィンドウ　※F4がショートカットキー</p>
</div>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_44.png"><img decoding="async" width="1024" height="555" src="https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_44-1024x555.png" alt="" class="wp-image-1298" srcset="https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_44-1024x555.png 1024w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_44-300x163.png 300w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_44-150x81.png 150w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_44-768x416.png 768w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_44-1536x832.png 1536w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_44.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h3 class="wp-block-heading"><span id="toc5">標準モジュールを追加</span></h3>



<p>自動更新プログラム用にモジュールを追加する</p>



<div class="wp-block-cocoon-blocks-blank-box-1 blank-box block-box">
<p>ヘッダーメニュー：挿入　→　標準モジュール</p>
</div>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_54.png"><img decoding="async" width="1024" height="555" src="https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_54-1024x555.png" alt="" class="wp-image-1299" srcset="https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_54-1024x555.png 1024w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_54-300x163.png 300w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_54-150x81.png 150w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_54-768x416.png 768w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_54-1536x832.png 1536w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h03_54.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h3 class="wp-block-heading"><span id="toc6">モジュール名を変更する</span></h3>



<p>必須ではないんですが、わかりやすい運用のためにはモジュール名変更推奨です</p>



<p>今回は&#8221;<span class="marker-under">ChromeDriverAutoUpdateModule</span>&#8220;にします</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h05_04.png"><img decoding="async" width="1024" height="555" src="https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h05_04-1024x555.png" alt="" class="wp-image-1300" srcset="https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h05_04-1024x555.png 1024w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h05_04-300x163.png 300w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h05_04-150x81.png 150w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h05_04-768x416.png 768w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h05_04-1536x832.png 1536w, https://javeo.jp/wp-content/uploads/2023/08/2023-08-01_09h05_04.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h3 class="wp-block-heading"><span id="toc7">プログラムの使い方</span></h3>



<p>「<span class="marker-under">&lt;モジュール名&gt;.&lt;プロシージャ名&gt;()</span>  ※&#8221;&lt;モジュール名&gt;.&#8221;は省略可」でプログラムを呼び出せるので、本体プログラムの最初に「<span class="marker-under">ChromeDriverAutoUpdateModule.ChromeDriverAutoUpdate()</span>」を追加すれば必要なときにchromedriverが自動更新されます</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-vba" data-file="sample" data-lang="Visual Basic + VBA"><code>Sub main()
&#39;---Chromedriverの自動更新 ※別モジュールを参照
If ChromeDriverAutoUpdateModule.ChromeDriverAutoUpdate Then
    Exit Sub
End If

&#39;－－・－－・－－以下にプログラムを－－・－－・－－
End Sub</code></pre></div>



<h2 class="wp-block-heading"><span id="toc8">Chromedriverの書き込み権限がない時</span></h2>



<p>Winsows11からセキュリティ周りが厳しくなったのか管理者権限でSeleniumBasicをインストールした場合、Chromedriverを更新しようとすると書き込み権限なしエラーが発生するので対応まとめました</p>



<p>画像の通りですが下記手順で権限設定ができます</p>



<ol class="wp-block-list has-watery-blue-background-color has-background">
<li>&#8220;C:\Program Files&#8221;にある&#8221;SeleniumBasic&#8221;フォルダを右クリック</li>



<li>右クリックメニューで&#8221;プロパティ&#8221;をクリック</li>



<li>セキュリティタブに移って&#8221;編集&#8221;ボタンをクリック</li>



<li>&#8220;Users（{コンピュータ名}\Users）&#8221;をクリック</li>



<li>&#8220;フルコントロール&#8221;にチェックがついていないはずなのでクリックしてチェックを付ける</li>



<li>&#8220;適用&#8221;ボタンをクリック</li>
</ol>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2023/07/2025-08-01_08h03_25.png"><img decoding="async" width="1024" height="538" src="https://javeo.jp/wp-content/uploads/2023/07/2025-08-01_08h03_25-1024x538.png" alt="" class="wp-image-3175" srcset="https://javeo.jp/wp-content/uploads/2023/07/2025-08-01_08h03_25-1024x538.png 1024w, https://javeo.jp/wp-content/uploads/2023/07/2025-08-01_08h03_25-300x158.png 300w, https://javeo.jp/wp-content/uploads/2023/07/2025-08-01_08h03_25-150x79.png 150w, https://javeo.jp/wp-content/uploads/2023/07/2025-08-01_08h03_25-768x403.png 768w, https://javeo.jp/wp-content/uploads/2023/07/2025-08-01_08h03_25.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h2 class="wp-block-heading"><span id="toc9">サンプルファイル</span></h2>



<p>JSON-VBA含めて最低限のモジュールをセットしたファイル準備したので一から作る時のベースにしていただければ</p>





<h2 class="wp-block-heading" id="program-source"><span id="toc10">最後に実際のソース</span></h2>



<p>まずはGithubをご利用の方向けはこちら</p>




<a rel="noopener noreferrer" target="_blank" href="https://github.com/javeo2022/webdriver_manager_VBA_Lite" title="GitHub - javeo2022/webdriver_manager_VBA_Lite: SeleniumBasic用のVBAでChromeDriverを自動更新するためのプログラムです" class="blogcard-wrap external-blogcard-wrap a-wrap cf"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img decoding="async" src="https://opengraph.githubassets.com/4854569a2cb6dba2b1062d618348a7196c7ab09cc88bba2176029d9baee800f9/javeo2022/webdriver_manager_VBA_Lite" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="320" height="198" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">GitHub - javeo2022/webdriver_manager_VBA_Lite: SeleniumBasic用のVBAでChromeDriverを自動更新するためのプログラムです</div><div class="blogcard-snippet external-blogcard-snippet">SeleniumBasic用のVBAでChromeDrive...</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://github.com/javeo2022/webdriver_manager_VBA_Lite" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">github.com</div></div></div></div></a>



<p>例によってコピペ用はこちらです</p>



<div class="wp-block-cocoon-blocks-toggle-box-1 toggle-wrap toggle-box block-box not-nested-style cocoon-block-toggle"><input id="toggle-checkbox-202510131456140" class="toggle-checkbox" type="checkbox"/><label class="toggle-button" for="toggle-checkbox-202510131456140">ソースを見る</label><div class="toggle-content">
<div class="hcb_wrap"><pre class="prism undefined-numbers lang-vba" data-lang="Visual Basic + VBA"><code>Option Explicit
#If VBA7 Then
Private Declare PtrSafe Function URLDownloadToFile Lib &quot;urlmon&quot; Alias &quot;URLDownloadToFileA&quot; _
                        (ByVal pCaller As Long, _
                         ByVal szURL As String, _
                         ByVal szFileName As String, _
                         ByVal dwReserved As Long, _
                         ByVal lpfnCB As Long) As Long
Private Declare PtrSafe Function SHCreateDirectoryEx Lib &quot;shell32.dll&quot; Alias &quot;SHCreateDirectoryExA&quot; _
                        (ByVal hwnd As LongPtr, ByVal pszPath As String, ByVal psa As LongPtr) As Long
#Else
Private Declare Function URLDownloadToFile Lib &quot;urlmon&quot; Alias &quot;URLDownloadToFileA&quot; _
                        (ByVal pCaller As Long, _
                         ByVal szURL As String, _
                         ByVal szFileName As String, _
                         ByVal dwReserved As Long, _
                         ByVal lpfnCB As Long) As Long
Private Declare Function SHCreateDirectoryEx Lib &quot;shell32.dll&quot; Alias &quot;SHCreateDirectoryExA&quot; _
                        (ByVal hwnd As LongPtr, ByVal pszPath As String, ByVal psa As LongPtr) As Long
#End If

Private Type VersionType &#39;---本当はクラスオブジェクトにしたいけどこれだけのためにモジュール作りたくない
    Major As Long
    Minor As Long
    Build As Long
    Revision As Long
    BuildVersion As String
    RevisionVersion As String
End Type
Const ZIP_FILE As String = &quot;chromedriver.zip&quot;
Const DRIVER_EXE As String = &quot;chromedriver.exe&quot;
Dim workPath As String
Sub test()
Call ChromeDriverAutoUpdate
End Sub
Public Function ChromeDriverAutoUpdate(Optional ByVal ForcedExecution As Boolean = False) As Boolean
&#39;====================================================================================================
&#39;chrome.exeとchromedriver.exeのバージョンを比較してchromedriverを自動更新する
&#39;もしくは強制実行フラグ（ForcedExecution）がTrueでも実行する
&#39;====================================================================================================
    Dim chromePath As String &#39;---chrome.exeが保存されているパス
    Dim chromeFullpath As String &#39;---chrome.exeまで含めたフルパス
    Dim chromeVersion As VersionType
    Dim chromedriverPath As String
    Dim chromedriverFullPath As String
    Dim objFso As New Scripting.FileSystemObject
    &#39; ---chromedriverをダウンロード用のフォルダを作成する　※Seleniumのキャッシュ構造に合わせている
    workPath = Environ(&quot;USERPROFILE&quot;) & &quot;\.cache\selenium\seleniumbasic&quot;
    Select Case SHCreateDirectoryEx(0&, workPath, 0&)
        Case 0:
            &#39; ---作成成功
        Case 183
            &#39; ---作成済み
        Case Else:
            &#39; ---作成できなかった時
            MsgBox &quot;ダウンロード用フォルダを作成できませんでした&quot; & vbCrLf & Error(Err), vbCritical
            ChromeDriverAutoUpdate = False
            Exit Function
    End Select
    
    &#39;---chrome本体のフォルダを探す
    Select Case True
        Case objFso.FolderExists(Environ(&quot;LOCALAPPDATA&quot;) & &quot;\Google\Chrome\Application&quot;)
            chromePath = Environ(&quot;LOCALAPPDATA&quot;) & &quot;\Google\Chrome\Application&quot;
        Case objFso.FolderExists(Environ(&quot;ProgramW6432&quot;) & &quot;\Google\Chrome\Application&quot;)
            chromePath = Environ(&quot;ProgramW6432&quot;) & &quot;\Google\Chrome\Application&quot;
        Case objFso.FolderExists(Environ(&quot;ProgramFiles&quot;) & &quot;\Google\Chrome\Application&quot;)
            chromePath = Environ(&quot;ProgramFiles&quot;) & &quot;\Google\Chrome\Application&quot;
        Case Else
            MsgBox &quot;&#39;chrome&#39;フォルダが見つかりません&quot;, vbCritical
            ChromeDriverAutoUpdate = False
            Exit Function
    End Select
    
    &#39;---念のためchrome.exeを確認する
    If objFso.FileExists(chromePath & &quot;\chrome.exe&quot;) = True Then
        chromeFullpath = chromePath & &quot;\chrome.exe&quot;
    Else
        MsgBox &quot;&#39;chrome.exe&#39;が見つかりません&quot;, vbCritical
        Exit Function
    End If
    
    &#39;---SeleniumBasicのフォルダを探す
    Select Case True
        Case objFso.FolderExists(Environ(&quot;LOCALAPPDATA&quot;) & &quot;\SeleniumBasic&quot;)
            chromedriverPath = Environ(&quot;LOCALAPPDATA&quot;) & &quot;\SeleniumBasic&quot;
        Case objFso.FolderExists(Environ(&quot;ProgramW6432&quot;) & &quot;\SeleniumBasic&quot;)
            chromedriverPath = Environ(&quot;ProgramW6432&quot;) & &quot;\SeleniumBasic&quot;
        Case objFso.FolderExists(Environ(&quot;ProgramFiles&quot;) & &quot;\SeleniumBasic&quot;)
            chromedriverPath = Environ(&quot;ProgramFiles&quot;) & &quot;\SeleniumBasic&quot;
        Case Else
            MsgBox &quot;&#39;SeleniumBasic&#39;のフォルダが見つかりません&quot;, vbCritical
            ChromeDriverAutoUpdate = False
            Exit Function
    End Select
    
    &#39;---念のためchromedriver.exeを確認する
    If objFso.FileExists(chromedriverPath & &quot;\&quot; & DRIVER_EXE) = False Then
        Debug.Print &quot;&#39;chromedriver.exe&#39;が見つかりませんでした&quot;
    End If
    chromedriverFullPath = chromedriverPath & &quot;\&quot; & DRIVER_EXE
        
    &#39;---chrome.exeのバージョンを取得する
    If GetChromeVersion(chromeFullpath, chromeVersion) = False Then &#39;---chrome.exeのバージョンを取得する
        MsgBox &quot;&#39;chrome.exe&#39;のバージョンが取得できませんでした&quot;, vbCritical
        ChromeDriverAutoUpdate = False
        Exit Function
    End If
    
    &#39;---chrome.exeのバージョンに合わせたchromedriver.exeをダウンロードする
    If ChromedriverQuickCheck(chromedriverPath, chromeVersion) = False Then &#39;---chromedriverのバージョンを取得する
        MsgBox &quot;&#39;chromedriver.exe&#39;のバージョンが取得できませんでした&quot;, vbCritical
        ChromeDriverAutoUpdate = False
        Exit Function
    End If
    
    &#39;---結果として更新していない場合もあるが、更新失敗じゃなくて更新不要な判定だからTrueを返す
    ChromeDriverAutoUpdate = True
Exit Function
ErrLabel:     &#39;---予期せぬエラーの分岐
    MsgBox &quot;chromedriver の入替に失敗しました&quot; & vbCrLf & Error(Err) & vbCrLf & &quot;※この画面のキャプチャを作成者へ送ってください&quot;
    ChromeDriverAutoUpdate = False
End Function
Private Function GetChromeVersion(ByVal chromeFullpath As String, ByRef chromeVersion As VersionType) As Boolean
&#39;====================================================================================================
&#39;PowerShellでchrome.exeのバージョン情報を取得する　※一瞬PowerShellが立ち上がる
&#39;====================================================================================================
    Dim command As String
    Dim objRet As Object
    
    On Error GoTo ErrLabel
        &#39;---chromeバージョン情報の初期値
        chromeVersion.Major = 1
        chromeVersion.Minor = 0
        chromeVersion.Build = 0
        chromeVersion.Revision = 0
        &#39;---chrome.exeのバージョンを取得するPowerShellコマンド
        command = &quot;powershell.exe -NoProfile -ExecutionPolicy Bypass (Get-Item -Path &#39;&quot; & chromeFullpath & &quot;&#39;).VersionInfo.FileVersion&quot;
        &#39;---PowerShellの実行結果をセット
        Set objRet = CreateObject(&quot;WScript.Shell&quot;).Exec(command)
        &#39;---PowerShellのコマンドレットの実行結果を取得
        chromeVersion.RevisionVersion = Trim(objRet.StdOut.ReadAll)
        &#39;---情報の取得が終わったらオブジェクトをクリアする
        Set objRet = Nothing
        &#39;---改行コードが含まれているから削除する
        chromeVersion.RevisionVersion = Trim(Replace(Replace(Replace(chromeVersion.RevisionVersion, vbCrLf, vbNullString), vbCr, vbNullString), vbLf, vbNullString))
        &#39;---バージョン情報を分けて返す
        With CreateObject(&quot;VBScript.RegExp&quot;) &#39;---正規表現の準備
            .Pattern = &quot;\d+\.\d+\.\d+(\.\d+)?&quot;
            .Global = True
            If .test(chromeVersion.RevisionVersion) Then &#39;---念のため正規表現でバージョン情報をチェックする
                chromeVersion.Major = CLng(Split(chromeVersion.RevisionVersion, &quot;.&quot;)(0))
                chromeVersion.Minor = CLng(Split(chromeVersion.RevisionVersion, &quot;.&quot;)(1))
                chromeVersion.Build = CLng(Split(chromeVersion.RevisionVersion, &quot;.&quot;)(2))
                If UBound(Split(chromeVersion.RevisionVersion, &quot;.&quot;)) &gt;= 3 Then &#39;---リビジョン番号がなければ9999を仮でセット※基本あるはず
                    chromeVersion.Revision = CLng(Split(chromeVersion.RevisionVersion, &quot;.&quot;)(3))
                Else
                    chromeVersion.Revision = 9999
                End If
                chromeVersion.BuildVersion = Join(Array(chromeVersion.Major, chromeVersion.Minor, chromeVersion.Build), &quot;.&quot;) &#39;---リビジョンを覗いたショートバージョン情報をセットする
                Debug.Print &quot;Chromeのバージョン：&quot; & chromeVersion.RevisionVersion
            Else &#39;---正規表現不一致なら失敗で返す
                MsgBox &quot;chrome.exe のバージョン情報取得に失敗しました&quot; & vbCrLf & &quot;[取得バージョン情報：&quot; & chromeVersion.RevisionVersion & &quot;]&quot; & vbCrLf & &quot;※この画面のキャプチャを作成者へ送ってください&quot;
                GetChromeVersion = False
                Exit Function
            End If
        End With
        GetChromeVersion = True
    On Error GoTo 0
    Exit Function
ErrLabel:     &#39;---予期せぬエラーの分岐
    MsgBox &quot;chrome.exe のバージョン情報取得に失敗しました&quot; & vbCrLf & &quot;[&quot; & Error(Err) & &quot;]&quot; & vbCrLf & &quot;※この画面のキャプチャを作成者へ送ってください&quot;
    GetChromeVersion = False
End Function
Private Function ChromedriverQuickCheck(chromedriverPath, chromeVersion As VersionType) As Boolean
    Dim objHttp As New MSXML2.XMLHTTP60
    Dim targetVarsion As String
    Dim uri As String
    Dim api_endpoints As String
    Dim downloadPath As String
    Dim objFso As New Scripting.FileSystemObject
    Const TARGET_PLATFORM As String = &quot;win64&quot;

    api_endpoints = &quot;https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_&quot; & chromeVersion.BuildVersion
    On Error GoTo ErrLabel
        With objHttp
            .Open &quot;GET&quot;, api_endpoints, False
            .Send
            targetVarsion = .responseText &#39;---JSON endpoints から情報を収集する
            downloadPath = workPath & &quot;\&quot; & targetVarsion
            &#39;--- 念のためリビジョンバージョンを比較する
            If chromeVersion.Major &gt;= CLng(Split(targetVarsion, &quot;.&quot;)(0)) Then
                &#39;--- まだダウンロードしていなかったらダウンロードする
                If objFso.FileExists(downloadPath & &quot;\&quot; & DRIVER_EXE) = False Then
                    uri = &quot;https://storage.googleapis.com/chrome-for-testing-public/&quot; & targetVarsion & &quot;/&quot; & TARGET_PLATFORM & &quot;/chromedriver-&quot; & TARGET_PLATFORM & &quot;.zip&quot;
                    Call DownloadChromedriver(uri, targetVarsion)
                    Call objFso.DeleteFile(chromedriverPath & &quot;\&quot; & DRIVER_EXE, True)
                    Debug.Print &quot;インストールしたChromedriverのバージョン：&quot; & targetVarsion
                End If
                &#39;--- chromedriverはいつでも上書きする
                Call objFso.GetFile(downloadPath & &quot;\&quot; & DRIVER_EXE).Copy(chromedriverPath & &quot;\&quot; & DRIVER_EXE, True)
            Else
                Debug.Print &quot;Chromeのバージョンが古いためChromedriverは更新しません&quot;
            End If
        End With
    On Error GoTo 0
    ChromedriverQuickCheck = True
    Exit Function
ErrLabel:     &#39;---予期せぬエラーの分岐
    MsgBox &quot;chromedriver.exe の更新に失敗しました&quot; & vbCrLf & &quot;[&quot; & Error(Err) & &quot;]&quot; & vbCrLf & &quot;※この画面のキャプチャを作成者へ送ってください&quot;
    ChromedriverQuickCheck = False
End Function
Private Function DownloadChromedriver(ByVal url As String, targetVersion As String) As Boolean
    Dim rc As Long
    Dim downloadPath As String
    Dim newDriverPath As String
    Dim objFso As New Scripting.FileSystemObject
    Dim objFolder As Scripting.Folder
    downloadPath = workPath & &quot;\&quot; & targetVersion
    &#39; ---chromedriverのフォルダを作成する
    Select Case SHCreateDirectoryEx(0&, downloadPath, 0&)
        Case 0:
            &#39; ---作成成功
        Case 183
            &#39; ---作成済み
        Case Else:
            &#39; ---作成できなかった時
            MsgBox &quot;ChromeDriver用フォルダを作成できませんでした&quot; & vbCrLf & Error(Err), vbCritical
            DownloadChromedriver = False
            Exit Function
    End Select
    
    &#39;---ファイルをダウンロードする
    If URLDownloadToFile(0, url, workPath & &quot;\&quot; & ZIP_FILE, 0, 0) &lt;&gt; 0 Then
        MsgBox &quot;ChromeDriverをダウンロードできませんでした&quot; & vbCrLf & Error(Err), vbCritical
        DownloadChromedriver = False
        Exit Function
    End If
    Application.DisplayAlerts = False
    &#39;---zipを既定のフォルダに向けて解凍する
    With CreateObject(&quot;Shell.Application&quot;) &#39;---zipを既定のフォルダに向けて解凍する
        .Namespace((downloadPath)).CopyHere .Namespace((workPath & &quot;\&quot; & ZIP_FILE)).Items
    End With
    &#39;--- 解凍したフォルダから再起処理してchromedriver.exeのフルパスを取得する
    newDriverPath = SearchFilesRecursively(downloadPath & &quot;\&quot;, &quot;chromedriver.exe&quot;)
    If newDriverPath = &quot;&quot; Then
        MsgBox &quot;chromedriver.exe の更新に失敗しました&quot;
        DownloadChromedriver = False
    End If
    &#39;---chromedriverをバージョンフォルダ直下に移動する
    Call objFso.MoveFile(newDriverPath, downloadPath & &quot;\&quot;)
    &#39;---chromedriverがなくなった不要フォルダを削除する
    For Each objFolder In objFso.GetFolder(downloadPath).SubFolders
        objFolder.Delete True
    Next
    &#39;---zipファイルを削除する
    Call objFso.DeleteFile(workPath & &quot;\&quot; & ZIP_FILE, True)
    Application.DisplayAlerts = True
    DownloadChromedriver = True
End Function
Function SearchFilesRecursively(ByVal folderPath As String, fileName As String) As String
    &#39;====================================================================================================
    &#39; folderPathを起点に再帰処理でサブフォルダまで対象にしてfileNameを探してフルパスを返す
    &#39;====================================================================================================
    Dim objFso As New Scripting.FileSystemObject
    Dim objFolder As Scripting.Folder
    Dim subFolder As Scripting.Folder
    Dim objFile As Scripting.File
    Dim result As String

    &#39; ファイル一覧をチェック
    For Each objFile In objFso.GetFolder(folderPath).Files
        If objFile.Name = fileName Then
            SearchFilesRecursively = objFile.Path
            Exit Function
        End If
    Next objFile

    &#39; サブフォルダを再帰的に探索
    For Each subFolder In objFso.GetFolder(folderPath).SubFolders
        result = SearchFilesRecursively(subFolder.Path, fileName)
        If result &lt;&gt; &quot;&quot; Then
            SearchFilesRecursively = result
            Exit Function
        End If
    Next subFolder

    &#39; 見つからなかった場合
    SearchFilesRecursively = &quot;&quot;
End Function
</code></pre></div>
</div></div>



<h2 class="wp-block-heading"><span id="toc11">あとがき</span></h2>



<p>こちらが後出しなので簡易版としましたがむしろこちらを正規版で過去作成した方を特殊版にした方がいいかなと思っているレベル</p>



<p>今後改修するとしたらこちらになる予定です</p>
]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/vba-chromedriver-auto-update-lite/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Python】Seleniumのfind_elementの使い方を解説！結局CSS_SELECTOR</title>
		<link>https://javeo.jp/selenium-find-element/</link>
					<comments>https://javeo.jp/selenium-find-element/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Wed, 20 Aug 2025 14:02:51 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Selenium]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=3305</guid>

					<description><![CDATA[目次 まずは要素検索の基本Byの種類とそれぞれの特徴CSS_SELECTORが最適な理由CSS_SELECTORでの代用方法親子要素、兄弟要素を指定親子要素、兄弟要素を指定するセレクタのいろいろ開発者ツールでセレクタを自 [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<div class="wp-block-cocoon-blocks-info-box block-box primary-box">
<p>Seleniumを使うときに一番よく使うのが、find_element / find_elementsですよね</p>



<p>ブラウザを自動操作するためには、画面上のボタンや入力欄を「どうやって特定するか」が重要ポイントです</p>
</div>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-12" checked><label class="toc-title" for="toc-checkbox-12">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">まずは要素検索の基本</a></li><li><a href="#toc2" tabindex="0">Byの種類とそれぞれの特徴</a></li><li><a href="#toc3" tabindex="0">CSS_SELECTORが最適な理由</a><ol><li><a href="#toc4" tabindex="0">CSS_SELECTORでの代用方法</a></li><li><a href="#toc5" tabindex="0">親子要素、兄弟要素を指定</a></li><li><a href="#toc6" tabindex="0">親子要素、兄弟要素を指定するセレクタのいろいろ</a></li><li><a href="#toc7" tabindex="0">開発者ツールでセレクタを自動判別</a></li></ol></li><li><a href="#toc8" tabindex="0">find_elementでよくあるエラーと回避方法</a></li><li><a href="#toc9" tabindex="0">あとがき</a></li><li><a href="#toc10" tabindex="0">サンプルHTML</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">まずは要素検索の基本</span></h2>



<p>まずはよくある基本の書き方です</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get(&quot;https://example.com&quot;)

element = driver.find_element(By.ID, &quot;username&quot;)</code></pre></div>



<p>このようにBy.IDやBy.NAMEなどを使って要素を探します</p>



<p>でも、このByの選び方によってコードの安定性や書きやすさが全然変わってきます</p>



<h2 class="wp-block-heading"><span id="toc2">Byの種類とそれぞれの特徴</span></h2>



<p>Byの種類は実は結構な数ありましてこんな感じ</p>



<ul class="wp-block-list has-watery-yellow-background-color has-background">
<li>By.ID</li>



<li>By.NAME</li>



<li>By.CLASS_NAME</li>



<li>By.TAG_NAME</li>



<li>By.LINK_TEXT</li>



<li>By.PARTIAL_LINK_TEXT</li>



<li>By.CSS_SELECTOR</li>



<li>By.XPATH</li>
</ul>



<p>ネットでは&#8221;By.ID&#8221;や&#8221;CLASS_NAME&#8221;も見かけますが、結論は&#8221;<strong><span class="marker-under"><span class="bold-red">By.CSS_SELECTOR</span></span></strong>&#8220;を使っておけば間違いないです</p>



<p>XPATHが他唯一候補になりますが、CSS_SELECTORはスクレイピングで使う&#8221;Beautiful Soup&#8221;にも応用できますし、記述がすっきりしてわかりやすいのでCSS_SELECTORに軍配が上がります</p>



<h2 class="wp-block-heading"><span id="toc3">CSS_SELECTORが最適な理由</span></h2>



<p>CSS_SELECTORが最適な最大の要因は全てCSS_SELECTORで代用できるところにあります</p>



<p>つまり、CSS_SELECTORさえ覚えてしまえば他を使う必要がなくなるんです</p>



<h3 class="wp-block-heading"><span id="toc4">CSS_SELECTORでの代用方法</span></h3>



<p>ここからは具体的に代用する際の記述です</p>



<p>Seleniumを利用するなら何度も書くことになる必修レベルなのでぜひ覚えてください</p>



<p>※説明は割愛しますが、XPATHも他の代用ができますので参考までに記載しておきます</p>



<div class="wp-block-cocoon-blocks-caption-box-1 caption-box block-box has-border-color has-blue-border-color not-nested-style cocoon-block-caption-box" style="--cocoon-custom-border-color:#42a5f5"><div class="caption-box-label block-box-label box-label fab-pencil"><span class="caption-box-label-text block-box-label-text box-label-text">By.ID ※&#8221;#&#8221;の後ろに値を記載</span></div><div class="caption-box-content block-box-content box-content">
<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">sample</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.ID, &#8216;hoge&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">CSS_SELECTOR</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.CSS_SELECTOR, &#8216;#hoge&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">XPATH</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.XPATH, &#8216;//*[@id=&#8221;hoge&#8221;]&#8217;)</p>
</div></div>
</div></div>



<div class="wp-block-cocoon-blocks-caption-box-1 caption-box block-box has-border-color has-blue-border-color not-nested-style cocoon-block-caption-box" style="--cocoon-custom-border-color:#42a5f5"><div class="caption-box-label block-box-label box-label fab-pencil"><span class="caption-box-label-text block-box-label-text box-label-text">By.CLASS_NAME ※&#8221;.&#8221;の後ろに値を記載</span></div><div class="caption-box-content block-box-content box-content">
<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">sample</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.CLASS_NAME, &#8216;hoge&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">CSS_SELECTOR</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.CSS_SELECTOR, &#8216;.hoge&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">XPATH</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.XPATH,&nbsp;&#8216;//*[@class=&#8221;hoge&#8221;]&#8217;)</p>
</div></div>
</div></div>



<div class="wp-block-cocoon-blocks-caption-box-1 caption-box block-box has-border-color has-blue-border-color not-nested-style cocoon-block-caption-box" style="--cocoon-custom-border-color:#42a5f5"><div class="caption-box-label block-box-label box-label fab-pencil"><span class="caption-box-label-text block-box-label-text box-label-text">By.LINK_TEXT ※forでaタグをループして最初にtextの完全一致</span></div><div class="caption-box-content block-box-content box-content">
<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">sample</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.LINK_TEXT, &#8216;hoge&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">CSS_SELECTOR</span></div><div class="label-box-content block-box-content box-content">
<p>next((a for a in driver.find_elements(By.CSS_SELECTOR, &#8216;a&#8217;) if a.text == &#8216;hoge&#8217;), None)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">XPATH</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.XPATH, &#8216;//a[text()=&#8221;hoge&#8221;]&#8217;)</p>
</div></div>
</div></div>



<div class="wp-block-cocoon-blocks-caption-box-1 caption-box block-box has-border-color has-blue-border-color not-nested-style cocoon-block-caption-box" style="--cocoon-custom-border-color:#42a5f5"><div class="caption-box-label block-box-label box-label fab-pencil"><span class="caption-box-label-text block-box-label-text box-label-text">By.PARTIAL_LINK_TEXT ※forでaタグをループして最初にtextの部分一致</span></div><div class="caption-box-content block-box-content box-content">
<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">sample</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.PARTIAL_LINK_TEXT, &#8216;hoge&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">CSS_SELECTOR</span></div><div class="label-box-content block-box-content box-content">
<p>next((a for a in driver.find_elements(By.CSS_SELECTOR, &#8216;a&#8217;) if &#8216;hoge&#8217; in a.text), None)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">XPATH</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.XPATH, &#8216;//a[contains(text(), &#8220;hoge&#8221;)]&#8217;)</p>
</div></div>
</div></div>



<div class="wp-block-cocoon-blocks-caption-box-1 caption-box block-box has-border-color has-blue-border-color not-nested-style cocoon-block-caption-box" style="--cocoon-custom-border-color:#42a5f5"><div class="caption-box-label block-box-label box-label fab-pencil"><span class="caption-box-label-text block-box-label-text box-label-text">By.TAG_NAME ※何も記号を付けなければタグになる</span></div><div class="caption-box-content block-box-content box-content">
<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">sample</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.TAG_NAME, &#8216;div&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">CSS_SELECTOR</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.CSS_SELECTOR, &#8216;div&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">XPATH</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.XPATH,&nbsp;&#8216;//div&#8217;)</p>
</div></div>
</div></div>



<div class="wp-block-cocoon-blocks-caption-box-1 caption-box block-box has-border-color has-blue-border-color not-nested-style cocoon-block-caption-box" style="--cocoon-custom-border-color:#42a5f5"><div class="caption-box-label block-box-label box-label fab-pencil"><span class="caption-box-label-text block-box-label-text box-label-text">By.NAME ※&#8221;[key=value]&#8221;で指定できる</span></div><div class="caption-box-content block-box-content box-content">
<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">sample</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.NAME, &#8216;hoge&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">CSS_SELECTOR</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.CSS_SELECTOR, &#8216;[name=&#8221;hoge&#8221;]&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">XPATH</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.XPATH, &#8216;//*[@name=&#8221;hoge&#8221;]&#8217;)</p>
</div></div>
</div></div>



<div class="wp-block-cocoon-blocks-caption-box-1 caption-box block-box has-border-color has-blue-border-color not-nested-style cocoon-block-caption-box" style="--cocoon-custom-border-color:#42a5f5"><div class="caption-box-label block-box-label box-label fab-pencil"><span class="caption-box-label-text block-box-label-text box-label-text">その他の属性 ※&#8221;[key=value]&#8221;で指定できる</span></div><div class="caption-box-content block-box-content box-content">
<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">CSS_SELECTOR</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.CSS_SELECTOR, &#8216;[data-test=&#8221;hoge&#8221;]&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">XPATH</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.XPATH, &#8216;//*[@data-test=&#8221;hoge&#8221;]&#8217;)</p>
</div></div>
</div></div>



<div class="wp-block-cocoon-blocks-caption-box-1 caption-box block-box has-border-color has-blue-border-color not-nested-style cocoon-block-caption-box" style="--cocoon-custom-border-color:#42a5f5"><div class="caption-box-label block-box-label box-label fab-pencil"><span class="caption-box-label-text block-box-label-text box-label-text">&#8220;div&#8221;タグと&#8221;hoge、piyo&#8221;の2つのクラス指定したい場合 ※繋げるだけ</span></div><div class="caption-box-content block-box-content box-content">
<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">CSS_SELECTOR</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.CSS_SELECTOR, &#8216;div.hoge.piyo&#8217;)</p>
</div></div>



<div class="wp-block-cocoon-blocks-label-box-1 label-box block-box has-border-color has-watery-blue-border-color not-nested-style cocoon-block-label-box" style="--cocoon-custom-border-color:#e3f2fd"><div class="label-box-label block-box-label box-label"><span class="label-box-label-text block-box-label-text box-label-text">XPATH</span></div><div class="label-box-content block-box-content box-content">
<p>driver.find_element(By.XPATH, &#8216;//div[contains(@class, &#8220;hoge&#8221;) and contains(@class, &#8220;piyo&#8221;)]&#8217;)</p>
</div></div>
</div></div>



<h3 class="wp-block-heading"><span id="toc5">親子要素、兄弟要素を指定</span></h3>



<p>もう一つCSS_SELECTORの大きな利点として親子要素、兄弟要素の指定ができるところです</p>



<p>親子要素、兄弟要素とはHTMLソースで見たときに縦・横の関係にある要素です</p>



<ul class="wp-block-list">
<li>親子　…　横（階層の深さ）</li>



<li>兄弟　…　縦（同じ階層の横並び）</li>
</ul>



<figure class="wp-block-image size-full is-style-default"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/08/image-16.png"><img decoding="async" width="707" height="544" src="https://javeo.jp/wp-content/uploads/2025/08/image-16.png" alt="" class="wp-image-3316" title="" srcset="https://javeo.jp/wp-content/uploads/2025/08/image-16.png 707w, https://javeo.jp/wp-content/uploads/2025/08/image-16-300x231.png 300w, https://javeo.jp/wp-content/uploads/2025/08/image-16-150x115.png 150w" sizes="(max-width: 707px) 100vw, 707px" /></a></figure>



<p>例えば上図で黄色囲いした&#8221;<span class="marker-under">説明文2です</span>&#8220;の要素を指定しようとした時</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>driver.find_element(By.CLASS_NAME, &quot;description&quot;)</code></pre></div>



<p>では上部の&#8221;<span class="marker-under">説明文です</span>&#8220;の要素を取得してしまいます※n番目の指定もできますがややこしくなるので割愛</p>



<p>うまく取得するためには指定が一意になるように親要素から指定する必要があり、どこまで丁寧に書くかですが</p>



<ul class="wp-block-list has-watery-yellow-background-color has-background">
<li>&#8220;.younger .description&#8221;</li>



<li>&#8220;.younger &gt; .card &gt; .description&#8221;</li>



<li>&#8220;div.younger &gt; div.card &gt; p.description&#8221;</li>
</ul>



<p>などで取得できます</p>



<p>※このページ下部に同じ画像とソースを準備していますので試してみてください</p>



<h3 class="wp-block-heading"><span id="toc6">親子要素、兄弟要素を指定するセレクタのいろいろ</span></h3>



<p>要素を指定する方法はいくつかありまして状況に合わせて使い分けが必要です</p>



<figure class="wp-block-table is-style-color-head"><div class="scrollable-table"><table><thead><tr><th>セレクタ</th><th>意味</th></tr></thead><tbody><tr><td>A B（AとBの間にスペース）</td><td>Aの子孫であるB（何階層先でもOK）</td></tr><tr><td>A &gt; B</td><td>Aの<strong>直下の子要素</strong>B</td></tr><tr><td>A + B</td><td>Aの<strong>直後の兄弟要素</strong>B</td></tr><tr><td>A ~ B</td><td>Aの後に続く兄弟要素B全て</td></tr><tr><td>A *</td><td>Aの後に続く全要素</td></tr><tr><td>A , B</td><td>A or B</td></tr><tr><td>A &gt; B, C &gt; D</td><td>&#8220;A&gt; B&#8221; or &#8220;C &gt;D&#8221; ※&#8221;A&gt; C &gt;D&#8221; or &#8220;A &gt; B &gt; D&#8221;じゃない</td></tr></tbody></table></div></figure>



<p>特に多く利用するのが上二つの親子要素を指定するセレクタです</p>



<h3 class="wp-block-heading"><span id="toc7">開発者ツールでセレクタを自動判別</span></h3>



<p>慣れてしまえばソースを見て起点とする要素の判別とそこから取得したい要素を導くセレクタが判断できるようになりますが、開発者ツールを使えば自動判別してくれます</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/08/image-17.png"><img decoding="async" width="1024" height="645" src="https://javeo.jp/wp-content/uploads/2025/08/image-17-1024x645.png" alt="" class="wp-image-3320" srcset="https://javeo.jp/wp-content/uploads/2025/08/image-17-1024x645.png 1024w, https://javeo.jp/wp-content/uploads/2025/08/image-17-300x189.png 300w, https://javeo.jp/wp-content/uploads/2025/08/image-17-150x94.png 150w, https://javeo.jp/wp-content/uploads/2025/08/image-17-768x483.png 768w, https://javeo.jp/wp-content/uploads/2025/08/image-17.png 1185w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>そのまま使うことは少ないですが、参考にするとか下書きで取得してそこから編集するには使える機能です</p>



<h2 class="wp-block-heading"><span id="toc8">find_elementでよくあるエラーと回避方法</span></h2>



<p>Seleniumを触っていると必ず出会うエラーが「NoSuchElementException」や「ElementNotInteractableException」</p>



<p>要素が見つからなかったり、まだ読み込みが終わってないのが原因です</p>



<p>例えば画面上の文字を取得しようとした時のプログラムは</p>



<div class="wp-block-cocoon-blocks-tab-caption-box-1 tab-caption-box block-box has-border-color has-blue-border-color not-nested-style cocoon-block-tab-caption-box" style="--cocoon-custom-border-color:#42a5f5"><div class="tab-caption-box-label block-box-label box-label fab-check"><span class="tab-caption-box-label-text block-box-label-text box-label-text">一般的な文字の取得方法</span></div><div class="tab-caption-box-content block-box-content box-content">
<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>hoge = driver.find_element(By.CSS_SELECTOR, &#39;#hoge&#39;).text</code></pre></div>
</div></div>



<p>ですが、これではもし指定した要素が見つからなかった場合にエラーになります</p>



<p>それを防ぐためには下記2パターンのどちらかを推奨です</p>



<div class="wp-block-cocoon-blocks-tab-caption-box-1 tab-caption-box block-box has-border-color has-blue-border-color not-nested-style cocoon-block-tab-caption-box" style="--cocoon-custom-border-color:#42a5f5"><div class="tab-caption-box-label block-box-label box-label fab-lightbulb"><span class="tab-caption-box-label-text block-box-label-text box-label-text">WebDriverWaitで要素の出現を待つ</span></div><div class="tab-caption-box-content block-box-content box-content">
<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code># 10秒待っても要素が見つからないエラーをキャッチする
try:
    elm = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, &#39;#hoge&#39;)))
    hoge = elm.text
except TimeoutException:
    print(&#39;#hoge が見つかりませんでした&#39;)
except Exception:
    print(&#39;予期せぬエラーが発生しました&#39;)</code></pre></div>
</div></div>



<div class="wp-block-cocoon-blocks-tab-caption-box-1 tab-caption-box block-box has-border-color has-blue-border-color not-nested-style cocoon-block-tab-caption-box" style="--cocoon-custom-border-color:#42a5f5"><div class="tab-caption-box-label block-box-label box-label fab-lightbulb"><span class="tab-caption-box-label-text block-box-label-text box-label-text">ジェネレータ式で最初の要素を取得する</span></div><div class="tab-caption-box-content block-box-content box-content">
<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code># 要素が見つからないとNoneを返す
elm = next((e for e in driver.find_elements(By.CSS_SELECTOR, &#39;#hoge&#39;)), None)
if elm:
    hoge = elm.text
else:
    print(&#39;#hoge が見つかりませんでした&#39;)</code></pre></div>
</div></div>



<p>やり方は違いますが&#8221;まずは要素を検索&#8221;した後に&#8221;目的のアクションを実施&#8221;することでエラーを防ぎます</p>



<p>このやり方なら文字の取得だけでなく、文字入力やクリックなどにも流用できます</p>



<h2 class="wp-block-heading"><span id="toc9">あとがき</span></h2>



<p>基礎の基礎なfind_elementでも結構奥が深いです</p>



<p>少しずつ理解を深めてSeleniumを活用していきたいですね</p>



<p>最後に練習に使えるHTMLを準備していますのでご自由にどうぞ</p>



<h2 class="wp-block-heading"><span id="toc10">サンプルHTML</span></h2>



<div class="wp-block-cocoon-blocks-blank-box-1 blank-box block-box">
<section class="sample">
    <div class="parent">
        <p>親要素です</p>
        <div class="child older">
            <p>子要素です</p>
            <div class="grandchild">
                <p>孫要素です</p>
                <div class="card">
                    <p class="description">説明文です</p>
                    <a href="#" class="cta">詳しく見る</a>
                </div>
            </div>
        </div>
        <div class="child younger">
            <p>子要素の兄弟要素です</p>
            <div class="card">
                <p class="description">説明文2です</p>
                <a href="#" class="cta">詳しく見る</a>
            </div>
        </div>
    </div>
</section>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/selenium-find-element/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Python】Seleniumで気を付けたいことまとめ</title>
		<link>https://javeo.jp/selenium-point/</link>
					<comments>https://javeo.jp/selenium-point/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Sun, 23 Feb 2025 16:52:41 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Selenium]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=2951</guid>

					<description><![CDATA[Seleniumはスクレイピングで使うことも多くてスピードを求める人も多いですが根源的にはWEBアプリのテスト用であり、スクレイピングするにしてもWEBサイトに迷惑をかけないことが必須なので&#8221;スピード &#038;lt [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<div class="wp-block-cocoon-blocks-info-box block-box primary-box">
<p>私は本業でも副業でもお世話になてるSeleniumさん</p>



<p>普通に使ってると歯痒いところ何気に多く、ラッパーを作ったり微調整してあげてるんですが実際に遭遇した事象と対処法をメモしていくのでSelenium好きの方はちょくちょく覗きに来てもらうと情報共有できると思います</p>
</div>



<p>Seleniumはスクレイピングで使うことも多くてスピードを求める人も多いですが根源的にはWEBアプリのテスト用であり、スクレイピングするにしてもWEBサイトに迷惑をかけないことが必須なので&#8221;スピード &lt;&lt;&lt; 正確な動作&#8221;を前提にプログラムを作成します</p>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-14" checked><label class="toc-title" for="toc-checkbox-14">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">利用しているモジュール群</a></li><li><a href="#toc2" tabindex="0">遭遇した事象と対処方法</a><ol><li><a href="#toc3" tabindex="0">Getでページ遷移完了する前に次の処理が走ってしまう</a></li><li><a href="#toc4" tabindex="0">文字入力ができない、入力後の処理が動かない</a></li><li><a href="#toc5" tabindex="0">Frameの遷移が成功しない</a></li></ol></li><li><a href="#toc6" tabindex="0">あとがき</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">利用しているモジュール群</span></h2>



<p>このページでは使っていないものもありますが、私がSeleniumを使う時の基本セットてきなやつです</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-plain"><code>import dataclasses
import logging
import logging.config
import logging.handlers

import os
import datetime
from time import sleep

import bs4
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchElementException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common import utils
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.ui import WebDriverWait

# ---今回はoptionsとserviceは考慮しない
driver = webdriver.Chrome()</code></pre></div>



<h2 class="wp-block-heading"><span id="toc2">遭遇した事象と対処方法</span></h2>



<p>ここから実際に遭遇した事象と個人的対処方法を書き残していきます</p>



<p>自分で使うときはラッパークラスを作ってるので厳密には違うコードになってますが考え方は同じなんで参考にどうぞ</p>



<h3 class="wp-block-heading"><span id="toc3">Getでページ遷移完了する前に次の処理が走ってしまう</span></h3>



<p>何を言ってるのかわからねーと思うがおれも何をされたのかわからなかった…頭がどうにかなりそうだった…</p>



<p>例えば</p>



<ul class="wp-block-list has-watery-green-background-color has-background is-style-numeric-list-step has-list-style">
<li>Getでログインページに遷移</li>



<li>ログインページでID/PWを入力してログインボタンをクリック</li>



<li>ログイン後のページで処理</li>
</ul>



<p>なんてよくある処理でもサイトによっては稀に謎エラーが発生します</p>



<p>何度デバックでステップインしても再現せずに苦しみましたが次の処理をすることでその後再現していないので対応完了ってことにしました</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>driver.get(url=url)
try:
    # JavaScriptを使ってページ全体が読み込まれるまで待機
    WebDriverWait(driver, 30).until(lambda d: d.execute_script(&quot;return document.readyState&quot;) == &quot;complete&quot;) # ---①
    sleep(0.1) # ---②
except Exception:
    logger.error(&#39;Page Transition Error!!&#39;)

driver.find_element(By.CSS_SELECTOR, &#39;#email&#39;).send_keys(id)
driver.find_element(By.CSS_SELECTOR, &#39;#password&#39;).send_keys(pw)
driver.find_element(By.CSS_SELECTOR, &#39;button.login_bunt&#39;).click()
try:
    # JavaScriptを使ってページ全体が読み込まれるまで待機
    WebDriverWait(driver, 30).until(lambda d: d.execute_script(&quot;return document.readyState&quot;) == &quot;complete&quot;) # ---①
    sleep(0.1) # ---②
except Exception:
    logger.error(&#39;Page Transition Error!!&#39;)

&#39;&#39;&#39;

～～～ ログイン後の処理 ～～～

&#39;&#39;&#39;</code></pre></div>



<p>やることは2つ</p>



<ul class="wp-block-list is-style-numeric-list-enclosed has-list-style">
<li>htmlファイルとサブリソースの読み込みがどちらも完了まで待機する</li>



<li>一瞬（0.1秒）でいいので無条件で待機処理を入れる</li>
</ul>



<p>jsの処理が終わってないのに次の処理をしようとしてエラーになってる気がするので適度に待機処理入れることで解消したんじゃないかと推察してます</p>



<h3 class="wp-block-heading"><span id="toc4">文字入力ができない、入力後の処理が動かない</span></h3>



<p>どのサイトでも発生するってわけでもないんですが、画面上に入力する要素が見えてないと文字入力ができない時がありまして・・</p>



<p>他にも文字入力処理は気を遣わないと思い通りの処理にならないことが多々あるのでちゃんとエラーハンドリングしようとするならこれくらい必要</p>



<ul class="wp-block-list has-watery-green-background-color has-background is-style-icon-list-check has-list-style">
<li>画面上に入力対象要素があるか確認する</li>



<li>タグが文字入力するinputかtextareaか確認する</li>



<li>readonlyやdisable属性が付いてないか確認する</li>



<li>ActionChainsで入力要素まで画面遷移する</li>



<li>send_keyの仕様が追記処理なので念のため文字入力の前にクリアする</li>



<li>入力が終わったらjs対策でタブキーを押す処理をする</li>
</ul>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>css_selector = &#39;#target_id&#39;
# ---入力する要素が見える状態か確認する
try:
    _ = WebDriverWait(driver, 3).until(EC.visibility_of(driver.find_element(By.CSS_SELECTOR, css_selector)))
except NoSuchElementException:
    print(&#39;No Such Element&#39;)
except TimeoutException:
    print(&#39;Timeout Error&#39;)
except Exception:
    print(&#39;Unknown Error&#39;, exc_info=True)

# ---WebDriverWait以外でもチェックする
element = driver.find_element(By.CSS_SELECTOR, css_selector)
# ---タグがinputかtextareaじゃないか確認する
if element.tag_name != &#39;input&#39; and element.tag_name != &#39;textarea&#39;:
    print(&#39;This element tagName is not input and textarea&#39;)
    return False
# ---タグが入力可能か確認する
if element.is_enabled() is False:
    print(&#39;This element is disable&#39;)
    return False
# ---readonly属性が付いてないか確認する
if not element.get_attribute(&#39;readonly&#39;) is None:
    print(&#39;This element is readonly&#39;)
    return False

# ---念のため画面をelementへ動かしておく
ActionChains(driver).move_to_element(element).perform()
# ---send_keysだと追記になってしまうので一旦クリアしておく
element.clear()
# ---念のため待機処理を入れる
sleep(0.1)
# ---ようやく実際に文字入力する
element.send_keys(&#39;hoge&#39;)
# ---入力後に発火するjsの可能性があるのでタブ移動する
element.send_keys(Keys.TAB)
# ---念のため待機処理を入れる
sleep(0.1)</code></pre></div>



<h3 class="wp-block-heading"><span id="toc5">Frameの遷移が成功しない</span></h3>



<p>まず&#8221;<strong>driver.switch_to.frame</strong>&#8220;より&#8221;<strong>expected_conditions</strong>&#8220;の&#8221;<strong>frame_to_be_available_and_switch_to_it</strong>&#8220;の方がエラーハンドリングしてくれるのでオススメ</p>



<p>中身を見ればやってることは結局&#8221;<strong>driver.switch_to.frame</strong>&#8220;だったりする</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>def frame_to_be_available_and_switch_to_it(locator: Union[Tuple[str, str], str]) -&gt; Callable[[WebDriver], bool]:
    &quot;&quot;&quot;An expectation for checking whether the given frame is available to
    switch to.

    If the frame is available it switches the given driver to the
    specified frame.
    &quot;&quot;&quot;

    def _predicate(driver: WebDriver):
        try:
            if isinstance(locator, Iterable) and not isinstance(locator, str):
                driver.switch_to.frame(driver.find_element(*locator))
            else:
                driver.switch_to.frame(locator)
            return True
        except NoSuchFrameException:
            return False

    return _predicate</code></pre></div>



<p>本題ですが&#8221;失敗する&#8221;じゃなくて&#8221;成功しない&#8221;と表現したのは&#8221;<strong>frame_to_be_available_and_switch_to_it</strong>&#8220;ではTrueで返ってくるのになぜか遷移できていないことに遭遇したから</p>



<p>発生確率も地味に高いのでちょっと面倒だけどこれくらいやらないと安心できないです</p>



<p>Frameの遷移が必要なWEBサイトは少ないのでこれくらいは我慢ってことですかね</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>css_selector = &#39;#target_id&#39;
try:
    # ---初期Frameに戻す
    driver.switch_to.default_content()
    # ---5回までリトライするようにする
    for _ in range(5):
        # ---5秒でFrameの遷移が完了するかチェック
        if WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, css_selector))) is False:
            sleep(1)
        else:
            # 選択したフレームが見えなくなっていることを確認して終わりにする
            if len(driver.find_elements(By.CSS_SELECTOR, css_selector)) == 0:
                return True
            else:
                sleep(1)
                continue
    else:
        raise NoSuchFrameException(msg=f&#39;&quot;{css_selector}&quot; に遷移できませんでした&#39;)
except Exception:
    # ---エラーになったら画面ショットを残しておく
    driver.save_screenshot(R&#39;errorshot_{}.png&#39;.format(datetime.datetime.now().strftime(&quot;%Y%m%d%H%M%S&quot;)))</code></pre></div>



<p>（Frameと言えばこんな感じのソースで動いているサイトもまだまだ現役のようです）</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/02/2025-02-24_18h26_11.png"><img decoding="async" width="1024" height="538" src="https://javeo.jp/wp-content/uploads/2025/02/2025-02-24_18h26_11-1024x538.png" alt="" class="wp-image-2961" srcset="https://javeo.jp/wp-content/uploads/2025/02/2025-02-24_18h26_11-1024x538.png 1024w, https://javeo.jp/wp-content/uploads/2025/02/2025-02-24_18h26_11-300x158.png 300w, https://javeo.jp/wp-content/uploads/2025/02/2025-02-24_18h26_11-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/02/2025-02-24_18h26_11-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/02/2025-02-24_18h26_11.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h2 class="wp-block-heading"><span id="toc6">あとがき</span></h2>



<p>何か問題に遭遇して解決した時は追記していくので気が向いた時にでも見に来てください！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/selenium-point/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Python】スクレイピングに向けてSQLite3を使いこなそう</title>
		<link>https://javeo.jp/python-sqlite3/</link>
					<comments>https://javeo.jp/python-sqlite3/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Sun, 09 Feb 2025 22:00:00 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Selenium]]></category>
		<category><![CDATA[SQLite]]></category>
		<category><![CDATA[スクレイピング]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=2685</guid>

					<description><![CDATA[目次 SQLiteとはSQLiteを利用するための準備データ型値のデータ型についてカラムのデータ型についてPythonで実際に使ってみるdb接続（≒ファイル作成）テーブル削除と作成データの作成（挿入）データの取得データの [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<div class="wp-block-cocoon-blocks-info-box block-box primary-box">
<p>Pythonでスクレイピングをする時にデータベースがあると色々楽でして、MySQL（MariaDB）やMicrosoft&nbsp;SQL Serverなど機能的にも優れたメジャーなデータベースを使うのもいいですが、個人利用かつ一時利用にはオーバースペック気味なのでお手軽使えるSQLiteの利用方法をご紹介します</p>



<p>&#8220;Pythonで使うため&#8221;前提なのであまり深堀はしませんが、シンプルかつ軽量なので初めてのデータベースにはオススメです</p>
</div>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-16" checked><label class="toc-title" for="toc-checkbox-16">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">SQLiteとは</a></li><li><a href="#toc2" tabindex="0">SQLiteを利用するための準備</a></li><li><a href="#toc3" tabindex="0">データ型</a><ol><li><a href="#toc4" tabindex="0">値のデータ型について</a></li></ol></li><li><a href="#toc5" tabindex="0">カラムのデータ型について</a><ol><li><a href="#toc6" tabindex="0">Pythonで実際に使ってみる</a><ol><li><a href="#toc7" tabindex="0">db接続（≒ファイル作成）</a></li><li><a href="#toc8" tabindex="0">テーブル削除と作成</a></li><li><a href="#toc9" tabindex="0">データの作成（挿入）</a></li><li><a href="#toc10" tabindex="0">データの取得</a></li><li><a href="#toc11" tabindex="0">データの削除</a></li><li><a href="#toc12" tabindex="0">データの更新</a></li><li><a href="#toc13" tabindex="0">同時に削除＆挿入 or 挿入＆更新</a></li><li><a href="#toc14" tabindex="0">全部をまとめたサンプルソース</a></li></ol></li></ol></li><li><a href="#toc15" tabindex="0">あとがき</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">SQLiteとは</span></h2>



<p>SQLiteはMySQL（MariaDB）やMicrosoft&nbsp;SQL Serverと同じでRDBMS（データベース管理システム）で、その名の通り軽量でオープンソースのデータベースです</p>



<p>と言っても特にサーバーなど準備する必要もなく、軽量なファイルがローカルに作成されるだけのお手軽データベース</p>



<p>SQLの知識が必要になりますが、最低限で十分なので覚えて損はないはず</p>



<h2 class="wp-block-heading"><span id="toc2">SQLiteを利用するための準備</span></h2>



<p>PythonはSQLiteを利用するためにはSQLite3を利用しますが、標準ライブラリ入っているので個別のインストールは不要で簡単に利用できます</p>



<p>必須ではないですが、GUIアプリの”<strong>DB Browser for SQLite</strong>”があると管理が楽になるので利用に合わせてお好みで</p>



<p>DB Browser for SQLiteのインストールについてはコチラのページからどうぞ</p>



<figure class="wp-block-embed is-type-wp-embed is-provider-excel-python wp-block-embed-excel-python"><div class="wp-block-embed__wrapper">

<a rel="noopener follow noreferrer" target="_blank" href="https://javeo.jp/sqlite-tool-install/" title="【Python】SQLite3のために&quot;DB Browser for SQLite&quot;をインストール" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="320" height="198" src="https://javeo.jp/wp-content/uploads/2024/10/SQLite-320x198.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://javeo.jp/wp-content/uploads/2024/10/SQLite-320x198.png 320w, https://javeo.jp/wp-content/uploads/2024/10/SQLite-240x148.png 240w, https://javeo.jp/wp-content/uploads/2024/10/SQLite-640x396.png 640w" sizes="(max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【Python】SQLite3のために"DB Browser for SQLite"をインストール</div><div class="blogcard-snippet internal-blogcard-snippet">Pythonでスクレイピングをする時にデータベース利用を推奨...</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://javeo.jp" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">javeo.jp</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2025.02.09</div></div></div></div></a>
</div></figure>



<h2 class="wp-block-heading"><span id="toc3">データ型</span></h2>



<p>SQLiteもデータベースなのでデータ型が存在します</p>



<p>値としてのデータ型とカラムとしてのデータ型の2つの観点があって詳細を知りたいなら<a rel="noreferrer noopener nofollow" target="_blank" href="https://www.sqlite.org/datatype3.html#determination_of_column_affinity" data-type="link" data-id="https://www.sqlite.org/datatype3.html#determination_of_column_affinity">公式ページはコチラ</a>で、ざっくり書き出すと↓↓の通り</p>



<h3 class="wp-block-heading"><span id="toc4">値のデータ型について</span></h3>



<p>SQLiteの値は5種類だけで下記参照</p>



<figure class="wp-block-table"><div class="scrollable-table"><table><thead><tr><th>データ型</th><th>意味</th></tr></thead><tbody><tr><td>NULL</td><td>NULL値。</td></tr><tr><td>INTEGER</td><td>整数。1, 2, 3, 4, 6, or 8 バイトで格納。</td></tr><tr><td>REAL</td><td>浮動小数点数。8バイトで格納。</td></tr><tr><td>TEXT</td><td>テキスト文字列。UTF-8, UTF-16BE or UTF-16-LEのいずれかで保存。</td></tr><tr><td>BLOB</td><td>Binary Large OBject。入力データをそのまま格納。</td></tr></tbody></table></div></figure>



<p>他のデータベースでよくあるBool型、Date型はなく</p>



<ul class="wp-block-list">
<li>Bool型だと整数 0 (False) と 1 (True)&nbsp;で代替</li>



<li>Date型は関数を使用して<strong>TEXT型なら（&#8221;YYYY-MM-DD HH:MM:SS.SSS&#8221;）</strong>、<strong>INTEGER型なら（1970-01-01 00:00:00 UTC からの秒数）</strong>として代替</li>
</ul>



<h2 class="wp-block-heading"><span id="toc5">カラムのデータ型について</span></h2>



<p>続いてカラムで設定できるデータ型について</p>



<p>こちらも5種類だけでデータベースとしてはかなり少ないです</p>



<figure class="wp-block-table"><div class="scrollable-table"><table><thead><tr><th>型親和性</th><th>説明</th></tr></thead><tbody><tr><td><strong>TEXT</strong></td><td>基本は文字列として保存される</td></tr><tr><td><strong>NUMERIC</strong></td><td>数値か文字列として保存される（基本は数値）</td></tr><tr><td><strong>INTEGER</strong></td><td>数値として保存される（整数を優先）</td></tr><tr><td><strong>REAL</strong></td><td>小数として保存される</td></tr><tr><td><strong>BLOB</strong></td><td>そのままのデータとして保存される（変換なし）</td></tr></tbody></table></div></figure>



<p>なんですが、実際は指定したデータ型に関係なく値が保存出来ちゃいます</p>



<p>“<strong>SQLite.exe</strong>“でデータを見てみるとこんな感じ</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2025/02/image-1.png"><img decoding="async" width="1024" height="538" src="https://javeo.jp/wp-content/uploads/2025/02/image-1-1024x538.png" alt="" class="wp-image-2898" srcset="https://javeo.jp/wp-content/uploads/2025/02/image-1-1024x538.png 1024w, https://javeo.jp/wp-content/uploads/2025/02/image-1-300x158.png 300w, https://javeo.jp/wp-content/uploads/2025/02/image-1-150x79.png 150w, https://javeo.jp/wp-content/uploads/2025/02/image-1-768x403.png 768w, https://javeo.jp/wp-content/uploads/2025/02/image-1.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>この仕様は良いのか悪いのか・・・</p>



<h3 class="wp-block-heading"><span id="toc6">Pythonで実際に使ってみる</span></h3>



<p>Pythonで使うと言っても基本的にはSQLを実行するだけ（データベースなんだからそりゃそう）</p>



<p>代表的なサンプルソース（≒SQL）を書き出します</p>



<h4 class="wp-block-heading"><span id="toc7">db接続（≒ファイル作成）</span></h4>



<p>DBの接続コマンドでファイルが無ければ生成してくれる</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>import sqlite3

#　---db接続（ファイルがなければ作成される）---
db_file= &quot;test.sqlite3&quot; # 拡張子は&quot;*.db&quot;,&quot;*.sqlite&quot;,&quot;*.db3&quot;,&quot;*.sqlite3&quot;からお好きなものを
conn = sqlite3.connect(db_file) 
# SQLiteを操作するためのカーソルを作成
cur = conn.cursor()</code></pre></div>



<h4 class="wp-block-heading"><span id="toc8">テーブル削除と作成</span></h4>



<p>SQLiteには<strong>&#8220;TRUNCATE TABLE&#8221;</strong>はないので<strong>&#8220;DROP &amp; CREATE&#8221;</strong>で代替</p>



<p><strong>&#8220;条件なしDELETE文&#8221;</strong>でも十分高速処理になるっぽい</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>#　---テーブルを作成---
# テーブルが既にあれば削除する
sql = &quot;DROP TABLE IF EXISTS test_table&quot;
cur.execute(sql)

# item_cdを主キーにテーブルを新規作成
sql = &quot;&quot;&quot;
    CREATE TABLE test_table(
    item_cd INTEGER PRIMARY KEY,
    item_name TEXT,
    item_count INTEGER,
    price INTEGER
    )
    &quot;&quot;&quot;
cur.execute(sql)
conn.commit() # コミットしないと反映しない</code></pre></div>



<h4 class="wp-block-heading"><span id="toc9">データの作成（挿入）</span></h4>



<p>複数データを同時にINSERTする時は他のデータベースでは見ない処理方法</p>



<p>無理にまとめて処理しなくてもPythonの中でループ処理もありかも</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code># データを挿入 ※execute
sql = &quot;INSERT INTO test_table (item_cd, item_name, item_count, price) VALUES (1, &#39;mouse&#39;, 1, 3000)&quot;
cur.execute(sql)
conn.commit()  # コミットしないと反映しない

# まとめてデータを挿入 ※executemany
sql = &quot;INSERT INTO test_table (item_cd, item_name, item_count, price) VALUES (?,?,?,?)&quot;
data = [(2, &quot;keyboard&quot;, 1, 8000), (3, &quot;monitor&quot;, 1, 15000), (4, &quot;USB cable&quot;, 3, 300), (5, &quot;HDMI cable&quot;, 1, 1000)]
cur.executemany(sql, data)
conn.commit()  # コミットしないと反映しない</code></pre></div>



<h4 class="wp-block-heading"><span id="toc10">データの取得</span></h4>



<p>普通のSELECT文</p>



<p>取得データはレコードをTUPLE型、複数レコードはLIST型で取得できるのでforなどでループして取得してあげればOK</p>



<p>変数に格納するならexecute後にfetchallで値を取得できる</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code># データベースからデータを取得
sql = &quot;SELECT * FROM test_table&quot;
_ = cur.execute(sql)
rows = cur.fetchall()
for row in rows:
    print(row)</code></pre></div>



<h4 class="wp-block-heading"><span id="toc11">データの削除</span></h4>



<p>特に変わりのない一般的な<strong>&#8220;DELETE文&#8221;</strong></p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code># データを削除
sql = &quot;DELETE FROM test_table WHERE item_cd=1&quot;
cur.execute(sql)
conn.commit()  # コミットしないと反映しない</code></pre></div>



<h4 class="wp-block-heading"><span id="toc12">データの更新</span></h4>



<p>こちらも一般的な<strong>&#8220;UPDATE文&#8221;</strong></p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code># データを更新
sql = &quot;UPDATE test_table SET price=5000 WHERE item_name=&#39;keyboard&#39;&quot;
cur.execute(sql)
conn.commit()  # コミットしないと反映しない</code></pre></div>



<h4 class="wp-block-heading"><span id="toc13">同時に削除＆挿入 or 挿入＆更新</span></h4>



<p><strong>&#8220;REPLACE INTO&#8221;</strong>と<strong>&#8220;UPSERT（と同じような処理）&#8221;</strong>の両方使える</p>



<p>データベース的にはUPSERTの方が適切なんだけどREPLACE INTOの方が簡単</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code># データ削除と挿入を同時にする
sql = &quot;&quot;&quot;
    REPLACE INTO test_table (item_cd, item_name, item_count, price)
    VALUES (3, &#39;wide monitor&#39;, 1, 30000)
    &quot;&quot;&quot;
cur.execute(sql)
conn.commit()  # コミットしないと反映しない

# データ挿入時に重複なら更新する ※upsert文
sql = &quot;&quot;&quot;
    INSERT INTO test_table (item_cd, item_name, item_count, price)
    VALUES (5, &#39;HDMI cable&#39;, 3, 800)
    ON CONFLICT (item_cd)
    DO UPDATE SET item_count=3, price=800
    &quot;&quot;&quot;
cur.execute(sql)
conn.commit()  # コミットしないと反映しない</code></pre></div>



<h4 class="wp-block-heading"><span id="toc14">全部をまとめたサンプルソース</span></h4>



<p>今までのプログラムを全部くっつけただけですが、実行すればSQLiteのプログラムを体感できるソースです</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>import sqlite3

#　---ファイルがなければ作成してdb接続---
db_file= &quot;test.db&quot; # 拡張子は&quot;.db&quot;か&quot;.sqlite&quot;
conn = sqlite3.connect(db_file) 
# SQLiteを操作するためのカーソルを作成
cur = conn.cursor()

#　---テーブルを作成---
# テーブルが既にあれば削除する
sql = &quot;DROP TABLE IF EXISTS test_table&quot;
cur.execute(&quot;DROP TABLE IF EXISTS test_table&quot;)
# item_cdを主キーにテーブルを新規作成
sql = &quot;&quot;&quot;
    CREATE TABLE test_table(
    item_cd INTEGER PRIMARY KEY,
    item_name TEXT,
    item_count INTEGER,
    price INTEGER
    )
    &quot;&quot;&quot;
cur.execute(sql)
conn.commit() # コミットしないと反映しない

# データを挿入 ※execute
sql = &quot;INSERT INTO test_table (item_cd, item_name, item_count, price) VALUES (1, &#39;mouse&#39;, 1, 3000)&quot;
cur.execute(sql)
conn.commit()  # コミットしないと反映しない

# まとめてデータを挿入 ※executemany
sql = &quot;INSERT INTO test_table (item_cd, item_name, item_count, price) VALUES (?,?,?,?)&quot;
data = [(2, &quot;keyboard&quot;, 1, 8000), (3, &quot;monitor&quot;, 1, 15000), (4, &quot;USB cable&quot;, 3, 300), (5, &quot;HDMI cable&quot;, 1, 1000)]
cur.executemany(sql, data)
conn.commit()  # コミットしないと反映しない

# データベースからデータを取得
sql = &quot;SELECT * FROM test_table&quot;
_ = cur.execute(sql)
rows = cur.fetchall()
for row in rows:
    print(row)

# データを削除
sql = &quot;DELETE FROM test_table WHERE item_cd=1&quot;
cur.execute(sql)
conn.commit()  # コミットしないと反映しない

# データを更新
sql = &quot;UPDATE test_table SET price=5000 WHERE item_name=&#39;keyboard&#39;&quot;
cur.execute(sql)
conn.commit()  # コミットしないと反映しない

# データ削除と挿入を同時にする
sql = &quot;REPLACE INTO test_table (item_cd, item_name, item_count, price) VALUES (3, &#39;wide monitor&#39;, 1, 30000)&quot;
cur.execute(sql)
conn.commit()  # コミットしないと反映しない

# データ挿入時に重複なら更新する ※upsert文
sql = &quot;&quot;&quot;
    INSERT INTO test_table (item_cd, item_name, item_count, price)
    VALUES (5, &#39;HDMI cable&#39;, 3, 800)
    ON CONFLICT (item_cd)
    DO UPDATE SET item_count=3, price=800
    &quot;&quot;&quot;
cur.execute(sql)
conn.commit()  # コミットしないと反映しない

# 処理結果を見るためにもう一度データを取得
sql = &quot;SELECT * FROM test_table&quot;
_ = cur.execute(sql)
for row in cur.fetchall():
    print(row)</code></pre></div>



<h2 class="wp-block-heading"><span id="toc15">あとがき</span></h2>



<p>CSVを直接書き出すプログラムだと重複チェックやスクレイピングで取得したデータを使った再スクレイピングが難しいのでデータベースが使えると幅が広がります</p>



<p>入門編としてSQLiteは導入コストはないし学習コストも少ないのでオススメです！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/python-sqlite3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Python】Seleniumの待機処理はWebDriverWaitを使おう</title>
		<link>https://javeo.jp/python_wait/</link>
					<comments>https://javeo.jp/python_wait/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Sat, 29 Jun 2024 23:00:00 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Selenium]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=2385</guid>

					<description><![CDATA[WebDriverWaitについて 指定した条件を満たすまで待機する便利なモジュールです Seleniumでブラウザ操作をする上で特定の条件を満たすまで待機するシーンは多く、&#8221;time.sleepでxx秒待つ [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<div class="wp-block-cocoon-blocks-info-box block-box primary-box">
<p>Seleniumでブラウザ操作をする際、「要素が表示されるまで待ちたい」「クリック可能になるまで待ちたい」などのタイミング調整は非常に重要です</p>



<p>単に <code>time.sleep()</code> を使うと、処理が無駄に遅くなったり、逆に待ちが足りずにエラーになることが頻繁にあります</p>



<p>今回は<strong>Python + Selenium</strong> における待機処理のベストプラクティスとして、<code>WebDriverWait</code> と <code>expected_conditions</code> を使った「より良い待機」について詳しく解説します</p>
</div>



<h2 class="wp-block-heading">WebDriverWaitについて</h2>



<p>指定した条件を満たすまで待機する便利なモジュールです</p>



<p>Seleniumでブラウザ操作をする上で特定の条件を満たすまで待機するシーンは多く、&#8221;<strong>time.sleepでxx秒待つ</strong>&#8220;にすると時間が長過ぎると無駄が多く、短過ぎるとエラーになりがちな雑なプログラムになってしまうのではこのWebDriverWaitは必須レベル</p>



<p>ただし、経験上WebDriverWaitだけではうまくいかない場合があり、最後に0.5秒ほどsleepしてあげると処理が安定する気がします</p>



<p>基本的なパターンはコチラ</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>WebDriverWait(webdriver, タイムアウトまでの上限秒数).until(expected_conditionsで設定する条件)</code></pre></div>



<p>実際にサンプルソースにするとこんな感じです</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="sample" data-lang="Python"><code>from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException

driver = webdriver.Chrome()
driver.get(&#39;https://javeo.jp/practice_scraping/&#39;)
try:
    WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, &#39;#hoge&#39;)))
    print(&#39;条件を満たしました&#39;)
except TimeoutException:
    print(&#39;条件を満たせませんでした&#39;)
driver.quit()</code></pre></div>



<h2 class="wp-block-heading">expected_conditionsについて</h2>



<p>WebDriverWaitとセットで使うのがこのexpected_conditions</p>



<p>結局のところexpected_conditionsが肝心の条件部分で、WebDriverWaitはこの条件が正常終了 or Trueになるまで待つだけの仕様</p>



<p>ただこのexpected_conditionsは良くも悪くも指定できる条件が多く、使いこなすには事前把握が望ましいってことでまとめてみました</p>



<h3 class="wp-block-heading">expected_conditionsのオススメ関数と全関数</h3>



<p>↓の表で&#8221;<span class="marker-under">個人的によく使う</span>&#8220;タブはその名の通り私が個人的によく使う・使えそうだと思うものだけを、&#8221;<span class="marker-under">分類別の全関数</span>&#8220;ではある程度グループ分けした関数を全て目次のようにしています</p>



<p>調べて気づきましたが思ったより多くの関数があって利用シーンが謎なものもチラホラ・・</p>



<p>また、expected_conditionsの返り値はいろいろありますが、WebDriverWaitとセットで使うとWebDriverWaitの仕様上、返り値は正常終了時の値 or エラー（&#8221;<span class="marker-under-red">TimeoutException</span>&#8220;）になるのでtry exceptするときは注意</p>



<div class="wp-block-cocoon-blocks-tab tab-block cocoon-block-tab"><ul class="tab-label-group"><li class="tab-label tab-label-0">個人的によく使う</li><li class="tab-label tab-label-1">分類別の全関数</li></ul><div class="tab-content-group">
<div class="tab-content">
<figure class="wp-block-table ec_table"><div class="scrollable-table"><table><thead><tr><th>関数</th><th>条件</th></tr></thead><tbody><tr><td><a href="#visibility_of_element_located" data-type="internal" data-id="#visibility_of_element_located"></a><a href="#presence_of_element_located">presence_of_element_located</a></td><td>DOM上に存在しているか</td></tr><tr><td><a href="#visibility_of_element_located" data-type="internal" data-id="#visibility_of_element_located">visibility_of_element_located</a></td><td>画面上に表示されているか</td></tr><tr><td><a href="#invisibility_of_element_located" data-type="internal" data-id="#invisibility_of_element_located">invisibility_of_element_located</a></td><td>画面上で非表示になっているか</td></tr><tr><td><a href="#element_to_be_clickable" data-type="internal" data-id="#element_to_be_clickable">element_to_be_clickable</a></td><td>画面上に表示されてかつ利用できる状態か</td></tr></tbody></table></div></figure>
</div>



<div class="tab-content">
<figure class="wp-block-table ec_table"><div class="scrollable-table"><table><thead><tr><th>分類</th><th>返値の型</th></tr></thead><tbody><tr><th colspan="2">DOMで判定する　※画面上に見えているかは加味しない</th></tr><tr><td><a href="#presence_of_element_located">presence_of_element_located</a></td><td>WebElement</td></tr><tr><td><a href="#presence_of_all_elements_located">presence_of_all_elements_located</a></td><td>WebElement</td></tr><tr><th colspan="2">画面上の表示・非表示で判定する</th></tr><tr><td><a href="#visibility_of">visibility_of</a></td><td>WebElement</td></tr><tr><td><a href="#visibility_of_element_located">visibility_of_element_located</a></td><td>WebElement</td></tr><tr><td><a href="#visibility_of_all_elements_located">visibility_of_all_elements_located</a></td><td>List</td></tr><tr><td><a href="#visibility_of_any_elements_located">visibility_of_any_elements_located</a></td><td>List</td></tr><tr><td><a href="#invisibility_of_element">invisibility_of_element</a></td><td>bool</td></tr><tr><td><a href="#invisibility_of_element_located">invisibility_of_element_located</a></td><td>bool</td></tr><tr><th colspan="2">elementの状態で判定する</th></tr><tr><td><a href="#element_attribute_to_include">element_attribute_to_include</a></td><td>bool</td></tr><tr><td><a href="#element_located_selection_state_to_be">element_located_selection_state_to_be</a></td><td>bool</td></tr><tr><td><a href="#element_located_to_be_selected">element_located_to_be_selected</a></td><td>bool</td></tr><tr><td><a href="#element_selection_state_to_be">element_selection_state_to_be</a></td><td>bool</td></tr><tr><td><a href="#element_to_be_clickable">element_to_be_clickable</a></td><td>WebElement</td></tr><tr><td><a href="#element_to_be_selected">element_to_be_selected</a></td><td>bool</td></tr><tr><th colspan="2">文字や要素の値で判定する</th></tr><tr><td><a href="#text_to_be_present_in_element">text_to_be_present_in_element</a></td><td>bool</td></tr><tr><td><a href="#text_to_be_present_in_element_attribute">text_to_be_present_in_element_attribute</a></td><td>bool</td></tr><tr><td><a href="#text_to_be_present_in_element_value">text_to_be_present_in_element_value</a></td><td>bool</td></tr><tr><th colspan="2">ページタイトルで判定する</th></tr><tr><td><a href="#title_contains">title_contains</a></td><td>bool</td></tr><tr><td><a href="#title_is">title_is</a></td><td>bool</td></tr><tr><th colspan="2">ページURLで判定する</th></tr><tr><td><a href="#url_changes">url_changes</a></td><td>bool</td></tr><tr><td><a href="#url_contains">url_contains</a></td><td>bool</td></tr><tr><td><a href="#url_matches">url_matches</a></td><td>bool</td></tr><tr><td><a href="#url_to_be">url_to_be</a></td><td>bool</td></tr><tr><th colspan="2">ブラウザのウィンドウで判定する</th></tr><tr><td><a href="#number_of_windows_to_be">number_of_windows_to_be</a></td><td>bool</td></tr><tr><td><a href="#new_window_is_opened">new_window_is_opened</a></td><td>bool</td></tr><tr><th colspan="2">frame要素で判定する</th></tr><tr><td><a href="#frame_to_be_available_and_switch_to_it">frame_to_be_available_and_switch_to_it</a></td><td>bool</td></tr><tr><td><a href="#staleness_of">staleness_of</a></td><td>bool</td></tr><tr><th colspan="2">アラートポップアップで判定する</th></tr><tr><td><a href="#alert_is_present">alert_is_present</a></td><td>Alert</td></tr><tr><th colspan="2">複合条件にする</th></tr><tr><td><a href="#all_of">all_of</a></td><td>List</td></tr><tr><td><a href="#any_of">any_of</a></td><td>List</td></tr><tr><td><a href="#none_of">none_of</a></td><td>bool</td></tr></tbody></table></div></figure>
</div>
</div></div>



<h4 class="wp-block-heading anchor-set" id="presence_of_element_located">presence_of_element_located(locator: Tuple[str, str])</h4>



<p>引数のlocatorがDOMに存在すしていれば<span class="marker-under">返り値は<strong>該当したWebElement</strong>を返す</span>（DOMなので画面上に見えるかどうかは問わない）</p>



<p>内部的にはfind_elementでlocatorの有無確認しているだけ</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="presence_of_element_located" data-lang="Python"><code>def presence_of_element_located(locator: tuple[str, str]) -&gt; Callable[[WebDriverOrWebElement], WebElement]:
    def _predicate(driver: WebDriverOrWebElement):
        return driver.find_element(*locator)

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="presence_of_all_elements_located">presence_of_all_elements_located(locator: Tuple[str, str])</h4>



<p>引数のlocatorがDOMに存在すしていれば<span class="marker-under">返り値は<strong>該当した<span class="bold-red">全ての</span>WebElement</strong>を返す</span>（DOMなので画面上に見えるかどうかは問わない）</p>



<p>待機するだけならpresence_of_element_locatedと同じ</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="presence_of_all_elements_located" data-lang="Python"><code>def presence_of_all_elements_located(locator: tuple[str, str]) -&gt; Callable[[WebDriverOrWebElement], list[WebElement]]:
    def _predicate(driver: WebDriverOrWebElement):
        return driver.find_elements(*locator)

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="visibility_of_element_located">visibility_of_element_located(locator: Tuple[str, str])</h4>



<p>引数のlocatorが画面上に見えていれば<span class="marker-under">返り値は<strong>該当したWebElement</strong>を返す</span></p>



<p>実態はlocatorの有無確認と&#8221;<span class="marker-under">is_displayed()</span>&#8220;をしているだけ</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>def visibility_of_element_located(
    locator: tuple[str, str],
) -&gt; Callable[[WebDriverOrWebElement], Union[Literal[False], WebElement]]:
    def _predicate(driver: WebDriverOrWebElement):
        try:
            return _element_if_visible(driver.find_element(*locator))
        except StaleElementReferenceException:
            return False

    return _predicate</code></pre></div>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="_element_if_visible" data-lang="Python"><code>def _element_if_visible(element: WebElement, visibility: bool = True) -&gt; Union[Literal[False], WebElement]:
    return element if element.is_displayed() == visibility else False</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="visibility_of">visibility_of(element: WebElement)</h4>



<p>引数のelementが画面上に見えていれば<span class="marker-under">返り値は<strong>該当したWebElement</strong>を返す</span></p>



<p>引数にしたWebElementがそのまま返り値になるので単純な待機処理としてしか使うことはなさそう</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="visibility_of" data-lang="Python"><code>def visibility_of(element: WebElement) -&gt; Callable[[Any], Union[Literal[False], WebElement]]:
    def _predicate(_):
        return _element_if_visible(element)

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="visibility_of_all_elements_located">visibility_of_all_elements_located(locator: Tuple[str, str])</h4>



<p>引数のlocatorが全て画面上に見えていれば<span class="marker-under"><span class="marker-under">返り値は<strong>該当した<span class="bold-red">全ての</span>WebElement</strong>を返す</span></span></p>



<p>ただし、locatorが<span class="marker-under">1つでも<span class="marker-under">DOM上に存在しないか</span>非表示（hidden）</span>になっていれば<strong>エラー</strong>になる絶妙仕様なので使うことはあまりなさそう</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="visibility_of_all_elements_located" data-lang="Python"><code>def visibility_of_all_elements_located(
    locator: tuple[str, str],
) -&gt; Callable[[WebDriverOrWebElement], Union[list[WebElement], Literal[False]]]:
    def _predicate(driver: WebDriverOrWebElement):
        try:
            elements = driver.find_elements(*locator)
            for element in elements:
                if _element_if_visible(element, visibility=False):
                    return False
            return elements
        except StaleElementReferenceException:
            return False

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="visibility_of_any_elements_located">visibility_of_any_elements_located(locator: Tuple[str, str])</h4>



<p>引数のlocatorが画面上に見えていれば<span class="marker-under"><span class="marker-under"><span class="marker-under">返り値は<strong>該当した<span class="bold-red">全ての</span></strong></span></span><strong>WebElement</strong>を返す</span></p>



<p>こちらはlocatorが<span class="marker-under">DOM上に存在しない場合のみ<strong>エラー</strong></span>になり、一つでも表示されていれば表示されているWebElementを返してくれる</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="visibility_of_any_elements_located" data-lang="Python"><code>def visibility_of_any_elements_located(locator: tuple[str, str]) -&gt; Callable[[WebDriverOrWebElement], list[WebElement]]:
    def _predicate(driver: WebDriverOrWebElement):
        return [element for element in driver.find_elements(*locator) if _element_if_visible(element)]

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="invisibility_of_element_located">invisibility_of_element_located(locator: Union[WebElement, Tuple[str, str]])</h4>



<p>visibility_of_element_locatedの逆でDOM上に見えてないことを検知してくれる</p>



<p><span class="marker-under">DOM上になければTrue</span>、<span class="marker-under">DOM上にあるけど非表示なら対象のWebElement</span>を返してくれる</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="invisibility_of_element_located" data-lang="Python"><code>def invisibility_of_element_located(
    locator: Union[WebElement, tuple[str, str]],
) -&gt; Callable[[WebDriverOrWebElement], Union[WebElement, bool]]:
    def _predicate(driver: WebDriverOrWebElement):
        try:
            target = locator
            if not isinstance(target, WebElement):
                target = driver.find_element(*target)
            return _element_if_visible(target, visibility=False)
        except (NoSuchElementException, StaleElementReferenceException):
            # In the case of NoSuchElement, returns true because the element is
            # not present in DOM. The try block checks if the element is present
            # but is invisible.
            # In the case of StaleElementReference, returns true because stale
            # element reference implies that element is no longer visible.
            return True

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="invisibility_of_element">invisibility_of_element(element: Union[WebElement, Tuple[str, str]])</h4>



<p>実は<a href="#invisibility_of_element_located">invisibility_of_element_located</a>のシノニム</p>



<p>見ての通り実はlocatorでも受け付けできて、<span class="marker-under"><a href="#invisibility_of_element_located">invisibility_of_element_located</a></span>をそのまま返してるだけ</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="invisibility_of_element" data-lang="Python"><code>def invisibility_of_element(
    element: Union[WebElement, tuple[str, str]],
) -&gt; Callable[[WebDriverOrWebElement], Union[WebElement, bool]]:
    return invisibility_of_element_located(element)</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="element_attribute_to_include">element_attribute_to_include(locator: Tuple[str, str], attribute_: str)</h4>



<p>引数のlocatorがDOM上に存在し、さらにそのタグの中に引数のattribute_属性有無で照合（それ以外はエラー）</p>



<p>使い道としてはjsで要素が追加される時ぐらいですかね</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="element_attribute_to_include" data-lang="Python"><code>def element_attribute_to_include(locator: tuple[str, str], attribute_: str) -&gt; Callable[[WebDriverOrWebElement], bool]:
    def _predicate(driver: WebDriverOrWebElement):
        try:
            element_attribute = driver.find_element(*locator).get_attribute(attribute_)
            return element_attribute is not None
        except StaleElementReferenceException:
            return False

    return _predicate
</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="element_located_selection_state_to_be">element_located_selection_state_to_be(locator: Tuple[str, str], is_selected: bool)</h4>



<p>引数のlocatorがDOM上に存在し、さらにその要素の選択状況と引数のis_selected()が判定を返してくれる</p>



<p>locatorがDOM上に存在しない時はエラーになります</p>



<p>チェックボックスやラジオボタンではない場合、そもそも選択の概念がないのでis_selected()はFalseになる</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="element_located_selection_state_to_be" data-lang="Python"><code>def element_located_selection_state_to_be(
    locator: tuple[str, str], is_selected: bool
) -&gt; Callable[[WebDriverOrWebElement], bool]:
    def _predicate(driver: WebDriverOrWebElement):
        try:
            element = driver.find_element(*locator)
            return element.is_selected() == is_selected
        except StaleElementReferenceException:
            return False

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="element_located_to_be_selected">element_located_to_be_selected(locator: Tuple[str, str])</h4>



<p>引数のlocatorが選択されている状態であればで照合</p>



<p>is_selected()はあまり使う機会ないと思うんですよね</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="element_located_to_be_selected" data-lang="Python"><code>def element_located_to_be_selected(locator: tuple[str, str]) -&gt; Callable[[WebDriverOrWebElement], bool]:
    def _predicate(driver: WebDriverOrWebElement):
        return driver.find_element(*locator).is_selected()

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="element_to_be_selected">element_to_be_selected(element: WebElement)</h4>



<p><a href="#element_located_to_be_selected" data-type="internal" data-id="#element_located_to_be_selected">element_located_to_be_selected</a>の引数がlocatorからWebElementになった版</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="element_to_be_selected" data-lang="Python"><code>def element_to_be_selected(element: WebElement) -&gt; Callable[[Any], bool]:
    def _predicate(_):
        return element.is_selected()

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="element_selection_state_to_be">element_selection_state_to_be(element: WebElement, is_selected: bool)</h4>



<p><a href="#element_to_be_selected">element_to_be_selected</a>のis_selected() == Falseが選べるようになっただけ</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="element_selection_state_to_be" data-lang="Python"><code>def element_selection_state_to_be(element: WebElement, is_selected: bool) -&gt; Callable[[Any], bool]:
    def _predicate(_):
        return element.is_selected() == is_selected

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="element_to_be_clickable">element_to_be_clickable(mark: Union[WebElement, Tuple[str, str]])</h4>



<p>まず引数がmark（WebElementとlocatorのどちらでもOK）になっているのに好感<br>※全部そうしてほしい</p>



<p>内部的には<span class="marker-under"><a href="#visibility_of">visibility_of</a></span>かつ<span class="marker-under">is_enabled()</span>なのでclickableの名前からcheckbox向けのような印象を受けますが、inputタグなどにも有効（むしろこっちの方が利用頻度高い）</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="element_to_be_clickable" data-lang="Python"><code>def element_to_be_clickable(
    mark: Union[WebElement, tuple[str, str]],
) -&gt; Callable[[WebDriverOrWebElement], Union[Literal[False], WebElement]]:
    # renamed argument to &#39;mark&#39;, to indicate that both locator
    # and WebElement args are valid
    def _predicate(driver: WebDriverOrWebElement):
        target = mark
        if not isinstance(target, WebElement):  # if given locator instead of WebElement
            target = driver.find_element(*target)  # grab element at locator
        element = visibility_of(target)(driver)
        if element and element.is_enabled():
            return element
        return False

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="text_to_be_present_in_element">text_to_be_present_in_element(locator: Tuple[str, str], text_: str)</h4>



<p>XPATHの[text()=&#8217;hoge&#8217;]を事前チェックできる感じ</p>



<p>需要がありそうでなさそう、、、でやっぱりありそう</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="text_to_be_present_in_element" data-lang="Python"><code>def text_to_be_present_in_element(locator: tuple[str, str], text_: str) -&gt; Callable[[WebDriverOrWebElement], bool]:
    def _predicate(driver: WebDriverOrWebElement):
        try:
            element_text = driver.find_element(*locator).text
            return text_ in element_text
        except StaleElementReferenceException:
            return False

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="text_to_be_present_in_element_value">text_to_be_present_in_element_value(locator: Tuple[str, str], text_: str)</h4>



<p><a href="#text_to_be_present_in_element">text_to_be_present_in_element</a>をtextからvalue属性に変えてみました</p>



<p>もともと微妙な需要だったのにさらに下がってる気がする</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="text_to_be_present_in_element_value" data-lang="Python"><code>def text_to_be_present_in_element_value(
    locator: tuple[str, str], text_: str
) -&gt; Callable[[WebDriverOrWebElement], bool]:
    def _predicate(driver: WebDriverOrWebElement):
        try:
            element_text = driver.find_element(*locator).get_attribute(&quot;value&quot;)
            if element_text is None:
                return False
            return text_ in element_text
        except StaleElementReferenceException:
            return False

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="text_to_be_present_in_element_attribute">text_to_be_present_in_element_attribute(locator: Tuple[str, str], attribute_: str, text_: str)</h4>



<p><a href="#text_to_be_present_in_element_value">text_to_be_present_in_element_value</a>をvalue以外の属性を選べるようにしてみました</p>



<p>じゃあ<a href="#text_to_be_present_in_element_value">text_to_be_present_in_element_value</a>いらない・・・</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="text_to_be_present_in_element_attribute" data-lang="Python"><code>def text_to_be_present_in_element_attribute(
    locator: tuple[str, str], attribute_: str, text_: str
) -&gt; Callable[[WebDriverOrWebElement], bool]:
    def _predicate(driver: WebDriverOrWebElement):
        try:
            element_text = driver.find_element(*locator).get_attribute(attribute_)
            if element_text is None:
                return False
            return text_ in element_text
        except StaleElementReferenceException:
            return False

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="title_is">title_is(title: str)</h4>



<p>titleとの完全一致判定</p>



<p>title自体ちょっと使いにくいのに完全一致はなかなか難しい印象</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="title_is" data-lang="Python"><code>def title_is(title: str) -&gt; Callable[[WebDriver], bool]:
    def _predicate(driver: WebDriver):
        return driver.title == title

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="title_contains">title_contains(title: str)</h4>



<p>こちらはtitleの部分一致判定</p>



<p>完全一致よりは現実的だけどやっぱりtitleで照合はしないと思う</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="title_contains" data-lang="Python"><code>def title_contains(title: str) -&gt; Callable[[WebDriver], bool]:
    def _predicate(driver: WebDriver):
        return title in driver.title

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="url_contains">url_contains(url: str)</h4>



<p>urlの部分一致で判定</p>



<p>待機処理の条件にurlは使わないと思う</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="url_contains" data-lang="Python"><code>def url_contains(url: str) -&gt; Callable[[WebDriver], bool]:
    def _predicate(driver: WebDriver):
        return url in driver.current_url

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="url_matches">url_matches(pattern: str)</h4>



<p>こちらはurlを正規表現で判定</p>



<p>だから待機処理の条件にurlは・・・</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="url_matches" data-lang="Python"><code>def url_matches(pattern: str) -&gt; Callable[[WebDriver], bool]:
    def _predicate(driver: WebDriver):
        return re.search(pattern, driver.current_url) is not None

    return _predicate
</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="url_to_be">url_to_be(url: str)</h4>



<p>urlの完全一致で判定</p>



<p>だから待機処理の・・・</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="url_to_be" data-lang="Python"><code>def url_to_be(url: str) -&gt; Callable[[WebDriver], bool]:
    def _predicate(driver: WebDriver):
        return url == driver.current_url

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="url_changes">url_changes(url: str)</h4>



<p>urlの不一致で判定</p>



<p>だから・・・</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="url_changes" data-lang="Python"><code>def url_changes(url: str) -&gt; Callable[[WebDriver], bool]:
    def _predicate(driver: WebDriver):
        return url != driver.current_url

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="number_of_windows_to_be">number_of_windows_to_be(num_windows: int)</h4>



<p>ウィンドウ（＝タブ）の数で照合</p>



<p>いつ使うんですか？</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="number_of_windows_to_be" data-lang="Python"><code>def number_of_windows_to_be(num_windows: int) -&gt; Callable[[WebDriver], bool]:
    def _predicate(driver: WebDriver):
        return len(driver.window_handles) == num_windows

    return _predicate
</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="new_window_is_opened">new_window_is_opened(current_handles: List[str])</h4>



<p>新しいウィンドウができるまで待つらしい</p>



<p>いつ使うんですか？（2回目）</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="new_window_is_opened" data-lang="Python"><code>def new_window_is_opened(current_handles: list[str]) -&gt; Callable[[WebDriver], bool]:
    def _predicate(driver: WebDriver):
        return len(driver.window_handles) &gt; len(current_handles)

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="frame_to_be_available_and_switch_to_it">frame_to_be_available_and_switch_to_it(locator: Union[Tuple[str, str], str])</h4>



<p>指定のframeに移動できるまで待つ</p>



<p>待機処理でじゃなくてswitch_to.frameを安全にする使い方なら需要ありそう</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="frame_to_be_available_and_switch_to_it" data-lang="Python"><code>def frame_to_be_available_and_switch_to_it(
    locator: Union[tuple[str, str], str, WebElement],
) -&gt; Callable[[WebDriver], bool]:
    def _predicate(driver: WebDriver):
        try:
            if isinstance(locator, Iterable) and not isinstance(locator, str):
                driver.switch_to.frame(driver.find_element(*locator))
            else:
                driver.switch_to.frame(locator)
            return True
        except NoSuchFrameException:
            return False

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="staleness_of">staleness_of(element: WebElement)</h4>



<p>なんでこんな名前になったのか、、実態はis_enabledだけ</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="staleness_of" data-lang="Python"><code>def staleness_of(element: WebElement) -&gt; Callable[[Any], bool]:
    def _predicate(_):
        try:
            # Calling any method forces a staleness check
            element.is_enabled()
            return False
        except StaleElementReferenceException:
            return True</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="alert_is_present">alert_is_present()</h4>



<p>アラートに遷移できるか</p>



<p><a href="#frame_to_be_available_and_switch_to_it">frame_to_be_available_and_switch_to_it</a>と同じく、待機処理でじゃなくてswitch_to.alertを安全にする使い方なら需要ありそう</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="alert_is_present" data-lang="Python"><code>def alert_is_present() -&gt; Callable[[WebDriver], Union[Alert, Literal[False]]]:
    def _predicate(driver: WebDriver):
        try:
            return driver.switch_to.alert
        except NoAlertPresentException:
            return False

    return _predicate</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="any_of">any_of(*expected_conditions: Callable[[D], T])</h4>



<p>指定した複数のexpected_conditionsが一つでもTrueになればOK</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="any_of" data-lang="Python"><code>def any_of(*expected_conditions: Callable[[D], T]) -&gt; Callable[[D], Union[Literal[False], T]]:
    def any_of_condition(driver: D):
        for expected_condition in expected_conditions:
            try:
                result = expected_condition(driver)
                if result:
                    return result
            except WebDriverException:
                pass
        return False

    return any_of_condition</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="all_of">all_of(*expected_conditions: Callable[[D], Union[T, Literal[False]]])</h4>



<p>こちらは指定した複数のexpected_conditionsが全てTrueになればOK</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="all_of" data-lang="Python"><code>def all_of(
    *expected_conditions: Callable[[D], Union[T, Literal[False]]],
) -&gt; Callable[[D], Union[list[T], Literal[False]]]:
    def all_of_condition(driver: D):
        results: list[T] = []
        for expected_condition in expected_conditions:
            try:
                result = expected_condition(driver)
                if not result:
                    return False
                results.append(result)
            except WebDriverException:
                return False
        return results

    return all_of_condition</code></pre></div>



<h4 class="wp-block-heading anchor-set" id="none_of">none_of(*expected_conditions: Callable[[D], Any])</h4>



<p>こちらは指定した複数のexpected_conditionsが一つもTrueにならなければOK</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-file="none_of" data-lang="Python"><code>def none_of(*expected_conditions: Callable[[D], Any]) -&gt; Callable[[D], bool]:
    def none_of_condition(driver: D):
        for expected_condition in expected_conditions:
            try:
                result = expected_condition(driver)
                if result:
                    return False
            except WebDriverException:
                pass
        return True

    return none_of_condition</code></pre></div>



<h2 class="wp-block-heading">あとがき</h2>



<p>expected_conditionsは調べてみると知らないだけで多くの関数がありました</p>



<p><a href="#presence_of_element_located">presence_of_element_located</a>や<a href="#visibility_of_element_located">visibility_of_element_located</a>は有名ですが<a href="#text_to_be_present_in_element">text_to_be_present_in_element</a>や<a href="#element_to_be_clickable">element_to_be_clickable</a>も有用そうで今後活用してみたい！</p>



<p>引数はTuple型のlocatorとWebElement型のelement、どちらでも対応できるパターンがありますがどうせなら全部どちらにも対応できるパターンにしてほしい・・・</p>
]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/python_wait/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Python】netkeibaをスクレイピングする-その1</title>
		<link>https://javeo.jp/python-scraping-netkeiba-1/</link>
					<comments>https://javeo.jp/python-scraping-netkeiba-1/#respond</comments>
		
		<dc:creator><![CDATA[ジャベ雄]]></dc:creator>
		<pubDate>Wed, 05 Jun 2024 23:00:00 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[netkeiba]]></category>
		<category><![CDATA[Selenium]]></category>
		<category><![CDATA[スクレイピング]]></category>
		<guid isPermaLink="false">https://javeo.jp/?p=2240</guid>

					<description><![CDATA[目次 スクレイピングを始める前に一度手動で操作しながらURLやページを観察する最初に静的ページか動的ページか確認するまずはレースマスタを作る（ベースの一覧を取得する）レース一覧を取得するために動作を確認するレース一覧を取 [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="codoc-evacuations" style="display:none;" data-shortcode=""></div>
<div class="wp-block-cocoon-blocks-info-box block-box primary-box">
<p>趣味で競馬をやっている私、ジャベ雄です</p>



<p>ブラッドスポーツと呼ばれるほど血統が重要視されていたり、会場による傾向や枠の有利不利などデータがものを言う競馬界においてデータ収集先の代表格、<a rel="noreferrer noopener nofollow" target="_blank" href="https://www.netkeiba.com/" data-type="link" data-id="https://www.netkeiba.com/">netkeiba</a>をPythonでスクレイピングする方法をまとめます</p>



<p>今回は&#8221;netkeibaをスクレイピングする&#8221;ことではなく、&#8221;netkeibaを題材にスクレイピングを学ぶ&#8221;ところに重きを置いているのでその前提で見てもらえると嬉しいです</p>
</div>




  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-18" checked><label class="toc-title" for="toc-checkbox-18">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">スクレイピングを始める前に</a></li><li><a href="#toc2" tabindex="0">一度手動で操作しながらURLやページを観察する</a></li><li><a href="#toc3" tabindex="0">最初に静的ページか動的ページか確認する</a></li><li><a href="#toc4" tabindex="0">まずはレースマスタを作る（ベースの一覧を取得する）</a><ol><li><a href="#toc5" tabindex="0">レース一覧を取得するために動作を確認する</a></li><li><a href="#toc6" tabindex="0">レース一覧を取得するための結論</a></li></ol></li><li><a href="#toc7" tabindex="0">実際のプログラム</a></li><li><a href="#toc8" tabindex="0">あとがき</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">スクレイピングを始める前に</span></h2>



<p>今回はnetkeibaから大量のデータを取得しますし、取得したデータは分析してナンボなので取得情報はデータベース（今回はXserverのMariaDB）に保存する前提でプログラム作成していますので必要に応じて適宜変更してください</p>



<p>PythonでXserverを操作する方法は↓↓を参考にどうぞ</p>




<a rel="noopener follow noreferrer" target="_blank" href="https://javeo.jp/python-xserver-connect" title="【Python】Xserverのデータベースを操作する" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="320" height="198" src="https://javeo.jp/wp-content/uploads/2023/07/python-320x198.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://javeo.jp/wp-content/uploads/2023/07/python-320x198.png 320w, https://javeo.jp/wp-content/uploads/2023/07/python-240x148.png 240w, https://javeo.jp/wp-content/uploads/2023/07/python-640x396.png 640w" sizes="(max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【Python】Xserverのデータベースを操作する</div><div class="blogcard-snippet internal-blogcard-snippet">PythonでXserverのデータベースであるMySQL（MariaDB）を操作するためのコネクタープログラムを作りました。データベースからの情報取得はもちろん、追加・更新もできるので外部データ連携にも使えますので参考にどうぞ。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://javeo.jp" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">javeo.jp</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2024.03.12</div></div></div></div></a>



<h2 class="wp-block-heading"><span id="toc2">一度手動で操作しながらURLやページを観察する</span></h2>



<p>スクレイピングの初手はRPA的に情報取得すべきページへ遷移するところからです</p>



<p>一度手動で一連の動作を実施しながら特にURLに注目しながら観察すればパラメータを変更しながらページを読み込むのか、ボタンをクリックする必要があるのかなどがわかります</p>



<h2 class="wp-block-heading"><span id="toc3">最初に静的ページか動的ページか確認する</span></h2>



<p>Pythonでスクレイピングをする時の2台巨塔&#8221;<span class="marker-under"><strong>Selenium</strong></span>&#8220;と&#8221;<strong><span class="marker-under">Beautifulsoup</span></strong>&#8220;ですが、どちらを使うかの切り分けはそのサイト（ページ）がJavascriptを有効にする必要があるかどうか</p>



<p>確認するためにははChromeの設定メニューで切り替えるのですが、頻繁に切り替える可能性がある人はChrome拡張機能（私は<a rel="noreferrer noopener nofollow" target="_blank" href="https://chromewebstore.google.com/detail/quick-javascript-switcher/geddoclleiomckbhadiaipdggiiccfje?hl=ja" data-type="link" data-id="https://chromewebstore.google.com/detail/quick-javascript-switcher/geddoclleiomckbhadiaipdggiiccfje?hl=ja">Quick Javascript Switcher</a>）を使うこと推奨です</p>



<p>で、肝心のnetkibaはどうかと言うと開催レース一覧の画面がJavascript無効ではと永遠と馬が走っている状態になってしまうので有効にしておく必要があるとわかるので<strong>Selenium</strong>必須</p>



<figure class="wp-block-image size-large is-resized"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2024/05/2024-05-29_23h02_31.png"><img decoding="async" width="1024" height="490" src="https://javeo.jp/wp-content/uploads/2024/05/2024-05-29_23h02_31-1024x490.png" alt="" class="wp-image-2253" style="width:840px;height:auto" srcset="https://javeo.jp/wp-content/uploads/2024/05/2024-05-29_23h02_31-1024x490.png 1024w, https://javeo.jp/wp-content/uploads/2024/05/2024-05-29_23h02_31-300x144.png 300w, https://javeo.jp/wp-content/uploads/2024/05/2024-05-29_23h02_31-150x72.png 150w, https://javeo.jp/wp-content/uploads/2024/05/2024-05-29_23h02_31-768x368.png 768w, https://javeo.jp/wp-content/uploads/2024/05/2024-05-29_23h02_31-1536x735.png 1536w, https://javeo.jp/wp-content/uploads/2024/05/2024-05-29_23h02_31.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>ぶっちゃけ、&#8221;<strong>Beautifulsoup</strong>&#8220;だけで完結するサイトは少ないので&#8221;<span class="bold-red">Selenium</span>&#8220;を使う前提でもOK</p>



<h2 class="wp-block-heading"><span id="toc4">まずはレースマスタを作る（ベースの一覧を取得する）</span></h2>



<p>私のスクレイピング方針のようなものですが最初は一覧情報を作ってその後に詳細情報を収集します</p>



<p>なぜかと言うとスクレイピングはNW状況含めて予想外にエラーが起こる可能性がありますし、詳細データでは予想外のデータもあるのでエラーが起こる前提として処理を途中から再開できるような仕様にすることが望ましいです</p>



<p>具体的にはnetkeibaなら開催日ごとのレース一覧、ECサイトなら検索結果画面にある商品ページリストを収集するイメージです</p>



<p>ここで&#8221;<strong>一度手動で操作しながらURLやページを観察する</strong>&#8220;に倣ってプログラムの方針を考えます</p>



<h3 class="wp-block-heading"><span id="toc5">レース一覧を取得するために動作を確認する</span></h3>



<p>まずは今週のレース一覧ページを開くとURLに&#8221;kaisai_date=yyyymmdd&#8221;がパラメータになっていることがわかるのでここを変更すれば良さそう</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h27_07.png"><img decoding="async" width="1024" height="538" src="https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h27_07-1024x538.png" alt="" class="wp-image-2283" srcset="https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h27_07-1024x538.png 1024w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h27_07-300x158.png 300w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h27_07-150x79.png 150w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h27_07-768x403.png 768w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h27_07.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>このパラメータを変えれば当然その日のレース一覧に変わるわけですが開催されていない日を指定するとレースが何も表示されないので1日ずる変更すると無駄な読み込みになってしまう</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h23_14.png"><img decoding="async" width="1024" height="538" src="https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h23_14-1024x538.png" alt="" class="wp-image-2284" srcset="https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h23_14-1024x538.png 1024w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h23_14-300x158.png 300w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h23_14-150x79.png 150w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h23_14-768x403.png 768w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h23_14.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>もう一つ、上部の&#8221;前&#8221;や&#8221;次&#8221;をクックすると1週間分の日付が前後することがわかります</p>



<figure class="wp-block-image size-large"><a rel="follow noopener noreferrer" target="_blank" href="https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h34_06.png"><img decoding="async" width="1024" height="538" src="https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h34_06-1024x538.png" alt="" class="wp-image-2286" srcset="https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h34_06-1024x538.png 1024w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h34_06-300x158.png 300w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h34_06-150x79.png 150w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h34_06-768x403.png 768w, https://javeo.jp/wp-content/uploads/2024/06/2024-06-02_22h34_06.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<h3 class="wp-block-heading"><span id="toc6">レース一覧を取得するための結論</span></h3>



<p>楽をするなら最初のパターンで取得対象の日まで1日読み込めばいいんですが、なるべくサイトへ負荷をかけないように無駄なページロードを避けるためやめました</p>



<p>続いて土日だけにするとイレギュラー開催（土日以外）の情報がカバーできなので止めました<br>※イレギュラー開催→1月の金杯、年末のホープフル、3連休の月曜日開催など</p>



<p>結論、取得したい起点の日を表示した状態から&#8221;次&#8221;ボタンをクリックし続けて日付が当日以上になるまでループする仕様にしました</p>



<h2 class="wp-block-heading"><span id="toc7">実際のプログラム</span></h2>



<p>私が実際に使っているプログラムですが必要な項目は違うでしょうし、データベース操作用のプログラムも違うと思うので適当に変更してください</p>



<p>コメントを大量に残しているのでプログラム自体の説明は割愛</p>



<div class="hcb_wrap"><pre class="prism undefined-numbers lang-python" data-lang="Python"><code>from datetime import datetime
import re
import urllib.parse
from time import sleep

from bs4 import BeautifulSoup
from db_connector import xserver_keiba
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait


# ====================================================================================================
class data_class:
    def __init__(self, data_title: list) -&gt; None:
        self.race_id = &#39;&#39;
        self.race_date = &#39;&#39;
        self.race_times = data_title[0]
        self.course_place = data_title[1]
        self.race_days = data_title[2]
        self.race_no = 0
        self.race_name = &#39;&#39;
        self.race_grade = &#39;&#39;
        self.race_time = &#39;&#39;
        self.coruse_type = &#39;&#39;
        self.course_distance = &#39;&#39;
        self.not_found = 0

    def upsert_sql(self):
        sql = f&#39;&#39;&#39;
            INSERT INTO race_mst(race_id,race_date,race_times,course_place,race_days,race_no,race_name,race_grade,race_time,coruse_type,course_distance,not_found)
            values ({self.race_id},&#39;{self.race_date}&#39;,&#39;{self.race_times}&#39;,&#39;{self.course_place}&#39;,&#39;{self.race_days}&#39;,{self.race_no},&#39;{self.race_name}&#39;,&#39;{self.race_grade}&#39;,&#39;{self.race_time}&#39;,&#39;{self.coruse_type}&#39;,&#39;{self.course_distance}&#39;,{self.not_found})
            ON DUPLICATE KEY UPDATE race_date=&#39;{self.race_date}&#39;,race_times=&#39;{self.race_times}&#39;,course_place=&#39;{self.course_place}&#39;,race_days=&#39;{self.race_days}&#39;,race_no={self.race_no},race_name=&#39;{self.race_name}&#39;,race_grade=&#39;{self.race_grade}&#39;,race_time=&#39;{self.race_time}&#39;,course_distance=&#39;{self.course_distance}&#39;,not_found=&#39;{self.not_found}&#39;
        &#39;&#39;&#39;.replace(&quot;&#39;&#39;&quot;, &quot;Null&quot;)
        return sql


# ====================================================================================================
def grade_converter(grade_class) -&gt; str:
    # クラス名からレースのグレードを判定して返す
    if &#39;Icon_GradeType1&#39; in grade_class:
        return &#39;GⅠ&#39;
    elif &#39;Icon_GradeType2&#39; in grade_class:
        return &#39;GⅡ&#39;
    elif &#39;Icon_GradeType3&#39; in grade_class:
        return &#39;GⅢ&#39;
    elif &#39;Icon_GradeType4&#39; in grade_class:
        return &#39;重賞&#39;
    elif &#39;Icon_GradeType5&#39; in grade_class:
        return &#39;OP&#39;
    elif &#39;Icon_GradeType6&#39; in grade_class:
        return &#39;1600万下&#39;
    elif &#39;Icon_GradeType7&#39; in grade_class:
        return &#39;1000万下&#39;
    elif &#39;Icon_GradeType8&#39; in grade_class:
        return &#39;900万下&#39;
    elif &#39;Icon_GradeType9&#39; in grade_class:
        return &#39;500万下&#39;
    elif &#39;Icon_GradeType10&#39; in grade_class:
        return &#39;JGⅠ&#39;
    elif &#39;Icon_GradeType11&#39; in grade_class:
        return &#39;JGⅡ&#39;
    elif &#39;Icon_GradeType12&#39; in grade_class:
        return &#39;JGⅢ&#39;
    elif &#39;Icon_GradeType13&#39; in grade_class:
        return &#39;WIN5&#39;
    elif &#39;Icon_GradeType14&#39; in grade_class:
        return &#39;特選&#39;
    elif &#39;Icon_GradeType15&#39; in grade_class:
        return &#39;L&#39;
    elif &#39;Icon_GradeType16&#39; in grade_class:
        return &#39;3勝&#39;
    elif &#39;Icon_GradeType17&#39; in grade_class:
        return &#39;2勝&#39;
    elif &#39;Icon_GradeType18&#39; in grade_class:
        return &#39;1勝&#39;
    else:
        pass


# ====================================================================================================
def main():
    db = xserver_keiba()
    # データベース内の最新レース日取得する
    sql = &#39;&#39;&#39;
        SELECT
            MAX(race_date) AS last_get_date
        FROM
            race_mst
    &#39;&#39;&#39;
    ret = db.fetch(sql)
    # dbにあるレース開催日の最大値を最初の取得対象日にする
    # レースデータがない（≒初回）は&#39;2014-01-05&#39;で固定する
    target_date = datetime(2014, 1, 5) if ret[0][&#39;last_get_date&#39;] is None else ret[0][&#39;last_get_date&#39;]
    options = Options()
    # 画像を読み込まない
    options.add_argument(&#39;--blink-settings=imagesEnabled=false&#39;)
    # シークレットモードで起動
    options.add_argument(&#39;--incognito&#39;)
    # Chromeを起動する
    driver = webdriver.Chrome(options=options)
    # urlに日付を設定すれば対象日のレース画面になる
    driver.get(f&quot;https://race.netkeiba.com/top/race_list.html?&kaisai_date={datetime.strftime(target_date, &#39;%Y%m%d&#39;)}&quot;)
    sleep(0.5)
    # 対象日付が未来日になるまでループする
    while target_date &lt; datetime.today():
        next_date_tab = True
        while next_date_tab is True:
            next_date_tab = False
            # ページソースをBeautifulSoupに食わせる
            soup = BeautifulSoup(driver.page_source)
            # 上部の日付のliにを確認
            for race_date in soup.select(&#39;#date_list_sub &gt; li[role=&quot;tab&quot;]&#39;):
                # 上部の日付のliにあるdate属性から対象の日付を取得して未来日になったら終わらせる
                if int(race_date.get(&#39;date&#39;)) &gt;= int(datetime.now().strftime(&#39;%Y%m%d&#39;)):
                    break
                # 取得済みの日付ならスキップ・未取得ならクリックする
                sql = f&#39;&#39;&#39;
                    SELECT
                        *
                    FROM
                        race_mst
                    WHERE
                        race_date=&#39;{race_date.get(&#39;date&#39;)}&#39;
                &#39;&#39;&#39;
                ret = db.fetch(sql)
                if len(ret) &gt; 0:
                    continue
                else:
                    driver.find_element(By.CSS_SELECTOR, f&#39;#date_list_sub &gt; li2026/04/11&#39;).click()
                # ↑のクリックでソースが書き換わっているのでもう一度ページソースをBeautifulSoupに食わせる
                soup = BeautifulSoup(driver.page_source)
                # id=&quot;RaceTopRace&quot;が複数ある可能性があるのでループさせる
                for RaceTopRace in soup.select(&#39;#RaceTopRace&#39;):
                    # 今表示されているRaceTopRaceは上の階層の属性で判断する
                    if RaceTopRace.parent.get(&#39;aria-hidden&#39;) == &#39;true&#39;:
                        continue
                    # 会場別でdlが分かれているのでループする
                    for dl in RaceTopRace.select(&#39;dl.RaceList_DataList&#39;):
                        # レースごとにliが分かれてるからループする
                        for li in dl.select(&#39;dd.RaceList_Data &gt; ul &gt; li.RaceList_DataItem&#39;):
                            # --- ここから実際のデータ取得 ---
                            # リンクが複数あるから&#39;result.html&#39;を含んでいるかで正誤判定する
                            for a in li.select(&#39;a&#39;):
                                if &#39;result.html&#39; in a.get(&#39;href&#39;):
                                    # 会場のヘッダー部から会場情報を取得する
                                    data = data_class(dl.select_one(&#39;dt.RaceList_DataHeader &gt; div.RaceList_DataHeader_Top &gt; p.RaceList_DataTitle&#39;).get_text(separator=&#39;/&#39;, strip=True).split(&#39;/&#39;))
                                    # urlのクエリパラメータにレースIDがあるので分解する
                                    url = a.get(&#39;href&#39;)
                                    qs = urllib.parse.urlparse(url).query
                                    qs_d = urllib.parse.parse_qs(qs)
                                    data.race_id = qs_d[&#39;race_id&#39;][0]
                                    # --- a配下にレース情報があるので取得する ---
                                    # レース番号
                                    data.race_no = a.select_one(&#39;div.Race_Num.Race_Fixed &gt; span&#39;).get_text(strip=True).replace(&#39;R&#39;, &#39;&#39;)
                                    # レース名
                                    data.race_name = a.select_one(&#39;div.RaceList_ItemContent &gt; div.RaceList_ItemTitle &gt; span.ItemTitle&#39;).get_text(strip=True)
                                    # レースのグレード設定があれば取得する
                                    if len(a.select(&#39;div.RaceList_ItemContent &gt; div.RaceList_ItemTitle &gt; span.Icon_GradeType&#39;)) &gt; 0:
                                        data.race_grade = grade_converter(a.select_one(&#39;div.RaceList_ItemContent &gt; div.RaceList_ItemTitle &gt; span.Icon_GradeType&#39;).get(&#39;class&#39;))
                                    # 出走時刻
                                    data.race_time = a.select_one(&#39;div.RaceList_ItemContent &gt; div.RaceData &gt; span.RaceList_Itemtime&#39;).get_text(strip=True)
                                    # 障害レースはクラス設定がないので分岐
                                    if len(a.select(&#39;div.RaceList_ItemContent &gt; div.RaceData &gt; span.RaceList_ItemLong&#39;)) &gt; 0:
                                        # 芝・ダートはクラスが設定されているからセレクタ―で指定する
                                        data.coruse_type = a.select_one(&#39;div.RaceList_ItemContent &gt; div.RaceData &gt; span.RaceList_ItemLong&#39;).get_text(strip=True)[0]
                                        data.course_distance = re.findall(R&#39;\d+&#39;, a.select_one(&#39;div.RaceList_ItemContent &gt; div.RaceData &gt; span.RaceList_ItemLong&#39;).get_text(strip=True))[0]
                                    else:
                                        # 障害はクラスが設定されていないから苦肉でindex指定する
                                        data.coruse_type = a.select(&#39;div.RaceList_ItemContent &gt; div.RaceData &gt; span&#39;)[1].get_text(strip=True)[0]
                                        data.course_distance = re.findall(R&#39;\d+&#39;, a.select(&#39;div.RaceList_ItemContent &gt; div.RaceData &gt; span&#39;)[1].get_text(strip=True))[0]
                                    # レース日は変数から反映させる
                                    data.race_date = race_date.get(&#39;date&#39;)
                                    db.execute(data.upsert_sql())
                next_date_tab = True
                break

        # 次ボタンを押すと次開催日に移るのでクリックする
        try:
            WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, &#39;#nextBtn &gt; a&#39;)))
        except TimeoutException:
            # 次がボタンになっていない（≒次がない）時はループを抜ける（けど、過去データしか取得しないから基本的にありえない）
            break
        driver.find_element(By.CSS_SELECTOR, &#39;#nextBtn &gt; a&#39;).click()
        # 一瞬でもsleepしないと処理が早すぎてエラーになる可能性があるので0.5秒待機
        sleep(0.5)
        # クエリパラメータに開催日があるので日付型に変換する
        qs = urllib.parse.urlparse(driver.current_url).query
        qs_d = urllib.parse.parse_qs(qs)
        target_date = datetime.strptime(qs_d[&#39;kaisai_date&#39;][0], &#39;%Y%m%d&#39;)
    # 最後にChromedriverを落として終了
    driver.close()
    driver.quit()


# ====================================================================================================
if __name__ == &#39;__main__&#39;:
    main()
</code></pre></div>



<h2 class="wp-block-heading"><span id="toc8">あとがき</span></h2>



<p>プログラムはもう少しスマートに書いた方が良さそうですが問題なく動いているのでこの辺りで手打ちにしました</p>



<p>netkeibaのスクレイピングにはまだ先は長いですが第一歩のまとめでした</p>



<p>次はレース画面を収集する方法をまとめます！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://javeo.jp/python-scraping-netkeiba-1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
