python (第十一章 动态网页爬取和反爬机制)

第10周学习计划:动态网页爬取和反爬机制

目标:掌握动态网页爬取工具(Selenium)和应对常见反爬措施。

学习内容总览
  1. 动态网页爬取:Selenium 基础。
  2. 反爬机制:识别和应对(如请求头、延迟、代理)。
  3. 实践任务:爬取动态电商页面(如京东商品价格)。

第一部分:动态网页爬取 - Selenium

1. Selenium 简介
  • 功能:模拟浏览器操作,加载 JavaScript 动态内容。
  • 安装
    • pip install selenium
    • 下载浏览器驱动(如 ChromeDriver),与你的 Chrome 版本匹配。
    • 将驱动放入 PATH,或在代码中指定路径。
2. 基本用法
  • 示例
python 复制代码
from selenium import webdriver
from selenium.webdriver.chrome.service import Service

# 指定 ChromeDriver 路径(替换为你的路径)
service = Service(executable_path="path/to/chromedriver")
driver = webdriver.Chrome(service=service)

driver.get("https://www.example.com")
print(driver.title)  # 输出页面标题
driver.quit()  # 关闭浏览器
3. 元素定位
  • find_elementfind_elements 提取网页元素。
  • 常用方法
    • By.ID
    • By.CLASS_NAME
    • By.CSS_SELECTOR
  • 示例
python 复制代码
from selenium.webdriver.common.by import By

driver.get("http://localhost:8000/test_shop.html")
products = driver.find_elements(By.CLASS_NAME, "product")
for product in products:
    name = product.find_element(By.CLASS_NAME, "name").text
    price = product.find_element(By.CLASS_NAME, "price").text
    print(f"{name} - {price}")
driver.quit()

第二部分:反爬机制

1. 常见反爬手段
  • User-Agent 检查:网站检测请求头。
  • IP 限制:频繁请求被封。
  • JavaScript 验证:数据动态加载。
  • 验证码:需要人工干预。
2. 应对方法
  • 伪装请求头

    python 复制代码
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/91.0.4472.124"}
  • 延迟请求

    python 复制代码
    import time
    time.sleep(2)  # 每次请求间隔2秒
  • 代理IP

    • 使用免费代理或代理服务(如 proxyscrape.com)。
    python 复制代码
    proxies = {"http": "http://代理IP:端口", "https": "https://代理IP:端口"}
    response = requests.get(url, proxies=proxies)

实践任务:爬取动态电商页面

目标

