質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.37%

指定した条件に合ったPDFのみWEBからダウンロード(Python)

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 791

前提・実現したいこと

特定のWEBページから条件にマッチしたファイルのみ保存したいです。

スクレイピングで下記URL(関西空港HP)から、
http://www.kansai-airports.co.jp/news/2020/

毎月公開される「関西国際空港・大阪国際空港・神戸空港 2020年●月利用状況」のPDFをダウンロード
したいと思いプログラムを作成しましたが、条件設定ができていないため、
現在は上記URLに表示されるPDFすべて(3種)をダウンロードしてしまいます。

「関西国際空港・大阪国際空港・神戸空港 2020年●月利用状況」
(http://www.kansai-airports.co.jp/news/2020/2807/J_TrafficReport_●●●●2020.pdf)
だけをダウンロードするには、URLの文字指定などが必要かと思いますがどのように行うべきでしょうか?

来月以降も"J_TrafficReport_"は含まれることが想定されるため、
例えば、URLに"J_TrafficReport_”が含まれているファイルのみという指定をかけたいと考えています。

一通り調べてみたのですが、解決せず、ご教示いただけますと幸いです。
よろしくお願いいたします。

該当のソースコード

import requests
from bs4 import BeautifulSoup
import urllib.request
from urllib.parse import urljoin
import os
import time

url = "http://www.kansai-airports.co.jp/news/2020/"
base = "http://www.kansai-airports.co.jp/news/2020/"
html = requests.get(url)
soup = BeautifulSoup(html.content, "html.parser")

div = soup.find("div", class_= "contentsType02")
li = div.find_next("li")
tags = li.find_all_next("a")
print(tags)

headers = {"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0"}

for i in range(len(tags)):
    filepath = "{}.pdf".format(i)
    target = tags[i]["href"]
    if os.path.splitext(target)[1] == '.pdf':
        #os.path.splitext関数は、pathをbase(拡張子以外の部分)とext(ピリオドを含む拡張子)に分割
        url_1 = urljoin(base, target)
        request = urllib.request.Request(url=url_1, headers=headers)
        with open(filepath, "wb") as f:
            f.write(urllib.request.urlopen(request).read())
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+1

beautifulsoupでスクレイピングするときに正規表現が使えます
ファイルが少ないので2019にしています

import re
from urllib.parse import urljoin
import pathlib

import requests
from bs4 import BeautifulSoup

url = "http://www.kansai-airports.co.jp/news/2019/"

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko",
}

r = requests.get(url, headers=headers)

r.raise_for_status()

soup = BeautifulSoup(r.content, "html5lib")

for i in soup.find("ul", class_="ul_list04").find_all(
    "a", text=re.compile("^関西国際空港・大阪国際空港・神戸空港.+月利用状況$"), href=re.compile(".pdf$")
):
    link = urljoin(url, i.get("href"))

    pdf = requests.get(link, headers=headers)

    p = pathlib.Path(pathlib.PurePath(link).name)

    with p.open(mode="wb") as f:
        f.write(pdf.content)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • この投稿は削除されました

  • 2020/05/06 15:33

    1点、質問させてください。
    p = pathlib.Path(pathlib.PurePath(link).name)

    はどういう意味を持っていますでしょうか?
    DLしたPDFを指定したフォルダに保存する方法を調べている中で疑問に思いました。

    キャンセル

  • 2020/05/07 10:38

    pathlib
    https://docs.python.org/ja/3/library/pathlib.html

    pathlib.PurePath(link).nameはos.path.basename()と同じでファイル名を取得しています

    キャンセル

checkベストアンサー

0

省略
for i in range(len(tags)):
    filepath = "{}.pdf".format(i)
    target = tags[i]["href"]
    if "J_TrafficReport_" in os.path.splitext(target)[0] and os.path.splitext(target)[1] == '.pdf':
        #os.path.splitext関数は、pathをbase(拡張子以外の部分)とext(ピリオドを含む拡張子)に分割
        url_1 = urljoin(base, target)
        request = urllib.request.Request(url=url_1, headers=headers)
        with open(filepath, "wb") as f:
            f.write(urllib.request.urlopen(request).read())


これでどうでしょうか。
in演算子はその文字列が含まれているかを調べることができます。
こちらのサイトが分かりやすいと思います。

 任意の文字列を含むか判定: in演算子

文字列の中に任意の文字列が含まれているか判定・確認するにはin演算子を使う。含まれているとTrue、含まれていないとFalseを返す。
大文字小文字は区別される(以降で説明する文字列のメソッドでも同様)。

正規表現を使ってもできますが、モジュールをimportしなければいけないことなど、少し面倒なところがあると思ったので、inを使いました。
正規表現の方が良い場合は、コメントいただければ幸いです。

正規表現の方法(追記1)

import os
import re
省略
for i in range(len(tags)):
    filepath = "{}.pdf".format(i)
    target = tags[i]["href"]
    if re.match(r'J_TrafficReport_(.+).pdf',os.path.basename(target)):
        url_1 = urljoin(base, target)
        request = urllib.request.Request(url=url_1, headers=headers)
        with open(filepath, "wb") as f:
            f.write(urllib.request.urlopen(request).read())

参考にさせていただいたサイト

Pythonでパス文字列からファイル名・フォルダ名・拡張子を取得、結合

ファイル名を取得: os.path.basename()
パス文字列からファイル名を取得するにはos.path.basename()を使う。

書きながら覚えよう!Pythonで正規表現を使う方法【初心者向け】
Pythonの正規表現マッチオブジェクトでマッチした文字列や位置を取得

ブール値としての扱い(if文での使い方)
マッチオブジェクトはブール値として判定される場合は常にTrueとして扱われる。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/02 21:31

    この度もご回答いただきありがとうございました。無事に目的のPDFのみ抽出できました。
    もし可能であれば、正規表現パターンもご教示いただきたいです。

    というのも、昨日質問させていただいた観光庁HPのPDFは
    https://www.jnto.go.jp/jpn/statistics/data_info_listing/pdf/200415_monthly.pdf

    と、「20***」「_monthly.pdf」という間がとんだ形で指定をかけたいと考えております。
    (おそらく他のWEBページでも同様の案件が出てきそうなので。。)

    import re を行った上で
    文字を飛ばすところ(上記例でいくと0415)はドットで表現するという
    ところまでは調べたのですが、どうも上手くいかず、、
    ご教示いただけますと幸いです。

    キャンセル

  • 2020/05/03 09:58

    追記しました。

    キャンセル

0

以下のようなコードで、文字列に特定の文字列が含まれているかをチェックできますよ。

if "J_TrafficReport_” in target:

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/02 21:32

    早速のご回答ありがとうございました!1つの問題を解決するにも様々な方法があるんですね!
    勉強させていただきます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る