selenium(Python)でstyleが"display: none;"となっている要素を取得する

 他の人も既に同様の記事を書いているのですが、メモ代わりにブログに残します。

使える場面

 例えば以下のような<li>タグがあった場合、

<li style="display: none;">
  <a href="...">
    <div class="title">fuga</div>
  </a>
  <div class="description">xxxxxxxxxxx</div>
</li>
<li style="display: none;">
  <a href="...">
    <div class="title">hoge</div>
  </a>
  <div class="description">xxxxxxxxxxx</div>
</li>

...

こういうの、ページネーションとセットでよく出てくる気がします。 次ページの番号をクリックすると、別リンクに飛ばすよくある仕様でなく。 指定した番号に対応する<li>noneからblockなどに切り替えると同時に、それ以外の<li>タグをnoneに切り替え非表示とすることで、ユーザーに他ページに飛んだように見せることがよくある気がします。

こういうサイト。例えばBeautifulSoupでスクレイピングしようとしてもうまくいかないので、seleniumを使ってjsをいじりながらやっていくのが早いかと思います。

コード

 seleniumでjsのコードを動かす場合、execute_scriptメソッドが非常によく使われるかと思います。例えば要素をクリックしたり、スクショしたり、、、etc.

そんなexecute_scriptですが、styleの書き換えも簡単に行うことが可能です。

driver.execute_script("arguments[0].style.display='block';",{要素})

結果の確認

 確認のため状況HTMLをローカルに保存してseleniumスクレイピングしてみます。まず以下のコードでローカルに保存したHTMLファイルを開いてみます。

url = 'file://{htmlファイルの絶対パス}'
chrome_options = webdriver.ChromeOptions()
driver = webdriver.Chrome(options=chrome_options)
driver.get(url)

結果

f:id:spider-man-dance:20211019142559p:plain
selenium1

非表示であることが確認できます。 次に以下の行を追記してコードを再実行してみます。

url = 'file://{htmlファイルの絶対パス}'
chrome_options = webdriver.ChromeOptions()
driver = webdriver.Chrome(options=chrome_options)
driver.get(url)

elems = elems.find_elements_by_tag_name('li')
for elem in elems:
    driver.execute_script("arguments[0].style.display='block';", elem)

結果

f:id:spider-man-dance:20211019143021p:plain
selenium2

CSSが書き換えられ<li>タグの中身が表示されているのが分かります。これで.textでテキストを取得したりすることも可能になります。

追記

プロ野球のデータ可視化サイトを作りました!ぜひ遊びにきてください!

YahooニュースのRSS一覧から好きなニュースをチョイスして新着情報を通知してくれるようにした話

YahooニュースRSS一覧について

 こちら初めて知ったのですが、結構内容充実していました。様々な媒体から多くの新着情報が出ています。

YahooニュースRSS一覧

とりあえずこの中から気になった記事のURLをコピペしてconfigに貼り付ければデイリーで新着情報をスクレイピングしてきて、HTMLを生成。それをメール通知してくれるとこまでやってみましたが、結構いい感じです。

メールのイメージ
メールのイメージ

ハンカチ王子、、、

構成

f:id:spider-man-dance:20211001153621p:plain
AWS構成

感想

  • YahooのRSSはかなり充実しているので結構情報のキャッチには使える。
  • メールでHTMLを通知する際、ダークモード対応できるようにCSSを設定していないと思わぬところで色反転を起こすので注意しないといけないことを初めて知った。

pandasでexcelを開くときは「xlrd」より「openpyxl」の方が安定してるかもしれない話

はじめに

pandasを初めて使って早2年強。この度業務で初めてexcelファイルを取り扱う必要が出てきました。 テキストファイル安定のこのご時世、エクセルみたいなバイナリーファイルという時点で不安はあったのですが、案の定読み込みの時点で少し面倒だったので一応解決法などをメモしておきます。 尚、pandasのバージョンは1.2.1です。

解決法

