scrapy で localhost サーバーのリソースをスクレイピングして parse 結果を json ファイルに出力する

他人のサーバーでテストすることは憚られる

環境

  • Mac OSX - 10.13.4
  • Python - 3.6.5
  • nginx - 1.12.2
  • scrapy - 1.5.0

localhost サーバー

workspace ディレクトリ直下の index.html を改変しておく。

/path/to/nginx/workspace/index.html

<html>
  <head>
    <style type="text/css">
      #caption {
        color: red;
      }   
      .elem {
        color: blue;
      }   
    </style>
  </head>
  <body>
    <h1 id="caption">hello world</h1>
    <div>
      <ul>
        <li class="elem">abc</li>
        <li class="electric">def</li>
        <li class="elem"><a href="#">link to myself</a></li>
      </ul>
    </div>
  </body>
</html>
$ nginx

クローラー

仮想環境で scrapy を導入

$ mkdir testdir && cd testdir
$ python3 -m venv ./venv/environment
$ source ./source/venv/environment/bin/activate
$ pip3 install scrapy
$ touch main.py

main.py

クローラー本体

import scrapy

class Spider(scrapy.Spider):
  start_urls = ['http://localhost:8080/index.html']
  name = 'spider'

  def parse(self, response):
    for text in response.xpath('//h1/text()').extract():
      yield { 'h1-text' : text }

    for dom in response.css('li.electric').extract():
      yield { 'dom li-electric' : dom }

    for text in response.xpath('//li/a/text()').extract():
      yield { 'text of a in li' : text }

クロール

$ scrapy runspider main.py -o outfile.json

クロール結果

outfile.json

[
{"h1-text": "hello world"},
{"dom li-electric": "<li class=\"electric\">def</li>"},
{"text of a in li": "link to myself"}
]

参考文献

python 仮想環境 とは

「管理者、システム権限から隔離された Python を実行できる環境」を仮想環境と呼ぶ。

実体的にはディレクトリであり venv ( あるいは env ) と表記される。

その配下には Python バイナリ, pip, 3rd パーティパッケージ などが集約されている。

(厳密な定義は リンク先をご覧ください)

簡易例

numpy を実行できる仮想環境を作る、使う、依存パッケージを抽出する(導入する)

環境

  • MacOSX - 10.13.4
  • Python - 3.6.5
    • brew で導入しておくことが望ましい

適当な空ディレクトリを作って移動しておく

$ mkdir mytest && cd mytest

仮想環境を作る

$ python3 -m venv ./venv/environment
$ source venv/environment/bin/activate
(environment)
$ which python3
/Users/matsukawa/Develop/python/mytest/venv/environment/bin/python3

3 つ目のコマンドから、仮想環境で Python を実行していることがわかる。

仮想環境に numpy を導入する

(environment)
$ pip3 install numpy

mytest ディレクトリ直下に main.py を作成する

./mytest/main.py

import numpy as np

print(np.array([1, 2, 3]))

仮想環境を使う

(environment)
$ python3 main.py

> 出力
[1, 2, 3]

仮想環境で依存したパッケージを抽出する

他環境へパッケージ導入を知らせる手段としてこれを使う

(environment)
$ pip3 freeze > requirements.txt

./mytest/requirements.txt

numpy==1.14.3

導入する時

(environment)
$ pip3 install -r requirements.txt

仮想環境から抜け出す

(environment)
$ deactivate
$

シェル冒頭の (environment) が消えていること

補足

venv は各々の環境に配置されるべきなので、ソースコード管理対象からは除外する。

参考文献

setup.py の最小構成

  • python setup.py sdist した時に warning なく dist が出力されること
  • hello world スクリプトすらない

最小というより 骨組み の方が適切かもしれない

試行目的

setup.py の使い方に慣れること

動作確認バージョン

ディレクトリ構成

./
├── .gitignore
├── LICENSE.rst
├── MANIFEST.in
├── README.rst
├── lib
│   └── __init__.py
└── setup.py

.gitignore

長いので リンク先を参照

LICENSE.rst

LICENSE
====================

MIT

MANIFEST.in

include *.rst

README.rst

setup_py
====================

Minimal setup.py to develop

lib/__init__.py

name = 'lib'

setup.py

from distutils.core import setup
from setuptools import find_packages

