ひよこになりたい

Programming Server Network Security CTF and so on

Python+Selenium+Chrome(+BeautifulSoup)でスクレイピングする

以前Python+Selenium+Phantom.js+Beautifulsoupでスクレイピングする - ひよこになりたいという記事を書きました。

zipsan.hatenablog.jp

当時はChromeを入れる必要がなく、バイナリを置くだけで使えるPhantom.jsが非常に便利でこれを使っていたのですが、去年、Phantom.jsのメンテナンスが終了するというニュースが発信され、記事も書き換えないとなあと思っていました。が、それから暫くの間はJavascriptをリアルタイム処理させる必要のないページばかりスクレイピングしていたので、結局放置したままでした(すみません)。

ここ1年の間に、ChromeのVersion59以降より標準で(stable版で)headlessモード(ブラウザ画面が立ち上がらないモード)が使えるようになったらしく、前のようにxvfbのような仮想スクリーンを使う必要もなくなったことに加え、久々にJavascriptが必要なサイトをスクレイピングする必要が出てきたため、この機会に使用法についてまとめておくことにします。

Phantom.jsの作者さんもChromeを使うとよろしーと言っているみたいですね。

環境構築

必要なもの

  • Python + pip(ここでは3.6.5を使いました)
  • Selenium
  • Google Chrome(Version59以上だったらOKです。)
  • ChromeDriver

OSはLinuxでもMacでも大丈夫です。多分Windowsでもいけます。私はArch Linux(GUIなし)を使いました。

インストール

  • Python+pip
    • 適当に入れておいてください
  • Selenium
    • pip install seleniumでインストール出来ます。
  • Google Chrome
    • Package管理ツールでいれてもいいですし、exeやdmg、直接rpmdebからいれてもいいです。
    • CentOSだったら CentOS7にChromeをインストール - Qiita あたりが参考になるかと思います。
    • Arch Linuxの場合は yaourt -S google-chrome-stable で入れれます。(私の場合はライブラリの依存関係が壊れていたので、起動時のエラーを見ながらdowngrade で頑張って3-4個のライブラリをダウングレードして起動まで持っていきました)
  • Chrome Driver
    • Downloads - ChromeDriver - WebDriver for Chrome からダウンロード出来ます。
    • ダウンロードして解凍しましょう。多分中にchromedriverというバイナリがあるはずです。適当なディレクトリに移動してておき、パスを通しておきましょう。
      • echo 'export PATH="$PATH:/path/to/chromedriver_directory"' >> ~/.bashrcとかで行けるんじゃないかなあ(未検証)

使ってみる

# -*- coding: utf-8 -*-
from selenium import webdriver

options = webdriver.chrome.options.Options()
options.add_argument("--headless")  # これ消せばブラウザ画面が出ます

driver = webdriver.Chrome(chrome_options=options)

driver.get("https://sukumizu.moe")

# タイトル
print(driver.title)

# URL
print(driver.current_url)

# cookies
print(driver.get_cookies())

# スクリーンショットの撮影
print(driver.save_screenshot("screenshot.png"))

# ページのソースの取得
print(driver.page_source)

Phantom.jsのときのように一通り欲しい機能は揃っていますね。

また、driver.page_sourceをBeautifulSoupに食わせれば以前のようにそのままBeautifulSoupの機能が使えますし、Seleniumにはそもそも要素の選択機能があるので、それを使ってスクレイピングすることも出来ます。

# id検索
driver.find_element_by_id('id')

# class検索
driver.find_element_by_class_name('classname')

# ネストされた要素の取得
driver.find_elements_by_xpath(".//div")

7. WebDriver API — Selenium Python Bindings 2 documentation

また、クリックや文字入力もできるので、もうなんでもやりたい放題って感じです。

UI操作はちょっと複雑なコードになるのでここでは割愛します。興味がある方は調べてみてください。

VSCode+Python+Jupyter Notebookでの開発環境を整える

機械学習(データ分析)をちょっと触りだけやってみようと思い、最近使い始めたVSCodeで環境構築をしてみました Jupyterを使ったことがなかったのでちょっと苦戦しましたが一応動いたので手順を書き記しておきます。 ついでにAnacondaについてくるJupyterを使う場合の手順も記述しておきます。

はじめに

