星标下公众号,
获取更多优质教程
用 Python 和 Selenium 打造自动化图片下载器——轻松收割 flickr 全网美图!
在这篇文章中,我们将探索如何利用 Python 的 Selenium 库,构建一个自动化的图片下载器。如果你曾经在 Flickr 上苦苦寻找高质量图片,却因为数量太多而手动下载感到头疼,那么这篇文章就是为你准备的。我们将用幽默的笔触带你领略全栈开发的乐趣,并教你如何使用 Selenium 自动化操作浏览器,轻松实现大批量图片下载。
如果你的目标网站不是 flickr,你也可以通过学习本文了解爬虫实现方法和思路,在其他图片网站一样可以使用。
为什么选择 Selenium?
初始化 Selenium——准备工作
页面分析--页面图片链接手到拿來
主页面变化
页面图片链接获取
下载图片——让链接变成你硬盘上的收藏
全自动批量处理——因为我们懒得一个个点
结语:Python 自动化的乐趣
插播:推荐一款免费的AI软件,我们自己开发的 想读APP,让阅读、学习文章更简单,点击查看想读安装使用说明,注册登录后私聊我微信领取SVIP权限。
为什么选择 Selenium?
Selenium 是一款强大的工具,它允许我们通过 Python 脚本自动化操作浏览器。这不仅省去了重复点击的烦恼,还能确保下载到的图片质量和速度都达到最佳水平。当然,前提是你得有一颗耐心调试的心,因为自动化的世界有时也需要些手工修修补补。
初始化 Selenium——准备工作
我们首先需要配置好 Selenium 的运行环境,确保它能无缝连接到我们本地的 Chrome 浏览器。
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
import json
import os
import urllib
import ssl
import urllib.request
# 创建一个未验证的上下文,避免SSL证书的问题
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
这段代码设置了一个未验证的 SSL 上下文,确保在请求图片链接时不会被各种证书问题困扰。
接下来,我们需要加载 Chrome 浏览器的驱动:
# 加载谷歌浏览器驱动
driver_path = r'你自己的chromedriver路径'
ser = Service(driver_path)
chrome_options = webdriver.ChromeOptions()
driver = webdriver.Chrome(service=ser, options=chrome_options)
driver.maximize_window() # 设置页面最大化,避免元素被隐藏
在这里,我们使用了webdriver.Chrome()
来启动浏览器。为了确保一切正常运行,请替换driver_path
为你自己本地的 ChromeDriver 路径。如果你想让程序在后台默默运行,可以加上chrome_options.add_argument('headless')
。
页面分析--页面图片链接手到拿來
接下来,我们进入核心部分——自动化抓取图片链接。
主页面变化
首先分析下页面url变化,我大概发现每一种类型的多页页面,切换链接格式都是:
主url+page{i}
i 表示页面号
比如 https://flickr.com/photos/coloraestheticist/
这个作者所有图片页面的第二页url就是:
https://flickr.com/photos/coloraestheticist/page2
页面图片链接获取
这一步中,我们把每页中的图片url提取出来,存到一个txt。
首先F12打开控制台,选择任意一张图片,发现图片的详情页面链接是在class=overlay
的a标签中。
另外当页面图片很多的时候,需要先下滑到底部才能加载所有照片。
根据分析,先写一个函数,用于完全打开页面,也就是把当前页面内容加载完全,代码如下。
def get_link(url, i):
url = f"{url}/page{i}"
print(f"开始第{i}页")
driver.get(url) # 打开目标页面
while True:
# 滑动到最底部,加载出所有图片
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(3)
# 检测是不是到最底部了
if driver.execute_script("return window.innerHeight + window.pageYOffset >= document.body.offsetHeight;"):
break
这个函数通过滚动页面到底部来加载所有的图片链接。我们设置了一个循环,直到页面不再加载新内容为止。虽然这看起来简单,但实际上能有效解决很多网页内容动态加载的问题。
然后写一段代码调用 get_link 先加载所有图片,然后获取页面a标签中的链接,并存储到txt文件。
# 要获取的页面链接
url = "https://flickr.com/photos/coloraestheticist"
# 页面总数
n = 2
for i in range(1, n+1):
get_link(i)
links = [i.get_attribute("href") for i in driver.find_elements(By.CLASS_NAME, 'overlay')]
print(f"第{i}页,图片:{len(links)}张")
with open(f"downloaded_images/links/{i}.txt", "w") as file:
for link in links:
file.write(link + "\n")
下载图片——让链接变成你硬盘上的收藏
获得链接后,我们自然要下载这些图片啦!
首先访问图片主页:
link = "https://flickr.com/photos/coloraestheticist/53898259811/"
driver.get(link)
页面分析发现,图片链接可以这样获取:点击页面下载按钮-->然后点击原本大小
即可,链接在这个 原本大小 a 标签的 href 中。
再进一步分析可以看出分析出如下规律:元素id开头一样,结尾固定。
按钮 | 元素id开头 | 元素href结尾 |
---|---|---|
下载 | yui_3_16_0 | sizes/l/ |
原本大小 | yui_3_16_0 | o_d.jpg |
直接上代码,实现上述逻辑自动化:
def get_element(endswith, click=False):
'''
点击下载/获取图片链接
'''
# 获取所有符合条件的元素
elements = driver.find_elements(By.XPATH, '//a[starts-with(@id, "yui_3_16_0")]')
# 遍历元素并打印它们的 href 属性值
for element in elements:
href = element.get_attribute('href')
if href.endswith(endswith):
if click:
element.click()
else:
return href
本以为这样就很好了,结果实际代码操作发现这个下载按钮和原本大小的a标签都是动态加载的,只有操作点击的时候才会渲染出来。。。
换换其他思路。
发现以下规律,直接访问:
图片链接+sizes/o/ 即可获得原图详情页面
如图片链接:https://flickr.com/photos/coloraestheticist/53930900080/
原图详情页面是:https://www.flickr.com/photos/coloraestheticist/53930900080/sizes/o/
然后再获取页面 img 标签下的 src 属性值即可。
上代码:
def download_imgs(links, save_directory):
global driver
for link in links:
max_retries = 3
for retry in range(max_retries):
try:
driver.get(link+"sizes/o/")
time.sleep(1)
image_url = driver.find_element(By.XPATH, '//*[@id="allsizes-photo"]/img').get_attribute("src")
if image_url:
break
except Exception as e:
print(f"获取失败:{e}")
if not image_url:
print(f"【图片获取失败】{link}")
return
image_filename = image_url.split("/")[-1]
print(f"正在下载:{image_filename}")
save_path = os.path.join(save_directory, image_filename)
for retry in range(max_retries):
try:
response = urllib.request.urlopen(image_url, context=context, timeout=3)
if response.status == 200:
break
except Exception as e:
print(f"请求失败:{e}")
image_data = response.read()
with open(save_path, "wb") as file:
file.write(image_data)
time.sleep(1)
我们定义了download_imgs
函数,它接收图片链接列表和保存路径。这个函数采用了重试机制,以防由于网络问题而下载失败。通过这段代码,你可以确保下载到的每一张图片都能妥善保存到指定文件夹中。
全自动批量处理——因为我们懒得一个个点
当然,手动调用这些函数还是太麻烦。既然是全自动化,那我们就该批量处理!
读取之前保存的链接文件,然后调用 download_imgs
函数来批量下载图片。
def batch_download_images_from_files(links_directory, output_directory):
# 确保输出目录存在
os.makedirs(output_directory, exist_ok=True)
# 遍历所有的链接文件
for file_name in os.listdir(links_directory):
file_path = os.path.join(links_directory, file_name)
# 读取链接文件中的所有图片链接
with open(file_path, 'r') as file:
links = file.readlines()
# 从链接中去掉换行符
links = [link.strip() for link in links]
# 为每个链接调用 download_imgs 函数下载图片
print(f"开始下载 {file_name} 中的图片...")
download_imgs(links, output_directory)
print(f"{file_name} 中的图片下载完成!")
# 定义链接文件所在目录和图片保存目录
links_directory = "downloaded_images/links"
output_directory = "downloaded_images/imgs"
# 执行批量下载
batch_download_images_from_files(links_directory, output_directory)
batch_download_images_from_files
函数:
该函数接受两个参数: links_directory
(存放链接文件的目录) 和output_directory
(存放下载图片的目录)。它遍历 links_directory
中的每一个文件,读取文件中的图片链接。然后调用 download_imgs
函数将图片下载到指定目录output_directory
。
主程序:
links_directory
和output_directory
分别是存放链接文件和下载图片的目录。调用 batch_download_images_from_files
函数来批量处理所有链接文件中的图片下载。
这样,你可以轻松地批量处理之前保存的所有图片链接,而无需手动逐个处理文件。希望这对你有帮助!
插播:推荐一款免费的AI软件,我们自己开发的 想读APP,让阅读、学习文章更简单,点击查看想读安装使用说明,注册登录后私聊我微信领取SVIP权限。
结语:Python 自动化的乐趣
这篇文章,我们利用 Python 和 Selenium一步步实现自动化图片下载。从浏览器操作分析到图片存储,每个环节都经过精心设计和调试。如果你也希望能批量获取图片或其他网页数据,不妨尝试自己动手搭建一个类似的工具吧!
总之,编程不仅仅是写代码,更是享受解决问题的过程。希望这篇文章能为你带来一点灵感与欢乐!Happy coding! 🧑💻
随手点个赞吧,如果方便还可以转发分享给更多朋友,这是对我最大的鼓励与支持。
文章中已经列举、分享了所有代码,如果你想要一个可以运行的源码文件,可以加我微信获取,我都整理好了。