🗂

Python, Docker, Scrapyを使ってURLからWebページをHTML形式でダウンロードする

2023/07/08に公開

本記事でやりたいこと

Python, Docker, Scrapyを使ってURLからWebページをHTML形式でダウンロードする
今回は私が以前作成した記事である下記のURLをHTML形式でダウンロードしたいと思います。
https://zenn.dev/elletech/articles/nextjs_microcms

本記事のリポジトリ

https://github.com/sugayutokyo/docker-scrapy-spider
うまく行かない処理などありましたら、こちらをご覧ください!

Python, Dockerの設定

Docker Desktopをインストールする

下記リンクからDocker Desktopをダウンロードして、インストールして起動してください
https://www.docker.com/products/docker-desktop

Python環境を作成

  1. Dockerfileを作成します
$ touch Dockerfile
FROM python:3.8.12-bullseye

WORKDIR /usr/src/app

RUN apt-get update && apt-get install -y unzip

ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/chrome

COPY requirements.txt ./
RUN pip install --upgrade pip && pip install --no-cache-dir -r ./requirements.txt
  1. requirements.txtを作成し、必要なライブラリを記述します
$ touch requirements.txt
requirements.txt
scrapy==2.9.0
  1. docker-compose.ymlを作成します
$ touch docker-compose.yml
docker-compose.yml
version: '3.9'

services:
  scrapy:
    build: 
      context: .
      dockerfile: Dockerfile
    image: scrapy:2.6.1
    container_name: my_scrapy
    volumes:
      - $PWD/app:/usr/src/app
    tty: true
  1. コンテナを起動する
$ docker-compose up -d --build
Creating network "docker-scrapy-spider_default" with the default driver
Building scrapy
[+] Building 32.9s (8/9)                                                                                                                    
 => [internal] load build definition from Dockerfile                                                                                   0.0s
 => => transferring dockerfile: 369B                                                                                                   0.0s
 => [internal] load .dockerignore                                                                                                      0.0s
 => => transferring context: 2B                                                                                                        0.0s
 => [internal] load metadata for docker.io/library/python:3.8.12-bullseye                                                              3.6s
 => [1/5] FROM docker.io/library/python:3.8.12-bullseye@sha256:53cb5152064a7e7b485ad42704ea63c5155b264c82e7f17de99d3aa28e4f8956        0.0s
 => [internal] load build context                                                                                                      0.0s
 => => transferring context: 93B                                                                                                       0.0s
 => CACHED [2/5] WORKDIR /usr/src/app                                                                                                  0.0s
 => CACHED [3/5] RUN apt-get update && apt-get install -y unzip                                                                        0.0s
 => [4/5] COPY requirements.txt ./                                                                                                     0.0s
 => [5/5] RUN pip install --upgrade pip && pip install --no-cache-dir -r ./requirements.txt                                       [+] Building 119.1s (10/10) FINISHED                             
 => [internal] load build definition from Dockerfile        0.0s 
 => => transferring dockerfile: 369B                        0.0s 
 => [internal] load .dockerignore                           0.0s
 => => transferring context: 2B                             0.0s 
 => [internal] load metadata for docker.io/library/python:  3.6s 
 => [1/5] FROM docker.io/library/python:3.8.12-bullseye@sh  0.0s
 => [internal] load build context                           0.0s 
 => => transferring context: 93B                            0.0s 
 => CACHED [2/5] WORKDIR /usr/src/app                       0.0s
 => CACHED [3/5] RUN apt-get update && apt-get install -y   0.0s 
 => [4/5] COPY requirements.txt ./                          0.0s 
 => [5/5] RUN pip install --upgrade pip && pip install -  115.0s
 => exporting to image                                      0.4s 
 => => exporting layers                                     0.4s 
 => => writing image sha256:081870f12dabf66be0d5d6f1cf72df  0.0s 
 => => naming to docker.io/library/scrapy:2.6.1             0.0s 
                                                                 
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
Creating my_scrapy ... done
  1. Docker Desktopを開いて以下の画像のようにコンテナが立ち上がっていればOK

Scrapyを使ってHTMLを実際にダウンロードする

  1. Dockerコンテナに入ります
    下記コマンドを打ったら root@~:/usr/src/app# とターミナルが表示されればOKです
$ docker-compose exec scrapy bash

下記のコードで /usr/src/app# で始まっている部分はコンテナ内で実行するということです!

  1. Scrapyのプロジェクトを作成
    今回はscrapingというプロジェクト名で作成します
/usr/src/app# scrapy startproject scraping .
New Scrapy project 'scraping', using template directory '/usr/local/lib/python3.8/site-packages/scrapy/templates/project', created in:
    /usr/src/app

You can start your first spider with:
    cd .
    scrapy genspider example example.com
  1. spiderをgetHtmlという名前で作成する
/usr/src/app# scrapy genspider getHtml zenn.dev
  1. 生成されたgetHtml.pyを開いて以下のように修正する
app/scraping/spiders/getHtml.py
import scrapy
import os

class GethtmlSpider(scrapy.Spider):
    name = "getHtml"
    allowed_domains = ["zenn.dev"]
    start_urls = ["https://zenn.dev/elletech/articles/nextjs_microcms"]
    
    def parse(self, response):
        output_path = '/usr/src/app/downloads/'
        os.makedirs(os.path.dirname(output_path), exist_ok=True)
        with open(output_path + 'index.html', 'w', encoding='utf-8') as f:
            f.write(response.text)

コードの解説

  • allowed_domains
    このSpiderがクロールすることが許可されているドメインを指定します。これにより、Spiderはzenn.devからのリクエストに制限されます。

  • start_urls
    Spiderがクロールを開始するURLを指定します。配列で複数指定することで連続で複数のURLに対してクロールを実行することができるようになります。

  • output_path
    ダウンロードしたHTMLを保存するディレクトリのパスを設定します。

  • os.makedirs(os.path.dirname(output_path), exist_ok=True)
    出力パスのディレクトリを作成します。exist_ok=Trueはディレクトリが既に存在する場合でもエラーを発生させないようにするオプションです。

  • with open(output_path + 'index.html', 'w', encoding='utf-8') as f:
    新しいファイル(ここではindex.html)を作成し、そのファイルを書き込む準備をします。

  • f.write(response.text)
    ダウンロードしたウェブページのHTMLをファイルに書き込みます。

  1. crawlを実行する
$ scrapy crawl getHtml
~省略
2023-07-08 06:06:21 [scrapy.core.engine] INFO: Spider closed (finished)
  1. 実行がうまくいくと下記の画像のようにapp/downloadsディレクトリの中にindex.htmlが作成されているはずです

  2. 生成されたhtmlをchromeなどのブラウザで開いてみましょう!
    以下のように表示されていれば成功です!お疲れ様でした!

参考

https://hossuii.com/?p=1282#a1
https://qiita.com/takecore@github/items/35905779504016085801

GitHubで編集を提案

Discussion