
本文旨在指导读者如何使用Python构建一个商品库存监控机器人,并实时通过Discord发送通知。文章将深入探讨在面对JavaScript动态加载内容的网站时,传统网页抓取工具(如BeautifulSoup)的局限性,并详细介绍如何利用无头浏览器(如Selenium)来模拟用户行为、获取动态数据,最终实现高效、准确的库存监控与通知机制。
1. 理解库存监控的需求与挑战
构建一个自动化的库存监控系统,其核心目标是定期检查特定商品(例如,特定尺码的鞋子)的库存状态,并在库存发生变化(例如,从缺货变为有货)时,通过即时通讯工具(如Discord)发送通知。
最初,开发者可能会尝试使用requests库获取网页内容,并结合BeautifulSoup进行解析。这种方法对于内容直接包含在HTML源代码中的静态网页非常有效。例如,对于一个表示商品库存状态的
元素,如果其类名从unselectable(缺货)变为selectable(有货),那么通过查找这些类名可以判断库存。
import requestsfrom bs4 import BeautifulSoupdef 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,因此它无法“看到”这些动态生成的内容。这就是传统网页抓取方法面临的主要挑战。
2. 解决方案:利用无头浏览器进行动态网页抓取
为了克服动态内容的挑战,我们需要一个能够模拟真实浏览器行为的工具,即无头浏览器。无头浏览器可以在后台运行,执行JavaScript、加载CSS、处理AJAX请求,并最终呈现出完整的DOM结构,就像一个普通浏览器一样。
Selenium是一个流行的自动化测试工具,它也可以作为强大的无头浏览器抓取工具。
2.1 Selenium环境搭建
安装Selenium库:
pip install selenium
下载浏览器驱动: Selenium需要一个浏览器驱动来控制实际的浏览器。常用的有ChromeDriver(Google Chrome)、GeckoDriver(Mozilla Firefox)。请根据您系统上安装的浏览器版本下载对应的驱动,并将其放置在系统的PATH环境变量中,或者在代码中指定其路径。ChromeDriver下载地址:https://www.php.cn/link/73715c097259c228af0648823d754407GeckoDriver下载地址:https://www.php.cn/link/9a1ecce2d381e29ac81279bdae9886bd
2.2 使用Selenium获取动态内容
以下是使用Selenium检查特定尺码库存的示例代码:
from selenium import webdriverfrom selenium.webdriver.chrome.service import Servicefrom selenium.webdriver.common.by import Byfrom selenium.webdriver.chrome.options import Optionsfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECimport timedef 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属性的标签 # 假设尺码选项的HTML结构为 ... # 并且有货时,其父级代码解释:
chrome_options.add_argument(“–headless”):启用无头模式,浏览器将在后台运行,不显示图形界面。这对于服务器环境和提高性能非常有用。WebDriverWait 和 expected_conditions:这是Selenium中处理动态加载内容的关键。它允许代码等待某个条件(例如,某个元素出现)满足后才继续执行,避免因元素尚未加载而导致的查找失败。driver.find_elements(By.CSS_SELECTOR, ‘a.swatchanchor’):使用CSS选择器查找所有匹配的尺码元素。element.get_attribute(‘title’):获取元素的title属性,用于匹配目标尺码。element.find_element(By.XPATH, ‘..’):通过XPath获取当前元素的父元素,以便检查其类名来判断库存状态。
3. 集成Discord通知机制
一旦我们能够准确地获取库存状态,就可以将其与Discord Webhook集成,发送实时通知。这部分可以使用aiohttp异步发送请求,以避免阻塞主程序。
import discordimport aiohttpimport asynciofrom selenium import webdriverfrom selenium.webdriver.chrome.service import Servicefrom selenium.webdriver.common.by import Byfrom selenium.webdriver.chrome.options import Optionsfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECimport time# 替换为您的Discord Webhook URLWEBHOOK_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_statusasync 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())
4. 注意事项与最佳实践
网站使用条款和robots.txt: 在进行网页抓取之前,务必查阅目标网站的robots.txt文件(例如 https://www.courir.com/robots.txt)以及其服务条款。遵守网站的规定,避免对网站造成不必要的负担。请求频率与IP封锁: 频繁的请求可能会被网站识别为恶意行为,导致IP地址被封锁。请合理设置检查间隔(例如,10分钟或更长),并考虑使用代理IP池来分散请求。元素定位的稳定性: 网站的HTML结构可能会发生变化,导致您在Selenium中使用的CSS选择器或XPath失效。当脚本不再工作时,需要重新检查页面结构并更新定位器。使用更通用或更稳定的定位方式(如id属性,如果存在)可以提高稳定性。错误处理: 在实际应用中,网络问题、元素未找到等异常情况时有发生。务必在代码中加入健壮的try-except块来处理这些异常,确保程序的稳定运行。资源管理: 每次使用Selenium后,务必调用driver.quit()来关闭浏览器实例及其驱动进程,释放系统资源,防止内存泄漏。异步编程: 对于需要同时监控多个商品或需要长时间运行的机器人,使用asyncio进行异步编程可以提高效率和响应性。日志记录: 记录程序的运行状态、错误信息和库存变化,有助于问题排查和历史数据分析。
总结
通过本文的讲解,我们了解了在面对动态加载内容的现代网站时,传统网页抓取方法的局限性,并掌握了如何利用Selenium无头浏览器来模拟真实用户行为,成功获取并解析这些动态数据。结合Discord Webhook,我们能够构建一个高效、可靠的自动化库存监控与通知系统。在实际应用中,请务必注意遵守网站规定,并采取适当的策略来确保程序的稳定性和可持续性。
以上就是使用Python监控动态网页库存并发送Discord通知:从静态抓取到无头浏览器的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1382600.html
微信扫一扫
支付宝扫一扫