
本教程旨在指导如何使用python监测网站上特定尺寸商品的库存状态,并在库存更新时通过discord发送通知。文章将深入探讨传统网络爬虫(如beautifulsoup)在处理javascript动态加载内容时的局限性,并介绍如何利用selenium等无头浏览器工具来克服这些挑战,实现对动态生成库存信息的准确抓取与实时监控。
在电子商务日益普及的今天,许多用户希望能够实时追踪特定商品的库存状态,尤其是一些热门或限量发售的商品。当商品重新有货时,通过自动化工具及时收到通知,可以大大提高抢购成功的几率。本教程将以监测特定尺寸(例如“40码”)的商品库存为例,并演示如何将库存更新信息发送至Discord频道。
最初的设想是使用requests库获取网页内容,并结合BeautifulSoup进行HTML解析,以查找库存信息。以下是用户尝试的初始代码结构:
import discord
from bs4 import BeautifulSoup
import requests
import aiohttp
import asyncio
webhook_url = 'YOUR_DISCORD_WEBHOOK_URL' # 替换为你的Discord Webhook URL
async def send_webhook_message(content):
"""
通过Discord Webhook发送消息。
"""
async with aiohttp.ClientSession() as session:
async with session.post(webhook_url, json={"content": content}) as response:
if response.status == 204:
print("Discord message sent successfully.")
else:
print(f"Error sending Discord message. Status code: {response.status}")
async def check_stock_initial(url, size):
"""
初步尝试检查库存,但存在局限性。
"""
try:
response = requests.get(url)
response.raise_for_status() # 检查HTTP请求是否成功
soup = BeautifulSoup(response.text, 'html.parser')
# 尝试查找表示库存状态的元素
stock_element = soup.find('li', {'class': 'unselectable'})
# 这里的逻辑是判断如果找到'unselectable'则表示无货,否则可能是有货。
# 但这并不能精确到特定尺寸,且未考虑动态内容。
return stock_element is None
except requests.RequestException as e:
print(f"Error making request to the website: {e}")
return False
# ... (后续的main函数和异步运行逻辑)问题分析:
通过浏览器开发者工具(通常按F12打开),我们可以观察到,当页面加载完成后,表示尺寸选择的元素可能具有如下结构:
立即学习“Python免费学习笔记(深入)”;
<li class="selectable">
<a class="swatchanchor" title="40" href="...">
<!-- 尺寸40的显示内容 -->
</a>
</li>然而,这些带有selectable类和title="40"的元素,在requests获取的原始HTML中是缺失的。
为了解决JavaScript动态加载内容的问题,我们需要使用无头浏览器(Headless Browser)。无头浏览器是一种没有图形用户界面的浏览器,它可以在后台运行,模拟真实用户的行为(如加载页面、执行JavaScript、点击元素等),从而获取到完全渲染后的页面内容。
常用的无头浏览器工具有:
本教程将以Selenium为例,演示如何获取动态加载的库存信息。
pip install selenium
现在,我们将重写check_stock函数,使其使用Selenium来加载和解析页面。
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException, WebDriverException
import time # 用于等待
# 配置ChromeDriver路径 (如果未添加到系统PATH)
# service = Service(executable_path='/path/to/chromedriver') # 替换为你的chromedriver路径
async def check_stock_selenium(url, target_size):
"""
使用Selenium检查特定尺寸的库存。
"""
options = webdriver.ChromeOptions()
options.add_argument('--headless') # 启用无头模式,不显示浏览器界面
options.add_argument('--disable-gpu') # 禁用GPU加速(Linux环境下推荐)
options.add_argument('--no-sandbox') # 禁用沙箱模式(Linux环境下推荐)
options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36')
driver = None
try:
# 初始化WebDriver
# driver = webdriver.Chrome(service=service, options=options) # 如果指定了service
driver = webdriver.Chrome(options=options) # 如果chromedriver在PATH中
driver.get(url)
# 等待页面元素加载完成。这里等待直到表示尺寸选择的某个元素出现。
# 通常,尺寸选择器会有一个共同的父容器或类名。
# 我们可以等待一个通用且稳定的元素,然后查找其内部的特定尺寸。
# 示例:等待一个class为'product-size-selector'的div出现
WebDriverWait(driver, 20).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'ul.product-size-list'))
)
# 查找特定尺寸的元素。
# CSS选择器:查找 class 为 'selectable' 的 li 元素,
# 在其内部查找 class 为 'swatchanchor' 且 title 包含目标尺寸的 a 元素。
# 注意:这里的选择器需要根据实际网站的HTML结构进行调整。
size_element_selector = f"li.selectable a.swatchanchor[title*='{target_size}']"
try:
# 尝试查找目标尺寸的“有货”元素
size_40_available = driver.find_element(By.CSS_SELECTOR, size_element_selector)
# 如果找到,则表示该尺寸有货
print(f"Size {target_size} is in stock!")
return True
except NoSuchElementException:
# 如果没有找到,则表示该尺寸无货
print(f"Size {target_size} is out of stock.")
return False
except TimeoutException:
print(f"Timeout waiting for page elements to load on {url}")
return False
except WebDriverException as e:
print(f"WebDriver error: {e}")
return False
except Exception as e:
print(f"An unexpected error occurred: {e}")
return False
finally:
if driver:
driver.quit() # 确保关闭浏览器实例
现在,我们可以将新的check_stock_selenium函数整合到原有的异步监测循环中。
# ... (send_webhook_message 函数保持不变)
product_data = [
{'url': 'https://www.courir.com/fr/p/ugg-tasman-1499533.html', 'size': '40'}, # 目标尺寸改为'40'
]
async def main():
previous_stock_status = {} # 存储上一次的库存状态
while True:
result_message = ""
for product_info in product_data:
url = product_info['url']
size = product_info['size']
# 使用Selenium检查库存
current_stock_status = await check_stock_selenium(url, size)
# 检查库存状态是否发生变化
if not previous_stock_status.get(url, {}).get(size, False) and current_stock_status:
result_message += f"商品 {url} 的 {size} 码现在有货!\n"
# 更新当前库存状态
previous_stock_status.setdefault(url, {})[size] = current_stock_status
if result_message: # 只有当有更新时才发送Discord消息
print(result_message.strip())
await send_webhook_message(result_message)
print("已发送Discord消息。")
else:
print("无库存更新。")
print("等待10分钟进行下一次检查...")
await asyncio.sleep(600) # 睡眠10分钟 (600秒)
if __name__ == "__main__":
asyncio.run(main())通过本教程,我们了解了在处理JavaScript动态加载内容的网站时,传统网络爬虫(如BeautifulSoup)的局限性。为了准确获取特定尺寸商品的库存信息,我们必须转向使用Selenium等无头浏览器工具来模拟用户行为,执行JavaScript并渲染完整页面。结合异步编程和Discord Webhook,我们可以构建一个高效、实用的库存监测和通知系统。然而,持续维护和应对网站反爬机制是此类自动化工具长期运行的关键。
以上就是监测动态网页库存并发送Discord通知的Python教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号