【Mac】Dockerfile を作成、イメージを作成しコンテナで Python 実行

Docker Hub で公開されているイメージを元に、自作の Python プログラムを含めて Docker イメージを作成する工程をメモしておきます。

作成したイメージからコンテナを作成、コンテナ内で Python プログラムを実行するところまでカバーしています。

前提:Mac で Docker Desktop をインストール済み

  1. Python 関連の準備
    1. Python プログラムの準備
    2. requirements.txt の作成
  2. Docker 関連の準備
    1. Dockerfile の作成
    2. .dockerignore の作成
    3. docker build でイメージを作成
  3. コンテナの作成と Python プログラムの実行
    1. docker run でイメージを実行
    2. コンテナに入ってみる
    3. Python プログラムを実行してみる
  4. コンテナ脱出、コンテナ停止、コンテナ削除

1. Python 関連の準備

1. Python プログラムの準備

まずは下準備として Python 仮想環境をローカル環境に作り、コンテナ内で実行したい Python プログラムを用意します。

とりあえず手持ちのプログラム「amazon_scraping.py」を使いまわします。仮想環境と横並びで配置しています。

% ls
amazon_scraping.py        venv

Amazon の商品リストページの情報をスクレイピングして CSV ファイルにアウトプットするプログラムです。

# amazon_scraping.py

from datetime import date
from time import sleep
import csv
import requests
from bs4 import BeautifulSoup


domain_name = 'amazon.co.jp'
search_term = 'iPhone 12'

url = f'https://www.{domain_name}/s?k={search_term}'.replace(' ','+')
urls = []
for i in range(1,2):
    urls.append(f'{url}&page={i}')

headers = {
    'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15',
    'Host':f'www.{domain_name}'
}

# Request each URL, convert into bs4.BeautifulSoup
soups = []
for url in urls:
    response = requests.get(url,headers=headers)
    soup = BeautifulSoup(response.content, 'html.parser')
    soups.append(soup)
    sleep(0.5)

# Convert delivery date
def format_delivery_date(date_string):
    if len(date_string) == 0:
        return None
    
    if date_string[-2:] == '曜日':
        date_string = date_string[:-3]

    if date_string[0:3] == '明日中' and date_string[-4:] == '1月/1':
        date_string = date_string.replace('明日中','2024/')
        
    elif date_string[0:3] == '明日中':
        date_string = date_string.replace('明日中','2023/')
    
    date_string = date_string.replace('月/','/')
        
    return date_string

# Extract data from bs4.BeautifulSoup
def scan_page(soup, page_num):
    products = []

    for product in soup.select('.s-result-item'):
        asin = product['data-asin']

        a_spacing_top_small = product.select_one('.a-spacing-top-small')
        a_section_list = product.select('.sg-row .a-section')

        for a_section in a_section_list:
            price_elem = a_section.select_one('.a-price .a-offscreen')        
            if price_elem:
                price = int(price_elem.get_text().replace('¥', '').replace(',',''))
                continue

            delivery_date_by = a_section.select_one('span:-soup-contains("までにお届け")')
            if delivery_date_by:
                delivery_date = format_delivery_date(a_section.select('span')[1].text)
                continue

        if asin:
            products.append({'asin': asin, 'price': price, 'delivery_date': delivery_date, 'page_number': page_num})

    return products

for page_num, soup in enumerate(soups):
    dict_list = scan_page(soup, page_num+1)
    fieldnames = dict_list[0].keys()
    
    with open('output.csv', 'w', newline='') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(dict_list)
    
print('csv file created')

標準ではないモジュールとして、requests と beautifulsoup4 を pip でインストールします。

(venv) % pip install requests
(venv) % pip install beautifulsoup4

2. requirements.txt の作成

次に requirements.txt を作ります。

% pip freeze > requirements.txt
(venv) % ls
amazon_scraping.py      requirements.txt        venv

中身は下記の様になっています。

# requirements.txt
beautifulsoup4==4.12.2
certifi==2023.5.7
charset-normalizer==3.1.0
idna==3.4
requests==2.30.0
soupsieve==2.4.1
urllib3==2.0.2

3. .dockerignore の作成

「venv」配下は必要ないため、イメージに含めない様「.dockerignore」に追加します。

# .dockerignore
venv

とりあえず Python プログラムの下準備はここまでです。

2. Docker 関連の準備

1. Dockerfile を作る

仮想環境のディレクトリと横並びで Dockerfile というファイルを作成します。

ubuntu:20.04 のイメージを元に、Python および使用するモジュールをインストールする様記述します。

# Dockerfile
FROM ubuntu:20.04

#apt の最新化の後 python と pip をインストール
RUN apt update 
RUN apt install -y python3.9 
RUN apt install -y python3-pip

# 作業ディレクトリを /var に移動
WORKDIR /var

# ローカル環境の amazon_scraping.py をコンテナへコピー
COPY amazon_scraping.py .

# ローカル環境の requirements.txt をコンテナへコピーし、中身を pip install
COPY requirements.txt .
RUN python3.9 -m pip install -r requirements.txt

中身は上記の通りで、ubuntu:20.04 のイメージを元に、ファイルのコピーやインストールをおこないます。

「ls」を実行すると下記の状態です。

(venv) % ls
Dockerfile              amazon_scraping.py      requirements.txt        venv