まず普通にread_excelで読み込もうとすると以下のエラーが

importerror: missing optional dependency 'xlrd'. install xlrd >= 1.0.0 for excel support use pip or conda to install xlrd.

なんでもxlrdというライブラリが別途必要とのこと。そこで現時点で最新だったバージョン2.0.1をインストールして再度試してみることに

your version of xlrd is 2.0.1. in xlrd >= 2.0, only the xls format is supported. install openpyxl instead.

またまたエラーです。どうやら2.0以上のxlrdだとエクセルの拡張子がxlsのものしか読み込めず、比較的新しいxlsxのものに関してはエラーが発生してしまうようです。時代に逆行してますね。

xlrdのバージョンを1.2.0に下げてみました。

attributeerror: 'elementtree' object has no attribute 'getiterator'



は??

本日3度目のエラー。エクセルファイル恐るべしです。 どうやら調べてみると結局xlrdよりもopenpyxlの方がよさげ、バージョン3.0.6をインストールし下記のようにreac_excelの引数に以下を加えたところ、ようやくファイル読み込みができました。

df = pd.read_excel('data.xlsx', engine='openpyxl')


【AWS】踏み台サーバを利用した多段sshを構築しVScodeで接続するまで

 多段sshでサーバーを構築することになったので作業がてらメモ。尚、プライベートサブネット内のEC2からの戻りトラフィックを有効にしたい場合、下記構成にプラスして、NATゲートウェイをパブリックサブネット内におき、プライベートサブネットへのルーティングを設定しないと行けないので追加作業が必要です。(このブログでは書いていませんが)


イメージ図

f:id:spider-man-dance:20210119224139p:plain
aws


ネットワークの設定

VPCの作成

  • IPv4 CIDR block (要はVPCで使用するIPv4アドレスの範囲)については、/16より大きな範囲を指定する事はできない。

f:id:spider-man-dance:20210119224919p:plain
aws vpc

後ほどDNSからホスト名を割り当てられる様、DNSホスト名を有効化する。

f:id:spider-man-dance:20210119232641p:plain


サブネットの作成

  • 先ほどのVPC空間に割り当てられたアドレス範囲内で、public subnetとprivate subnetの2つのサブネットを作成します。
  • 下記キャプチャはpublic subnetの例、先ほど指定したVPCのアドレス範囲(172.31.0.0 ~ 172.31.255.255)の内、172.31.10.0 ~ 172.31.10.255をpublic subnetに分割している。

f:id:spider-man-dance:20210119230404p:plain
サブネット


Internet Gatewayの作成

  • Internet GatewayVPCをインターネットに接続する仮想ルーター
  • detach状態で作成されるため、作成後に先ほどのVPCにアタッチする


Route Tableの作成

  • VPCを作成するとデフォルトでルートテーブルが作成されるので、こちらをprivate用に設定する。
  • 上記とは別にインターネットゲートウェイへのルーティングを持つルートテーブルを作成する。

private route table(デフォルトで作成されたルートテーブル)は分かりやすいように名前をつけておく。

f:id:spider-man-dance:20210119231604p:plain

public用の作成したルートテーブルには、先ほど作成したインターネットゲートウェイへのルートを追加する。 f:id:spider-man-dance:20210119232018p:plain

サブネットの関連付けで[編集]を押下し、先ほど作成したpublic subnetを追加する。

f:id:spider-man-dance:20210119232331p:plain


セキュリティグループの編集

  • デフォルトで作成されたセキュリティグループは「同一セキュリティグループ内の制限なしアクセス」が定義されているだけなので、インバウンドルールを編集する。

f:id:spider-man-dance:20210119233339p:plain

これで、sshのみで接続可能なインスタンスが作成される。

尚、これとは別にprivateサーバー用のセキュリティグループも用意する。


EC2作成

踏み台サーバー作成

(今回OSはubuntu 20.04.LTSで作成)