Jupyter(Project Jupyter | Home)はWeb上で様々な言語を実行することのできるツールです。実行するとWebサーバーのようなものが立ち上がり、ブラウザでコードを書いてポチポチして実行できます。データ分析の世界ではメジャーなツールらしいです。

とはいえブラウザ上でコード書くのも微妙だし、毎回ブラウザに移動するのも面倒なのでエディタ上で完結できないか調べたところ、 拡張機能を使ってVSCode上でも実行結果を表示することができるようなので、今回はその環境を構築しました。

こんな感じ f:id:zipsan:20180321035002p:plain

今回はWindowsでやってみましたがたぶんMacとかLinuxでも同じかなと思います。

前提

上記の環境はすでに整っているものとします。入ってない場合はググって適当にインストールしてください

環境構築

Jupyterのインストール

anacondaの仮想環境(Anacondaのcondaコマンドによる仮想環境の使い方のまとめ - minus9d's diary)を入れている場合は不要です。

VSCode上でTerminalを開きます。標準の場合Ctrl+Shift+Pを押し、「python create terminal」でPythonのターミナルパネルを出します。使用するPythonを選択して以下のコマンドを実行します。 f:id:zipsan:20180321035028p:plain

# pipでインストール(anacondaを入れている場合は不要)
python -m pip install jupyter
or
pip install jupyter

# テスト
> jupyter notebook
[I 03:22:50.412 NotebookApp] Serving notebooks from local directory: C:\Users\@@@@
[I 03:22:50.413 NotebookApp] 0 active kernels
[I 03:22:50.413 NotebookApp] The Jupyter Notebook is running at:
(略)

f:id:zipsan:20180321035031p:plain

ワークスペースディレクトリの作成

どこかよしななところに開発用のディレクトリを作成します。今後の設定はこのディレクトリのみ有効になるので、環境が違っても安心です

Jupyterのタスク(バックグラウンド実行環境)の設定

タスク>タスクの構成

f:id:zipsan:20180321040016p:plain

テンプレートからtasks.jsonを生成 f:id:zipsan:20180321040019p:plain

Others 任意の外部コマンドを実行する例 f:id:zipsan:20180321040021p:plain

と進めます。

以下の内容をtasks.jsonに記述します。 "cwd": "R:\\test"の部分は先程作った開発ディレクトリのパスを指定してください。

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Run Jupyter Notebook",
            "type": "shell",
            "command": "cmd.exe",
            "args": [
                "/C",
                "'jupyter notebook'"
            ],
            "group": "none",
            "options": {
                "cwd": "R:\\test"
            },
            "problemMatcher": []
        }
    ]
}

Mac/Linuxの場合は、commandの部分をbash、argsの部分を

"args": [
    "-c",
    "'jupyter notebook'"
],

になるのかなあと思いますが未検証です(検証後追記します)

参考:VSCodeのタスクでjupyter notebookを起動する - Qiita

また、anacondaの仮想環境で実行したい場合はargsの部分を以下のように記述すればOKです。

"args": [
    "/C",
    "'C:\\Users\\[ユーザー名]\\Anaconda3\\Scripts\\activate [仮想環境名] & jupyter notebook'"
],

Jupyterの実行

記述が終わったらタスクの実行をします。

Ctrl+Shift+Pで「task run」と検索して「タスク:タスクの実行」を選ぶ f:id:zipsan:20180321041710p:plain

「Run Jupyter Notebook」を選ぶ f:id:zipsan:20180321041735p:plain

するとJupyterが起動します。選択部分のURLが必要になるのでコピーします。 f:id:zipsan:20180321041827p:plain

Ctrl+Shift+Pで「jupyter enter」と検索し、「Jupyter: Enter the url~」を選ぶ f:id:zipsan:20180321042037p:plain

先ほどコピーしたURLを貼り付けてEnter f:id:zipsan:20180321042159p:plain

これで環境は整いました。

(Option)キーバインドの設定

実行を楽にしたい場合はキーバインドの設定をします。

Ctrl+Shift+Pで「shortcuts」と検索し「基本設定:キーボードショートカットを開く」を選ぶ f:id:zipsan:20180321042417p:plain

高度なカスタマイズを行うには~の keybindings.json を押す f:id:zipsan:20180321042549p:plain

次のように入力し、保存

[
    {
        "key": "ctrl+e ctrl+j",
        "command": "jupyter.execCurrentCell",
        "when": "editorTextFocus"
    }
]