用 Selenium 爬取京东(https://www.jd.com/)首页的商品名称和价格(动态加载部分),并保存到文件。

代码实现
python 复制代码
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import json
from datetime import datetime
import time

class JDPriceTracker:
    def __init__(self, filename="jd_prices.json"):
        self.prices = {}
        self.filename = filename
        self.load_prices()
        # 配置 Selenium
        self.service = Service(executable_path="path/to/chromedriver")  # 替换为你的路径
        self.driver = webdriver.Chrome(service=self.service)

    def fetch_prices(self, url):
        """抓取京东首页商品价格"""
        self.driver.get(url)
        time.sleep(3)  # 等待页面加载
        
        try:
            # 定位商品元素(京东的动态商品在 .gl-i-wrap 中)
            products = self.driver.find_elements(By.CLASS_NAME, "gl-i-wrap")
            current_prices = {}
            for product in products[:5]:  # 只抓前5个
                try:
                    name = product.find_element(By.CSS_SELECTOR, ".p-name a").get_attribute("title")
                    price = product.find_element(By.CSS_SELECTOR, ".p-price i").text
                    current_prices[name] = float(price)
                    print(f"抓到:{name} - ¥{price}")
                except Exception as e:
                    print(f"解析单个商品失败:{e}")
            self.update_prices(current_prices)
        except Exception as e:
            print(f"抓取失败:{e}")
        finally:
            self.driver.quit()

    def update_prices(self, current_prices):
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        for name, price in current_prices.items():
            if name not in self.prices:
                self.prices[name] = [{"time": now, "price": price}]
            elif self.prices[name][-1]["price"] != price:
                self.prices[name].append({"time": now, "price": price})
        self.save_prices()

    def view_prices(self):
        if not self.prices:
            print("暂无记录!")
        else:
            print("\n价格记录:")
            for name, history in self.prices.items():
                print(f"{name}:")
                for entry in history:
                    print(f"  {entry['time']} - ¥{entry['price']}")

    def save_prices(self):
        with open(self.filename, "w", encoding="utf-8") as f:
            json.dump(self.prices, f, ensure_ascii=False, indent=2)

    def load_prices(self):
        try:
            with open(self.filename, "r", encoding="utf-8") as f:
                self.prices = json.load(f)
        except FileNotFoundError:
            self.prices = {}

def main():
    tracker = JDPriceTracker()
    url = "https://www.jd.com/"
    
    while True:
        print("\n=== 京东价格监控 ===")
        print("1. 抓取当前价格")
        print("2. 查看记录")
        print("3. 退出")
        
        choice = input("请选择操作(1-3):")
        
        if choice == "1":
            tracker.fetch_prices(url)
        
        elif choice == "2":
            tracker.view_prices()
        
        elif choice == "3":
            print("谢谢使用!")
            break
        
        else:
            print("无效选择,请输入 1-3!")

if __name__ == "__main__":
    main()

代码讲解
  1. Selenium 配置

    • Service 指定 ChromeDriver 路径。
    • time.sleep(3) 等待页面动态内容加载。
  2. 元素定位

    • .gl-i-wrap 是京东商品的容器。
    • .p-name a 获取标题,.p-price i 获取价格。
  3. 异常处理

    • 捕获单个商品解析失败,避免程序崩溃。
    • finally 确保浏览器关闭。

动手实践
  1. 准备环境
    • 安装 seleniumpip install selenium
    • 下载 ChromeDriver,替换代码中的路径。
  2. 运行程序
    • 执行代码,选 1 抓取京东首页。
    • 2 查看记录。
    • 3 退出。
  3. 检查结果
    • 查看 jd_prices.json,确认数据。

预期输出
  • 抓取(示例,实际结果随京东变化):

    抓到:Apple iPhone 14 Pro Max - ¥7999.0
    抓到:华为 Mate 60 Pro - ¥6499.0
    ...

  • 查看记录:

    价格记录:
    Apple iPhone 14 Pro Max:
    2025-02-25 22:00:00 - ¥7999.0
    华为 Mate 60 Pro:
    2025-02-25 22:00:00 - ¥6499.0


小挑战
  1. 多页爬取:滚动页面加载更多商品。
  2. 代理支持:加入代理池应对 IP 限制。
  3. 价格变化提醒:如果价格变化,打印通知。
相关推荐
搞不懂语言的程序员8 分钟前
备忘录模式深度解析与实战案例
数据库·python·备忘录模式
angushine42 分钟前
Gateway获取下游最终响应码
java·开发语言·gateway
爱的叹息1 小时前
关于 JDK 中的 jce.jar 的详解,以及与之功能类似的主流加解密工具的详细对比分析
java·python·jar
Lhuu(重开版1 小时前
2025第十六届蓝桥杯PythonB组部分题解
python
西贝爱学习1 小时前
数据结构:C语言版严蔚敏和解析介绍,附pdf
c语言·开发语言·数据结构
程丞Q香1 小时前
python——学生管理系统
开发语言·python·pycharm
晓纪同学1 小时前
C++ Primer (第五版)-第十三章 拷贝控制
java·开发语言·c++
dragon_perfect2 小时前
ubuntu22.04上设定Service程序自启动,自动运行Conda环境下的Python脚本(亲测)
开发语言·人工智能·python·conda
LL1681992 小时前
SSM考研助手管理系统
java·服务器·开发语言·数据库·学习
明月看潮生2 小时前
青少年编程与数学 02-016 Python数据结构与算法 15课题、字符串匹配
python·算法·青少年编程·编程与数学