先ほど作成したVPC領域と、public subnetを指定し、パブリックIPアドレスの自動割り当てを有効化する。 f:id:spider-man-dance:20210119233818p:plain

このインスタンスにはプライベートIPアドレスも指定する。先ほど指定したアドレスの範囲から指定(指定しなければ自動的に割り当てもされる)

f:id:spider-man-dance:20210119234223p:plain

尚、セキュリティグループの設定は先ほど作成した既存のもの(public用)を指定する。


privateサーバーの作成

先ほどのpublicサーバーと殆ど同じだが、自動割り当てパブリックIPを無効化することを忘れずに(仮にIPアドレスが割り当てられても外部からは繋がらない)。尚、割り当てるサブネットやセキュリティグループもprivate用にする。間違えてpublic用にしないように注意


踏み台サーバーからプライベートサーバーにsshアクセス

まず、以下のコマンドで踏み台サーバーへアクセスできることを確認

ssh -i {秘密鍵} {ユーザー名}@{パブリックIPv4アドレス}

f:id:spider-man-dance:20210120214759p:plain

次に以下のコマンドでプライベートサーバーへ外部インターネットから一気にログインできることを確認

ssh -o ProxyCommand='ssh -i {秘密鍵} {ユーザー名}@{踏み台サーバーパブリックIPv4アドレス} -W {プライベートサーバーのローカルIPアドレス}:22' -i {秘密鍵} {ユーザー名}@{プライベートサーバーのローカルIPアドレス}

f:id:spider-man-dance:20210120215532p:plain

同じubuntuマシンなので分かりづらいですが、先ほどの踏み台サーバーとは異なるローカルIPアドレスである事が分かります。 次回以降のログインを楽にするために~/.ssh/configに以下のように追記します。

Host {publicのホスト名}
 HostName {踏み台サーバーパブリックIPv4アドレス}
 Port 22
 User {ユーザー名}
 IdentityFile {秘密鍵}
 ForwardAgent yes

Host {privateのホスト名}
 HostName {プライベートサーバーのローカルIPアドレス}
 Port 22
 User {ユーザー名}
 IdentityFile {秘密鍵}
 ProxyCommand ssh -W %h:%p {publicのホスト名}

そうすれば次回以降ssh {privateのホスト名}で一発ログインできます。楽だし、踏み台サーバーに秘密鍵を置いたりする必要もなく安心です。


VSCode で接続

以前の記事のVSCodeで編集参照


ImageOnlyTransformクラスを継承して、RandomShadowのdata augmentationを実装

CutoutとRandom Erasing

 最早定番となったdata augmentationの手法であるCutout/Random Erasing、入力画像をランダムなマスクで欠落させることで、より強い正則化の効果を作り出すことを狙いとしています。

Cutout [arXiv]

f:id:spider-man-dance:20200903194352p:plain
Cutout



Random Erasing [arXiv]

f:id:spider-man-dance:20200903194720p:plain
Random Erasing

albumentation

 data augmentation時によく使われるalbumentationsですが、基底クラスを継承する事で自作のdata augmentationクラスを作成することができます。 Albumentationは次の2つの基底となるクラスが存在します。

  • ImageOnlyTransform・・・画像のみに処理を適用する
  • DualTransform・・・画像+物体検出(+その他)に処理を適用する

 実際に作成する際はinputする画像だけに処理すれば良いのか、それとも教師ラベルとなるマスク自体にも処理をすべきなのかで上記2つのどちらを継承するかが変わってきます。

RandomShadow

 先ほどまでのCutoutなどとは異なり、完全に情報を欠落させるのではなく、輝度を落としたい場面がでてきたので新しく自作クラスを作成しました。

ImageOnlyTransformを継承したRandomShadowの実装

実際に使用してみたイメージです。

import cv2
import matplotlib.pyplot as plt

random.seed(1)
img_origin = cv2.imread('baseball.png')
img_origin = cv2.cvtColor(img_origin, cv2.COLOR_BGR2RGB)
img = img_origin.copy()