keyのところはご自由にどうぞ

f:id:zipsan:20180321042420p:plain

実行してみる

ディレクトリの中に pythonファイルをつくって、以下を記述。 matplotlibやnumpyがない場合はエラーになります

#%%
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

x = np.linspace(0, 20, 100)
plt.plot(x, np.sin(x))
plt.show() 


#%%
print("Hello")

うまく言っている場合は #%% の直前に Run cell とでていると思います。

#%% で区切られた部分が1つのセクションとなるので、その中のどこでも良いのでカーソルを移動し、 Ctrl+Shift+Pから「Jupyter run cell」を実行します。(キーバインドの設定をした場合はそれを押せばOK)

カーソルが上のセクションを指定している場合はグラフが表示され f:id:zipsan:20180321043407p:plain

下を指定している場合はHelloが出力されます。 f:id:zipsan:20180321043410p:plain

matploitlibなどがない場合はModuleNotFoundErrorとなりますが、ひとまずこれで実行できるようになりました。

SyslinuxでUSBメモリからWindowsインストールメディアを起動する

大学のメディアを使うときにちょっと詰まったのでメモ
コピペでできるように書いておきます
USBメモリ/インストールメディアに限定した話ではないけど、よく使うのがUSBメモリなのでとりあえずタイトルはこれで。

Arch Linuxで作ります。Ubuntuとか他のLinuxでも同じ感じでできるはず

必要なもの:

環境設定(Arch)

$ sudo pacman -S syslinux
$ sudo pacman -S dosfstools  # mkfs.vfat用
$ sudo pacman -S parted  # fdiskでもOK

USBのフォーマットとパーティショニング

まずUSBメモリを特定する。適当に以下のコマンドを駆使して目星をつける。

$ sudo fdisk -l
$ lsblk
$ dmesg  # USBを挿してすぐに見てみる 

今回は/dev/sdkがUSBでした。

次にフォーマットとパーティショニング。partedを使う。
USBの中身は完全に消去されるので注意

$ sudo parted /dev/sdk
(parted) p
(parted) mklabel msdos
(parted) mkpart primary fat32 0% 100%
(parted) set 1 boot on
(parted) p
(parted) quit

ブートフラグを立てておく。

作成した/dev/sdk1をfat32でフォーマット 

$ sudo mkfs.vfat /dev/sdk1

インストールメディアの書き込み

USBメディアとisoメディアをマウントしてisoのファイルをUSBにコピー。

