ดาวน์โหลดรูปภาพและไฟล์อื่นๆ จากเว็บใน Python (เป็นรายบุคคลหรือเป็นกลุ่ม)

ธุรกิจ

ข้อมูลต่อไปนี้จะอธิบายวิธีระบุ URL ของรูปภาพ, ZIP, PDF หรือไฟล์อื่นๆ บนเว็บใน Python ดาวน์โหลดและบันทึกเป็นไฟล์ในเครื่อง

  • ดาวน์โหลดภาพโดยระบุ URL
    • ตัวอย่างโค้ด
    • urllib.request.urlopen():เปิด URL
    • open():เขียนไปยังไฟล์ในโหมดไบนารี
    • ตัวอย่างโค้ดที่ง่ายกว่า
  • ดาวน์โหลดไฟล์ ZIP ไฟล์ PDF ฯลฯ
  • แยก URL ของรูปภาพบนหน้าเว็บ
    • ถ้าตัวเลขเป็นลำดับ
    • สกัดด้วยซุปที่สวยงาม
  • แบทช์ดาวน์โหลดหลายภาพจากรายการ URL

ดาวน์โหลดภาพโดยระบุ URL

คุณสามารถใช้ไลบรารีมาตรฐานเพื่อดาวน์โหลดไฟล์แต่ละไฟล์โดยระบุ URL เท่านั้น ไม่จำเป็นต้องติดตั้งเพิ่มเติม

ตัวอย่างโค้ด

ต่อไปนี้คือตัวอย่างฟังก์ชันที่ดาวน์โหลดและบันทึกไฟล์โดยระบุ URL และเส้นทางปลายทาง และการใช้งาน รหัสนี้ค่อนข้างละเอียดเล็กน้อยเพื่อการอธิบาย ตัวอย่างง่ายๆได้รับด้านล่าง

import os
import pprint
import time
import urllib.error
import urllib.request

def download_file(url, dst_path):
    try:
        with urllib.request.urlopen(url) as web_file:
            data = web_file.read()
            with open(dst_path, mode='wb') as local_file:
                local_file.write(data)
    except urllib.error.URLError as e:
        print(e)
url = 'https://www.python.org/static/img/python-logo.png'
dst_path = 'data/temp/py-logo.png'
download_file(url, dst_path)

ในการระบุไดเร็กทอรีปลายทางและบันทึกไฟล์ด้วยชื่อไฟล์ URL ให้ทำดังต่อไปนี้

def download_file_to_dir(url, dst_dir):
    download_file(url, os.path.join(dst_dir, os.path.basename(url)))

dst_dir = 'data/temp'
download_file_to_dir(url, dst_dir)

มันแยกชื่อไฟล์จาก URL ด้วย os.path.basename() และรวมเข้ากับไดเร็กทอรีที่ระบุด้วย os.path.join() เพื่อสร้างพาธปลายทาง

ส่วนต่อไปนี้อธิบายส่วนของการเก็บข้อมูลและส่วนของการบันทึกข้อมูลเป็นไฟล์

urllib.request.urlopen():เปิด URL

ใช้ urllib.request.urlopen() เพื่อเปิด URL และดึงข้อมูล โปรดทราบว่า urllib.urlopen() เลิกใช้แล้วใน Python 2.6 และรุ่นก่อนหน้า urllib.request.urlretrieve() ยังไม่เลิกใช้ แต่อาจเป็นในอนาคต

เพื่อหลีกเลี่ยงการหยุดเมื่อมีข้อยกเว้น ให้ตรวจจับข้อผิดพลาดด้วยการลองและยกเว้น

ในตัวอย่าง urllib.error ถูกนำเข้าและมีเพียง urllib.error.URLError เท่านั้นที่ถูกจับอย่างชัดเจน ข้อความแสดงข้อผิดพลาดจะปรากฏขึ้นเมื่อไม่มี URL ของไฟล์

url_error = 'https://www.python.org/static/img/python-logo_xxx.png'
download_file_to_dir(url_error, dst_dir)
# HTTP Error 404: Not Found

หากคุณต้องการตรวจจับข้อยกเว้น (FileNotFoundError เป็นต้น) เมื่อบันทึกในเครื่อง ให้ทำดังต่อไปนี้
(urllib.error.URLError, FileNotFoundError)