img_shadow = RandomShadow(p=1.0)(image=img)['image']

fig, axes = plt.subplots(1, 2, figsize=(12, 6))
axes[0].imshow(img_origin)
axes[1].imshow(img_shadow)

plt.show()

f:id:spider-man-dance:20200903214823p:plain

Linuxのrenameコマンドについて

経緯

 手元にある大量のjpgファイル。頭文字に一括で文字を付けたい時に今までは以下のコマンドで行っていました。

# rename "s/[変更前]/[変更後]" [ File-Path ]
# 拡張子に".jpg"をもつ全てのファイルに対して先頭に"hoge-"を追加

$ rename "s/^/hoge-/" *.jpg 

 ただ今まで問題なかったこのコマンド。他の環境で同じようにやろうとしたところ、使えないという事態に陥ってしまいました。

解決法

 実は上記のコマンドは、Ubuntu環境下でのrenameでした。今回はCentOSを使用していたので、上記のコマンドが使えなかったようです。下記のコマンドで無事処理することができました。

# rename [変更前] [変更後] [ File-Path ]

$ rename "" hoge- *.jpg

AtCoder 東京海上日動 プログラミングコンテスト2020

AB2完の緑パフォでした。そして今回のコンテストでようやくレート緑になることができました! f:id:spider-man-dance:20200614005522p:plain

個人的にレート緑は最初の目標として掲げていたので、ようやくですが入緑できてほっとしています。これからも少しずつ伸ばしていきたい。

A - Nickname

問題のリンク

概要

  • 省略

コード

S = input()
print(S[:3])



B - Tag

問題のリンク

概要

  • 二次元軸での鬼ごっこ問題。鬼役の座標と速度。逃げる役の座標と速度が与えれるので、制限時間以内に追いつけるかどうかを判定。

制約

省略

考察

省略

コード

A, V = map(int, input().split())
B, W = map(int, input().split())
T = int(input())

diff = abs(A-B)

if (V-W)*T >= diff:
    print('YES')
else:
    print('NO')



C - Lamps

問題のリンク

概要

  • 省略

制約

  •  1 ≤ N ≤ 2 × 10^{5}
  •  1 ≤ K ≤ 2 × 10^{5}
  •  0 ≤ A_i ≤ N

考察

 今回解けなかった問題。解説で学んだいもす法を振り返りながら実装して行こうと思います。

いもす法の考え

f:id:spider-man-dance:20200614121614p:plain

 スライドにしてみましたが、これが一番分かりやすいと思います。左図はのように一定の区間をドンドン足し合わせていく操作については、右図のようにその始点と終点+1のポイントに着目することで、大幅に計算量を減らせます。(始点と終点の間全てに+1をしてしまっては計算量が膨大になってしまうことはイメージできると思います。)よってこの方法を使うと、スライドの操作自体は見ての通り、 Order(N)になるので、これを K回だけ繰り返すとすると、 Order(NK)で問題を解くことが可能です。  ただここで問題が一つあり、最悪ケースの場合( N = 2 × 10^{5}, K = 2 × 10^{5})で Order(NK)だとAtCoderでは通りません。ただこれも解説で触れていたのですが、今回の問題設定の場合、 lon(N)の操作で収束してしまうことが分かるので、 Kはが 41回以上の場合、問答無用で答えは[N] * Nの配列になってしまいます。

コード

import numpy as np
from numba import jit
N, K = map(int, input().split())
A = np.array(list(map(int, input().split())), dtype=np.int64)

# 高速化
@jit
def imo(a, n):
    imos = np.zeros(n+1, dtype=np.int64)
    for i in range(n):
        imos[max(0, i-a[i])] += 1
        imos[min(n, i+a[i])+1] -= 1

    # 累積和はnumpyの方が高速
    immo = np.zeros(n+1, dtype=np.int64)
    immo = np.cumsum(imos)

    return immo[:n]


for _ in range(min(K, 41)):
    A = imo(A, N)

print(*A)