目的
http://example.com
というサイトがあって、レスポンス内容に含まれている
-
img
タグで呼んでいる画像URL -
script
タグで呼んでいるスクリプトのURL -
link
タグで呼んでいるスタイルシートのURL
をピックアップした後に、 同じホスト名から取るもの をリストアップするだけのもの。
コード
import requests
from bs4 import BeautifulSoup
def _fetch_targets(url: str) -> list:
"""指定したURLにアクセスした際に、直後に取る画像,JS,CSSファイルのURLリストを作る
"""
session = requests.Session()
resp = session.get(f"{url}/")
soup = BeautifulSoup(resp.content, 'html.parser')
# Image
img_tags = soup.find_all('img')
img_tags_origin = [
s.attrs['src'] for s in img_tags
if s.attrs['src'].startswith(url)
]
# JS
script_tags = [
s for s in soup.find_all('script')
if 'src' in s.attrs
]
script_tags_origin = [
s.attrs['src'] for s in script_tags
if s.attrs['src'].startswith(url)
]
# CSS
css_tags = [
s for s in soup.find_all('link')
if 'stylesheet' in s.attrs['rel']
]
css_tags_origin = [
s.attrs['href'] for s in css_tags
if s.attrs['href'].startswith(url)
]
# 一括加工
targets = img_tags_origin + script_tags_origin + css_tags_origin
return [t.replace(url, '') for t in targets]
# 使い方
if __name__ == '__main__':
_fetch_targets('http://example.com')
中身概要
基本的にはBeautifulSoup4
の機能に乗っかり、「タグを探索→特定属性によるフィルタ→全部を束ねて整形」というシンプルな構成
* img
タグは、「いくらなんでもsrcはあるだろう」と決めつける
* script
タグは、タグ内に直接書くことも可能なので、「src
属性を持っていること」でフィルタリング
-
link
タグは、いろいろと入り乱れているので、「rel
属性がstylesheet
であること」でフィルタリング
linkタグの属性について
CSSのものだけをlink
タグから抽出するときにrel
属性を使うのだけれど、リストであることを初めて知った気がする。
本当の目的
Locust.io
を使ったサーバーへの負荷テストをしたくて、アクセス先だけでなくそのページが参照しているリソースも含めて処理したほうが負荷テストになるかなと思い実装してみた。
残りのコード
from locust import HttpLocust, Task, TaskSet
# --------
# この辺に、さっきの_fetch_targetsが入る
# --------
def generate_get_task(task: Task, url: str) -> callable:
"""タスクジェネレータです
"""
def _get_task(task: Task):
task.client.get(url)
return _get_task
class TopPageWithResources(TaskSet):
"""テスト振る舞いの定義セット
"""
def __init__(self, parent):
"""アクセス対象のテストをまるごとセットする
"""
super().__init__(parent)
self.tasks = []
self.tasks.append(generate_get_task(self, '/'))
for t in _fetch_targets(self.locust.host):
self.tasks.append(generate_get_task(self, t, counter))
class WebsiteUser(HttpLocust):
"""テスト実行の実設定
"""
task_set = TopPageWithResources
min_wait = 500
max_wait = 900
動的に増やすときの正しい位置を調べるのが面倒がわからなかったので、
タスクを定義する関数を別途用意して、テスト対象 + _fetch_targets
で見つけたURL全てを、tasks
に突っ込んでみた。
こんな感じになる
トップページの構成が変わっても、そのままシナリオとして使えそうで、個人的には便利かなと思っている。