นอกจากนี้ยังสามารถใช้คำขอห้องสมุดบุคคลที่สามแทน urllib ไลบรารีมาตรฐานเพื่อเปิด url และรับข้อมูล

เขียนไปยังไฟล์ในโหมดไบนารีใน open()

ข้อมูลที่สามารถรับได้ด้วย urllib.request.urlopen() คือสตริงไบต์ (ประเภทไบต์)

Open() พร้อม mode=’wb’ เป็นอาร์กิวเมนต์ที่สองเขียนข้อมูลเป็นไบนารี w หมายถึงเขียนและ b หมายถึงเลขฐานสอง

ตัวอย่างโค้ดที่ง่ายกว่า

สามารถเขียนข้อความที่ซ้อนกันในครั้งเดียว โดยคั่นด้วยเครื่องหมายจุลภาค

เมื่อใช้สิ่งนี้ เราสามารถเขียนสิ่งต่อไปนี้ได้

def download_file(url, dst_path):
    try:
        with urllib.request.urlopen(url) as web_file, open(dst_path, 'wb') as local_file:
            local_file.write(web_file.read())
    except urllib.error.URLError as e:
        print(e)

ดาวน์โหลดไฟล์ ZIP ไฟล์ PDF ฯลฯ

ตัวอย่างจนถึงตอนนี้มีไว้สำหรับการดาวน์โหลดและบันทึกไฟล์รูปภาพ แต่เนื่องจากเราเพียงแค่เปิดไฟล์บนเว็บและบันทึกเป็นไฟล์ในเครื่อง เราจึงสามารถใช้ฟังก์ชันเดียวกันนี้กับไฟล์ประเภทอื่นได้

คุณสามารถดาวน์โหลดและบันทึกไฟล์โดยระบุ URL

url_zip = 'https://from-locas.com/sample_header.csv.zip'
download_file_to_dir(url_zip, dst_dir)

url_xlsx = 'https://from-locas/sample.xlsx'
download_file_to_dir(url_xlsx, dst_dir)

url_pdf = 'https://from-locas/sample1.pdf'
download_file_to_dir(url_pdf, dst_dir)

โปรดทราบว่า URL ที่ระบุในฟังก์ชันนี้ต้องเป็นลิงก์ไปยังไฟล์

ตัวอย่างเช่น ในกรณีของไฟล์ที่เก็บ GitHub URL ต่อไปนี้มีนามสกุล pdf แต่จริงๆ แล้วเป็นหน้า html หาก URL นี้ถูกระบุในฟังก์ชันด้านบน ซอร์ส html จะถูกดาวน์โหลด

  • https://github.com/from-locals/python-snippets/blob/master/notebook/data/src/pdf/sample1.pdf

ลิงก์ไปยังไฟล์เอนทิตีคือ URL ต่อไปนี้ ซึ่งคุณต้องระบุหากต้องการดาวน์โหลดและบันทึกไฟล์

  • https://github.com/from-locals/python-snippets/raw/master/notebook/data/src/pdf/sample1.pdf

นอกจากนี้ยังมีกรณีที่ตัวแทนผู้ใช้ ผู้อ้างอิง ฯลฯ ถูกจำกัดการเข้าถึง ทำให้ดาวน์โหลดไม่ได้ เราไม่รับประกันว่าไฟล์ทั้งหมดจะถูกดาวน์โหลด

ง่ายต่อการใช้คำขอเพื่อเปลี่ยนหรือเพิ่มส่วนหัวของคำขอเช่นตัวแทนผู้ใช้

แยก URL ของรูปภาพบนหน้าเว็บ

หากต้องการดาวน์โหลดรูปภาพทั้งหมดในหน้าเดียว ให้แยก URL ของรูปภาพออกก่อนแล้วสร้างรายการ

ถ้าตัวเลขเป็นลำดับ

หาก URL ของรูปภาพที่คุณต้องการดาวน์โหลดเป็นหมายเลขลำดับอย่างง่าย ก็ทำได้ง่าย หาก URL ไม่ได้เป็นเพียงตัวเลขที่เรียงตามลำดับแต่ยังมีความสม่ำเสมออยู่บ้าง การทำรายการ URL ตามกฎจะง่ายกว่าการขูดด้วย Beautiful Soup (ดูด้านล่าง)