$ sudo mkdir /mnt/{iso,usb}
$ sudo mount -o loop ~/path_to_iso/Win_Installer.iso /mnt/iso
$ sudo mount -o rw /dev/sdk1 /mnt/usb
$ sudo cp -r /mnt/iso/* /mnt/usb/

おそらく/mnt/usb/boot/ができているはず...

Syslinuxをいれる 

Syslinuxの本体のコピーとインストール

$ sudo mkdir /mnt/usb/boot/syslinux
$ sudo cp -r /usr/lib/syslinux/bios/*.c32 /mnt/usb/boot/syslinux/
$ sudo extlinux --install /mnt/usb/boot/syslinux

これだけでは起動できないのでmbrを書き込む

$ sudo dd if=/usr/lib/syslinux/bios/mbr.bin of=/dev/sdk bs=440 count=1 conv=notrunc

設定ファイル(syslinux.cfg)がないので作成する 

$ cd /mnt/usb/boot/syslinux/
$ sudo vim syslinux.cfg
--------- vim ---------
PROMPT 1
TIMEOUT 30
DEFAULT menu.c32

LABEL BOOTMGR
        MENU LABEL ^Windows-installer
        COM32 /boot/syslinux/chain.c32
        APPEND fs ntldr=/bootmgr
-----------------------

Windowsは/bootmgrを呼び出す必要があるみたいなので、chain.c32のオプションのntdlrで指定する。
bootmgrはWindows Vista以降で使われるブートローダー。
chain.c32はチェインロードを可能にするモジュール。syslinuxからbootmgrへとチェインロードする。
fsはパーティションを検出してくれる(らしい。よくわからないけど、消すとbootmgrを読み込んだあとエラーで落ちた)
ntldrはWindowsブートローダーをロードするchain.c32のオプション。

Comboot/chain.c32 - Syslinux Wiki

あとかたづけ

$ cd
$ sudo umount /mnt/usb
$ sudo umount /mnt/iso

これで終了 qemu-KVMでは無事インストーラーが起動しました。 boot:が表示されて3秒後に起動するけど、起動しない場合はmenuと打ってみるといいかも?

MDwikiをOwncloudと連携させてWebで編集できるようにした

MDwikiというMarkdownで書けるwikiをOwncloudと連携させて、ファイルをWeb上で編集できるようにした。ついでに認証もつけた。

MarkDownで書けてWebで参照できる自分(+少人数グループ)用のメモシステムが欲しいということで、今まではDokuwikiを使用していたのですが、Dokuwikiだと少し不便なところが多く、管理も面倒な感じでした。

そこで、Markdownで書けてデザインも綺麗なMDwikiを使ってみようかなと思ったのですが、MDwikiはファイルベースのwikiで手軽に編集できないと言う欠点がありました(毎回アップロードが必要なのが面倒...)。

DropboxやGoogleDrive上において使用するという方法もありましたが自分のドメインを使いたいので、今回はOwncloud上にMDwikiを置いて、Owncloudのファイル編集機能を使用して編集できるようにしました。

ついでにnginxを使用して簡単な認証(basic)をつけました。

とくに特別な設定はしていないので簡潔に。

概要

今回はMDwiki+Owncloud+Nginx(SSL)を使用しました。Nginxを使用しましたがApacheでも大丈夫と思います。
流れとしては、Nginxの導入→Owncloudの構築→MDwikiの設置と言った感じ。
長くなるので細かなインストールは省きます。

Nginxの導入 & Owncloudの導入

インストールは各OSによって異なるので省略。 普通にインストールすればOK。

Owncloudで認証が必要なので、SSLが必須。オレオレでもいいのでつけておく。

ここで、Owncloudのデータ保存ディレクトリを覚えておく。ここでは/home/owncloud/data/にします。

MDwikiの導入

構築が終わったら、Owncloud上にMDwiki用のディレクトリを作成。 その中にOwncloud上からMDwikiを突っ込む。

Releases · Dynalon/mdwiki · GitHub

mdwiki.html以外を削除して、mdwiki.htmlをindex.htmlにリネーム。

確認用にindex.mdを作成。

Test page
========

hello
------

f:id:zipsan:20151014185600p:plain

ディレクトリにシンボリックリンクを張る

ここで、Owncloud上のMDwikiディレクトリのパスを探す。
おそらくは[Owncloudデータディレクトリ]/[Username]/files/MDwikiあたりにあるかな?

$ cd /home/owncloud/data/  # Owncloudのドキュメントルート
$ cd owncloud_user  # Owncloudで作成したユーザー
$ cd files/mdwiki
$ pwd
/home/owncloud/data/owncloud_user/files/mdwiki

webのドキュメントルートでシンボリックリンクの作成。
owncloud上のデータディレクトリをnginxのドキュメントルートから読み出せるようにする。

cd </path/to/DocumentRoot>
ln -s /home/owncloud/data/owncloud_user/files/mdwiki mdwiki

これでOK

認証

今回はかんたんにbasic認証SSL必須です

htpasswdを作成

$ htpasswd -b -c .htpasswd user passwd

nginxの設定をいじる。

    location ~ /mdwiki/ {
        auth_basic "wiki";
        auth_basic_user_file /etc/nginx/.htpasswd;
        root   /var/www/;
        index  index.html index.htm index.php;
    }

これでhttp://example.jp/mdwiki/に接続すればbasic認証を求められるようになる。

ファイルの編集

owncloud上でファイル名をクリックする。
現在の最新版8.1.3だと標準で編集機能が付いているのでラク。ついてなければプラグインを入れましょう

とりあえずだけどコレでWebから編集できるようになった。

f:id:zipsan:20151014185613p:plain

大事な文書書く場合はセキュリティも意識しないとだめかも。

TrendMicro CTF(TMCTF) 2015 Online Qualifier 解けた問題などWriteup

Trendmicro CTF 2015のOnline Qualifier(TMCTF)をやってみました。
大学の友人がCTFにやる気を出していたので、今回はいつものチームではなく大学の友人3人でチーム"sagume"として出ました。

結果としては700点ほどしかとれませんでしたが、大学の友人に教えたり教えられたりとワイワイやりながらやるCTFは楽しかったです。

以下Writeup

続きを読む