setup(
  name         = 'minimal_setup',
  version      = '1.0',
  description  = 'minimal setup',
  author       = 'ymatsukawa',
  author_email = 'ymatsukawa27@example.com',
  url          = 'https://github.com/ymatsukawa/',
  license      = 'MIT',
  packages     = find_packages(where = '.'),
)

確認内容

  • python setup.py sdist するとコマンド実行ディレクトリで dist/minimal_setup-1.0.tar.gz が作成される

読んだリソース

仕様と設計の違い

f:id:mat5ukawa:20160817231309p:plain

将来どこかで誰かに

「仕様と設計を混同した時はこれ見といてね」と

言えることを念頭において書いた記事

「仕様」 と 「設計」 は別物

私なりの言葉で定義すると

仕様

= 作るものについて、満たされているべきことが定義されたもの

満たされているべきこととは「顧客が期待している結果」と「期待していない結果」のことだ

あなたが SE ならばこの定義について顧客と合意形成を取るべきだ

設計

= 仕様をどう実現するかが具体的に明確化されたもの

設計を基に SE と PG で意思疎通を図る

具体的な手段(モノ)として設計書がある


具体例を挙げるのでおおよその感覚を掴んでいただければ幸い

(突っ込み所は色々あると思うがスルーでお願いしたい)


例 - 顧客からのブログ Web アプリ作成依頼

あなたは SE だ(時には PG だったりする)

ある顧客から実現したいことについて依頼を貰った

依頼内容

弊社内で完結させる、ブログ Web アプリが欲しい
直近で (1) を実現してほしい

(1) タイトル・内容
    を投稿できる画面を作る

補足しておくと
  今考えている画面総数は 3 つ
    記事を投稿できる画面
    記事の一覧を表示する画面
    記事の内容を確認する画面
(資料を添付するので見ておいてください)

添付資料

f:id:mat5ukawa:20160817231232p:plain

顧客の依頼内容は「作るものがどうあるべきか」を示した「仕様」だ、「設計」ではない

「設計」はまだだ

あなたは「ご依頼を一度預かります」と伝え、依頼内容を確認する

「この依頼内容でシステムへ落とし込めるが、幾つか顧客が期待する結果を聞かないといけない」

と考えた

そう、入力制限がないことに違和感を覚え始めているはず

依頼内容を精査し、顧客に次の質問を持ちかけた

  • タイトルの文字数はいくつまで可能? (これは仕様だ)
  • タイトルは未入力を許してよい? (これも仕様だ)
  • 内容の文字数はいくつまで可能? (仕様だ)
  • 内容は未入力を許してよい? (これも)

その結果こうなった

(1) タイトル・内容
    を投稿できる画面を作る
(1) - 1
    タイトルは 255 文字まで
(1) - 2
    内容は 1,000 文字まで
(1) - 3
    タイトルのみ
    未入力、空白記号のみの入力で投稿はできないようにする

繰り返しになるが、これは「仕様」であり、実施していたのを仕様を決める行為だ

「設計」は一つもやっていない = 仕様をどう実現するかの具体化は、まだ何もやっていない

仕様を決めていた

f:id:mat5ukawa:20160817231450p:plain

ここからようやく「設計」だ

仕様で決まったことをどう実現するかを具体的に明確化しよう、ここから設計だ

あなたが 開発の設計者なら次の設計をするだろう

  • ユースケースを書いてユーザー視点の実行パターンを明確化する
  • ER 図を書いてテーブル連携の明確化する
  • (もう少しコード側に突っ込んで)
    文字数バリデーションを実行する手段を明確化する
    • FW が持っているバリデーションメソッドを使うか
    • form から POST された値をビジネスロジック内で
      length や size などミドルウェアのメソッドで文字数チェックし
      文字数を超えていれば 例外出力する処理とするか
  • 他、色々
  • (設計書には仕様の説明は書かない。仕様は自明である前提だ)

テストの設計者なら別のことをするかもしれない

仕様を決めた後に設計をする

f:id:mat5ukawa:20160817231527p:plain


蛇足

1

「ここからようやく「設計」だ」に関する項目が曖昧だが...

この辺り勉強中なので、色々わかり次第またの機会に

2

仕様を相談するくだりは

説明用ということでその内容を簡素(削った、という方が正確)にしたが

あなたなら顧客へ他に何を質問・相談するだろうか、考えてみてほしい

動機付けになった Web リソース

参考にした Web リソース