
本文旨在指导读者如何使用Python构建一个商品库存监控机器人,并实时通过Discord发送通知。文章将深入探讨在面对JavaScript动态加载内容的网站时,传统网页抓取工具(如BeautifulSoup)的局限性,并详细介绍如何利用无头浏览器(如Selenium)来模拟用户行为、获取动态数据,最终实现高效、准确的库存监控与通知机制。
构建一个自动化的库存监控系统,其核心目标是定期检查特定商品(例如,特定尺码的鞋子)的库存状态,并在库存发生变化(例如,从缺货变为有货)时,通过即时通讯工具(如Discord)发送通知。
最初,开发者可能会尝试使用requests库获取网页内容,并结合BeautifulSoup进行解析。这种方法对于内容直接包含在HTML源代码中的静态网页非常有效。例如,对于一个表示商品库存状态的<li>元素,如果其类名从unselectable(缺货)变为selectable(有货),那么通过查找这些类名可以判断库存。
import requests
from bs4 import BeautifulSoup
def check_static_stock(url, target_size_title):
try:
response = requests.get(url)
response.raise_for_status() # 检查HTTP请求是否成功
soup = BeautifulSoup(response.text, 'html.parser')
# 尝试查找表示有货的元素,例如:
# 假设有货时,尺码选项的父元素是'selectable',且尺码选项本身有'swatchanchor'类和包含尺码的title
# 如果网页是静态的,这可能是一个有效的查找方式
available_size_elements = soup.find('li', class_='selectable')
if available_size_elements:
# 进一步查找包含特定尺码的链接
size_40_available = available_size_elements.find_all('a', class_='swatchanchor', title=lambda t: t and target_size_title in t)
return len(size_40_available) > 0
return False
except requests.RequestException as e:
print(f"请求网页时发生错误: {e}")
return False
# 示例:如果网页是静态的,可以这样调用
# url = 'https://www.courir.com/fr/p/ugg-tasman-1499533.html'
# is_in_stock = check_static_stock(url, '40')
# if is_in_stock:
# print("尺码 40 有货!")
# else:
# print("尺码 40 缺货或未找到。")然而,许多现代网站,包括示例中的电商网站,广泛使用JavaScript来动态加载和渲染页面内容。这意味着当您使用requests.get(url)获取页面时,返回的HTML源代码可能不包含所有最终在浏览器中可见的元素。尺码选项、库存状态等关键信息可能是在页面加载完成后,由JavaScript通过AJAX请求获取数据并插入到DOM中的。
立即学习“Python免费学习笔记(深入)”;
在这种情况下,BeautifulSoup只能解析原始的HTML文本,无法执行JavaScript,因此它无法“看到”这些动态生成的内容。这就是传统网页抓取方法面临的主要挑战。
为了克服动态内容的挑战,我们需要一个能够模拟真实浏览器行为的工具,即无头浏览器。无头浏览器可以在后台运行,执行JavaScript、加载CSS、处理AJAX请求,并最终呈现出完整的DOM结构,就像一个普通浏览器一样。
Selenium是一个流行的自动化测试工具,它也可以作为强大的无头浏览器抓取工具。
pip install selenium
以下是使用Selenium检查特定尺码库存的示例代码:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
def check_dynamic_stock_selenium(url, target_size):
chrome_options = Options()
chrome_options.add_argument("--headless") # 启用无头模式,不显示浏览器界面
chrome_options.add_argument("--disable-gpu") # 禁用GPU硬件加速
chrome_options.add_argument("--no-sandbox") # 禁用沙箱模式,某些Linux环境需要
chrome_options.add_argument("--disable-dev-shm-usage") # 解决在某些Docker容器中内存不足的问题
# 根据您的ChromeDriver路径进行修改
# 例如:service = Service('/path/to/chromedriver')
driver = webdriver.Chrome(options=chrome_options)
try:
driver.get(url)
# 等待页面加载完成,或者等待特定元素出现
# 这里我们等待一个包含尺码选项的父容器出现
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'div.product-attributes__size-selector'))
)
# 查找所有尺码选项,这些选项通常是带有特定类名和title属性的<a>标签
# 假设尺码选项的HTML结构为 <a class="swatchanchor" title="40">...</a>
# 并且有货时,其父级<li>可能没有'unselectable'类,或者其自身没有'disabled'属性
# 查找所有尺码的链接
size_elements = driver.find_elements(By.CSS_SELECTOR, 'a.swatchanchor')
for element in size_elements:
if element.get_attribute('title') == target_size:
# 找到目标尺码
# 检查其父级<li>元素的类名,或者元素本身的属性来判断是否可选/有货
# 在Courir网站的例子中,如果一个尺码不可选(缺货),它的父级<li>会有'unselectable'类
parent_li = element.find_element(By.XPATH, '..') # 获取父元素
if 'unselectable' not in parent_li.get_attribute('class'):
print(f"尺码 {target_size} 有货!")
return True
else:
print(f"尺码 {target_size} 缺货。")
return False
print(f"未找到尺码 {target_size} 的选项。")
return False
except Exception as e:
print(f"使用Selenium检查库存时发生错误: {e}")
return False
finally:
driver.quit() # 确保关闭浏览器实例
# 示例调用
# url = 'https://www.courir.com/fr/p/ugg-tasman-1499533.html'
# is_size_40_in_stock = check_dynamic_stock_selenium(url, '40')
# print(f"尺码 40 库存状态: {is_size_40_in_stock}")代码解释:
一旦我们能够准确地获取库存状态,就可以将其与Discord Webhook集成,发送实时通知。这部分可以使用aiohttp异步发送请求,以避免阻塞主程序。
import discord
import aiohttp
import asyncio
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
# 替换为您的Discord Webhook URL
WEBHOOK_URL = 'YOUR_DISCORD_WEBHOOK_URL_HERE'
async def send_webhook_message(content):
"""
异步发送Discord Webhook消息
"""
async with aiohttp.ClientSession() as session:
try:
async with session.post(WEBHOOK_URL, json={"content": content}) as response:
if response.status == 204:
print("Discord消息发送成功。")
else:
print(f"发送Discord消息失败。状态码: {response.status}, 响应: {await response.text()}")
except aiohttp.ClientError as e:
print(f"发送Discord消息时发生网络错误: {e}")
async def check_stock_and_notify(url, target_size, previous_stock_status):
"""
检查指定尺码的库存,并在状态变化时发送Discord通知。
"""
current_stock_status = check_dynamic_stock_selenium(url, target_size)
# 检查库存状态是否从缺货变为有货
if not previous_stock_status.get(url, {}).get(target_size, False) and current_stock_status:
message = f"? 尺码 {target_size} 的商品已到货!请尽快查看: {url}"
print(message)
await send_webhook_message(message)
elif previous_stock_status.get(url, {}).get(target_size, True) and not current_stock_status:
# 如果之前有货,现在缺货,也可以选择发送通知
message = f"⚠️ 尺码 {target_size} 的商品已缺货: {url}"
print(message)
# await send_webhook_message(message) # 根据需求决定是否通知缺货
# 更新本次库存状态
previous_stock_status.setdefault(url, {})[target_size] = current_stock_status
return previous_stock_status
async def main():
product_to_monitor = [
{'url': 'https://www.courir.com/fr/p/ugg-tasman-1499533.html', 'size': '40'},
# 可以添加更多商品和尺码
# {'url': '另一商品URL', 'size': '另一尺码'},
]
previous_stock_status = {} # 存储上次检查的库存状态
while True:
print("\n开始检查库存...")
for product_info in product_to_monitor:
url = product_info['url']
size = product_info['size']
previous_stock_status = await check_stock_and_notify(url, size, previous_stock_status)
print("所有商品检查完毕。下次检查将在10分钟后。")
await asyncio.sleep(600) # 每10分钟检查一次
if __name__ == "__main__":
# 请确保将 WEBHOOK_URL 替换为您的实际 Discord Webhook URL
# 确保ChromeDriver路径正确配置,或者在check_dynamic_stock_selenium函数中指定
asyncio.run(main())
通过本文的讲解,我们了解了在面对动态加载内容的现代网站时,传统网页抓取方法的局限性,并掌握了如何利用Selenium无头浏览器来模拟真实用户行为,成功获取并解析这些动态数据。结合Discord Webhook,我们能够构建一个高效、可靠的自动化库存监控与通知系统。在实际应用中,请务必注意遵守网站规定,并采取适当的策略来确保程序的稳定性和可持续性。
以上就是使用Python监控动态网页库存并发送Discord通知:从静态抓取到无头浏览器的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号