ใช้สัญกรณ์ความเข้าใจรายการ

url_list = ['https://example.com/basedir/base_{:03}.jpg'.format(i) for i in range(5)]
pprint.pprint(url_list)
# ['https://example.com/basedir/base_000.jpg',
#  'https://example.com/basedir/base_001.jpg',
#  'https://example.com/basedir/base_002.jpg',
#  'https://example.com/basedir/base_003.jpg',
#  'https://example.com/basedir/base_004.jpg']

ในตัวอย่างข้างต้น {:03} ใช้สำหรับหมายเลขลำดับที่เติมศูนย์ 3 หลัก {} ถูกใช้เมื่อไม่จำเป็นต้องเติมศูนย์ และ {:05} ใช้สำหรับตัวเลข 5 หลักแทนที่จะเป็น 3 หลัก สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการจัดรูปแบบสตริง str ดูบทความต่อไปนี้

นอกจากนี้ เรายังใช้ pprint เพื่อให้อ่านผลลัพธ์ได้ง่ายขึ้น

สกัดด้วยซุปที่สวยงาม

หากต้องการแยก URL รูปภาพออกจากหน้าเว็บจำนวนมาก ให้ใช้ Beautiful Soup

import os
import time
import urllib.error
import urllib.request

from bs4 import BeautifulSoup

url = 'https://th.from-locals.com/'
ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) '\
     'AppleWebKit/537.36 (KHTML, like Gecko) '\
     'Chrome/55.0.2883.95 Safari/537.36 '

req = urllib.request.Request(url, headers={'User-Agent': ua})
html = urllib.request.urlopen(req)

soup = BeautifulSoup(html, "html.parser")

url_list = [img.get('data-src') for img in soup.find(class_='list').find_all('img')]

ในตัวอย่าง URL ของภาพขนาดย่อของเว็บไซต์นี้จะถูกดึงออกมา

โครงสร้างแตกต่างกันไปขึ้นอยู่กับหน้าเว็บ แต่โดยทั่วไปแล้วจะได้ดังนี้

  • รับรายการ <img> แท็กวัตถุโดยระบุคลาส id ฯลฯ ของบล็อกที่มีรูปภาพหลายรูปที่คุณต้องการดาวน์โหลด
    • soup.find(class_='list').find_all('img')
  • รับ URL ของรูปภาพจากองค์ประกอบ src หรือองค์ประกอบ data-src ของ <img> แท็ก
    • img.get('data-src')

โค้ดตัวอย่างด้านบนเป็นเพียงตัวอย่างและไม่รับประกันว่าจะใช้งานได้

แบทช์ดาวน์โหลดหลายภาพจากรายการ URL

หากคุณมีรายการ URL คุณสามารถเปลี่ยนเป็น for loop และเรียกใช้ฟังก์ชันเพื่อดาวน์โหลดและบันทึกไฟล์โดยแสดง URL แรก เนื่องจากรายการ URL ชั่วคราว การเรียกฟังก์ชัน download_image_dir() จึงถูกแสดงความเห็นไว้ที่นี่

download_dir = 'data/temp'
sleep_time_sec = 1

for url in url_list:
    print(url)
#     download_file_dir(url, download_dir)
    time.sleep(sleep_time_sec)
# https://example.com/basedir/base_000.jpg
# https://example.com/basedir/base_001.jpg
# https://example.com/basedir/base_002.jpg
# https://example.com/basedir/base_003.jpg
# https://example.com/basedir/base_004.jpg

เพื่อไม่ให้โอเวอร์โหลดเซิร์ฟเวอร์ ฉันใช้ time.sleep() เพื่อสร้างเวลารอสำหรับการดาวน์โหลดแต่ละภาพ หน่วยเป็นวินาที ดังนั้นในตัวอย่างข้างต้น โมดูลเวลาจะถูกนำเข้าและใช้งาน

ตัวอย่างคือไฟล์รูปภาพ แต่ไฟล์ประเภทอื่นสามารถดาวน์โหลดพร้อมกันได้เช่นกัน ตราบใดที่อยู่ในรายการ