2. docker build でイメージを作成

「docker build」コマンドを実行します。

% docker build -t docker_amzn:1.0 .
[+] Building 239.4s (13/13) FINISHED                                                                                                              
 => [internal] load build definition from Dockerfile                                                                                         0.0s
 => => transferring dockerfile: 253B                                                                                                         0.0s
 => [internal] load .dockerignore                                                                                                            0.0s
 => => transferring context: 2B                                                                                                              0.0s
 => [internal] load metadata for docker.io/library/ubuntu:20.04                                                                              0.9s
 => [1/8] FROM docker.io/library/ubuntu:20.04@sha256:db8bf6f4fb351aa7a26e27ba2686cf35a6a409f65603e59d4c203e58387dc6b3                        4.2s
 => => resolve docker.io/library/ubuntu:20.04@sha256:db8bf6f4fb351aa7a26e27ba2686cf35a6a409f65603e59d4c203e58387dc6b3                        0.0s
 => => sha256:db8bf6f4fb351aa7a26e27ba2686cf35a6a409f65603e59d4c203e58387dc6b3 1.13kB / 1.13kB                                               0.0s
 => => sha256:b795f8e0caaaacad9859a9a38fe1c78154f8301fdaf0872eaf1520d66d9c0b98 424B / 424B                                                   0.0s
 => => sha256:88bd6891718934e63638d9ca0ecee018e69b638270fe04990a310e5c78ab4a92 2.30kB / 2.30kB                                               0.0s
 => => sha256:ca1778b6935686ad781c27472c4668fc61ec3aeb85494f72deb1921892b9d39e 27.50MB / 27.50MB                                             2.9s
 => => extracting sha256:ca1778b6935686ad781c27472c4668fc61ec3aeb85494f72deb1921892b9d39e                                                    0.9s
 => [internal] load build context                                                                                                            0.0s
 => => transferring context: 2.67kB                                                                                                          0.0s
 => [2/8] RUN apt update                                                                                                                    62.4s
 => [3/8] RUN apt install -y python3.9                                                                                                      35.9s
 => [4/8] RUN apt install -y python3-pip                                                                                                   130.6s
 => [5/8] COPY requirements.txt .                                                                                                            0.0s
 => [6/8] RUN python3.9 -m pip install -r requirements.txt                                                                                   2.7s
 => [7/8] WORKDIR /var                                                                                                                       0.0s
 => [8/8] COPY /venv/amazon_scraping.py .                                                                                                    0.0s
 => exporting to image                                                                                                                       2.6s
 => => exporting layers                                                                                                                      2.6s
 => => writing image sha256:9f3dfca1f57b234294ed4666ea9d6dc05f7200cf30c6c10bbebf83834ae6e457                                                 0.0s
 => => naming to docker.io/library/docker_amzn:1.0                                                                                           0.0s
% 

数分かかりましたが無事完了。「docker images」コマンドで作成済みのイメージを確認できます。

% docker images
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
docker_amzn   1.0       9f3dfca1f57b   59 seconds ago   473MB

3. コンテナに入ってみる

1. docker run でイメージを実行

「docker run」コマンドで Docker イメージからコンテナを作成します。

コンテナ外からのアクセスはしないのでポートフォワーディング(-p オプション)は指定していません。

% docker run --name amzn_scraper -it -d docker_amzn:1.0
47caefa69121c3323c7379f448952003001817e937ffb3232d4564fce9b3c01c

2. コンテナに入ってみる

% docker exec -it amzn_scraper bash
root@47caefa69121:/var# 

「ls」を実行すると、Dockerfile で COPY の記述をした amazon_scraping.py や requirements.txt がコンテナに存在することを確認できます。

root@cd3f7f913010:/var# ls
amazon_scraping.py  backups  cache  lib  local  lock  log  mail  opt  requirements.txt  run  spool  tmp

3. Python プログラムを実行してみる

そのままコンテナ内で Python プログラムを実行してみます。

root@cd3f7f913010:/var# python3.9 amazon_scraping.py
csv file created

ファイルが作成された様です。

root@cd3f7f913010:/var# ls
amazon_scraping.py  backups  cache  lib  local  lock  log  mail  opt  output.csv  requirements.txt  run  spool  tmp

「head」コマンドで中身も確認。きちんと作成されている様です。

root@cd3f7f913010:/var# head output.csv
asin,price,delivery_date,page_number
B0BDHLR5WP,164800,,1
B0BDHYRRQX,134800,,1
B09M69W9KR,234801,,1
B09M68Y2HZ,162800,,1
B0928MGLCR,50025,,1
B0928LZ4HD,67980,2023/5/19,1
B08B9WMNSS,49490,,1
B0928L4D5H,92430,,1
B08B9GTC1T,78695,,1

8. コンテナ脱出、コンテナ停止、コンテナ削除

コンテナ脱出

# exit
exit

コンテナ停止

% docker stop amzn_scraper
amzn_scraper
% docker ps -a            
CONTAINER ID   IMAGE             COMMAND       CREATED          STATUS                     PORTS     NAMES
47caefa69121   docker_amzn:1.0   "/bin/bash"   13 minutes ago   Exited (0) 2 seconds ago             amzn_scraper

コンテナ削除

% docker rm amzn_scraper
amzn_scraper
% docker ps -a          
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です