跳转至

🐍 Python 爬虫全栈开发:从入门到反爬攻防

这是一份涵盖 Python 爬虫各个阶段的详细学习笔记,从基础的 HTTP 请求到高级的 Selenium 自动化与反爬策略。


📅 Day 01:爬虫初探与基础流程

1. 课程体系概览 🗺️

  • 基础阶段: 语法环境、数据类型、流程控制、函数模块。
  • 进阶阶段: 面向对象、网络编程、Mysql 数据库、并发编程。
  • 前端补充: HTML/CSS/JS、jQuery、Bootstrap、Ajax。
  • 爬虫阶段核心:
  • 数据容器: 字符串、列表、字典。
  • 流程控制: 筛选与提取。
  • 工具封装: 函数与类(面向对象)。
  • 网络协议: HTTP/HTTPS (GET/POST)。

2. 什么是爬虫? 🕷️

爬虫是模拟用户向服务器发送请求,并在互联网上获取数据的一种方式。

  • 核心动作: 模拟(非真人)、请求(下载、保存、注册、查询)。
  • 数据分类:
  • 娱乐/商业数据: 图片、小说、视频、商品信息。
  • 搜索引擎: 百度、谷歌的抓取系统。
  • 人机交互: 抢票、秒杀、自动投票。

3. 爬虫分类

  • 通用爬虫: 搜索引擎的核心,抓取全网数据。
  • 聚焦爬虫: 针对特定网站或内容进行筛选抓取。
  • 增量爬虫: 监测更新,只抓取新产生的数据(如股票、天气)。

4. 爬虫流程操作 (Requests) 🛠️

Requests 是 Python 的第三方库,用于发送网络请求。

基本步骤:

  1. 准备工具: import requests
  2. 确定目标: url = '网址'
  3. 发送请求: res = requests.get(url)
  4. 处理数据:

Python

import requests

url = 'http://www.example.com'
res = requests.get(url)

# 常用属性
print(res.status_code) # 状态码
print(res.text)        # 文本数据 (HTML/JSON)
print(res.content)     # 字节数据 (图片/音频/视频)
print(res.encoding)    # 字符编码

# 编码修正示例
# res.encoding = 'utf-8' 

5. 多媒体数据抓取 🎵

  • 图片/音频/视频: 必须使用 .content 获取二进制数据。
  • 保存文件: 使用 wb 模式。

Python

# 保存图片示例
img_data = res.content
with open('image.jpg', 'wb') as f:
    f.write(img_data)

📅 Day 02:Requests 进阶与正则表达式

1. HTTP 与 HTTPS 🌐

  • HTTP (80端口): 超文本传输协议,明文传输。
  • HTTPS (443端口): HTTP + SSL 证书加密,更安全。
  • HTTP 状态码:
  • 200: 成功。
  • 3xx: 重定向。
  • 4xx: 客户端错误 (404 丢失, 403 拒绝)。
  • 5xx: 服务器错误。

2. 伪装请求 (Headers) 🎭

服务器会校验请求头中的 User-Agent,如果识别为 Python 脚本可能会拒绝访问。

Python

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...'
}
res = requests.get(url, headers=headers)

3. GET vs POST 请求

  • GET: 获取数据(查询),参数在 URL 中显示。
  • POST: 发送数据(登录、上传),参数在请求体中。

Python

# 带参数的搜索请求 (GET)
params = {'wd': 'Python爬虫'}
res = requests.get('https://www.baidu.com/s', params=params)

# 带数据的提交请求 (POST)
data = {'username': 'admin', 'password': '123'}
res = requests.post(url, data=data)

4. 正则表达式 (Re模块) 🔍

正则用于在字符串中筛选符合规则的数据。

常用元字符表:

元字符 说明 示例
\d 匹配数字 \d+ 匹配 123
. 匹配除换行外任意字符 .* 匹配一行
* 匹配前一个字符 0 次或多次
? 匹配前一个字符 0 次或 1 次
+ 匹配前一个字符 1 次或多次
[] 范围匹配 [0-9]
() 提取分组

导出到 Google 表格

代码案例:

Python

import re

text = '我叫麒麟,手机号是19120412166,座机是6013-8214006'

# 1. 匹配手机号 (1开头,11位数字)
print(re.findall(r'1\d{10}', text))

# 2. 贪婪与非贪婪 (重要)
html = '<p>多喝热水</p><p>好好学习</p>'
# (.*?) 是非贪婪匹配,只匹配标签内的内容
print(re.findall(r'<p>(.*?)</p>', html)) 

📅 Day 03:抓包分析与实战案例

1. 浏览器抓包 (F12) 🕵️‍♂️

  • Elements: 查看网页源代码结构。
  • Console: 调试 JS,打印日志。
  • Network (核心): 查看所有网络请求。
  • Fetch/XHR: 异步加载的数据 (Ajax)。
  • Doc: HTML 文档。
  • Img/Media: 媒体文件。

2. 豆瓣电影实战 (面向对象版) 🎬

结合了 Requests、Re 和 PyMySQL 的完整案例。

Python

import requests
import re
import pymysql

class DoubanSpider:
    def __init__(self):
        self.url = 'https://movie.douban.com/top250?start={}'
        self.headers = {'User-Agent': 'Mozilla/5.0...'}
        # 数据库连接
        self.db = pymysql.connect(host='localhost', user='root', password='...', database='chairman')
        self.cursor = self.db.cursor()

    def get_data(self, url):
        res = requests.get(url, headers=self.headers)
        return res.text

    def parse_data(self, html):
        # 使用正则提取:标题、导演、主演
        # re.S 让 . 能匹配换行符
        pattern = r'<span class="title">(.*?)</span>.*?<p class="">(.*?)</p>'
        data = re.findall(pattern, html, re.S)
        self.save_data(data)

    def save_data(self, datas):
        for item in datas:
            title = item[0]
            content = item[1]
            # 进一步清洗数据...
            print(f"保存电影:{title}")
            # sql = "INSERT INTO..."
            # self.cursor.execute(sql)

    def run(self):
        for i in range(0, 250, 25):
            self.get_data(self.url.format(i))

if __name__ == '__main__':
    spider = DoubanSpider()
    spider.run()

📅 Day 04:XPath 数据提取

1. XML vs HTML

  • HTML: 展示数据(给用户看)。
  • XML: 存储和传输数据(给机器看),语法与 HTML 类似但标签自定义。

2. XPath 语法与 lxml 模块 🏹

XPath 是在 XML/HTML 中查找信息的语言。

常用语法:

  • // : 全文查找后代。
  • / : 查找直接子节点。
  • . : 当前节点。
  • .. : 父节点。
  • @ : 选取属性 (如 @href)。
  • text() : 选取文本内容。

代码操作:

Python

from lxml import etree

# 1. 解析 HTML 字符串
html = etree.HTML(text)
# 2. 解析 HTML 文件
# html = etree.parse('index.html')

# 3. 提取数据
# 获取所有 li 标签下的 href 属性
link_list = html.xpath('//li/a/@href')

# 获取特定 class 的 div 下的文本
content = html.xpath('//div[@class="box"]/text()')

📅 Day 05:BeautifulSoup4 (BS4)

1. BS4 特点 🥣

  • 优点: 语法简单,基于 Python 对象操作,适合初学者。
  • 缺点: 效率比 XPath 稍慢。
  • 依赖: 需要安装 lxml 解析器。

2. 核心语法

  • 对象创建: soup = BeautifulSoup(html_str, 'lxml')
  • Tag 对象: soup.div (获取第一个 div)。
  • 搜索文档树:
  • find('标签名', attrs={...}): 找一个。
  • find_all('标签名'): 找所有,返回列表。
  • CSS 选择器 (select):
  • soup.select('.classname')
  • soup.select('#idname')
  • soup.select('div > p')

📅 Day 06:数据保存与并发编程基础

1. Excel 操作 (openpyxl) 📊

Python

import openpyxl

# 创建工作簿
wb = openpyxl.Workbook()
sheet = wb.active
sheet.title = "爬虫数据"

# 添加一行数据
sheet.append(['标题', '链接', '价格'])

# 保存
wb.save('data.xlsx')

# 读取
wb2 = openpyxl.load_workbook('data.xlsx')
print(wb2.active['A1'].value)

2. 进程与线程 🚀

  • 进程 (Process): 资源分配的最小单位(工厂车间)。适合多页面爬取,资源消耗大,独立稳定。
  • 线程 (Thread): CPU 调度的最小单位(车间流水线)。适合单页面多任务,资源消耗小,共享内存。

自定义进程类示例:

Python

from multiprocessing import Process

class MyProcess(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print(f"{self.name} 开始工作...")

if __name__ == '__main__':
    p = MyProcess('爬虫1号')
    p.start()

📅 Day 07:GUI 编程与加密逻辑

1. Tkinter 界面编程 🖥️

Python 自带的 GUI 库。

Python

import tkinter

root = tkinter.Tk()
root.geometry('500x400')
tkinter.Label(root, text="Hello Spider").pack()
root.mainloop()

2. 业务逻辑:加盐 (Salt) 🧂

  • 原理: 为了防止密码被“彩虹表”或“字典”暴力破解,在原始密码后加入一段随机字符串(盐)再进行加密(如 MD5)。
  • 爬虫启示: 在逆向登录时,需要找到前端 JS 中的加盐逻辑才能生成正确的加密参数。

📅 Day 08:多任务爬虫与进程通信

1. 消息队列 (Queue)

用于进程间的数据通信,保证数据安全有序。

Python

from multiprocessing import Queue
q = Queue()
q.put("任务1")
data = q.get()

2. 进程池/线程池 (Pool) 🏊‍♂️

自动管理一定数量的进程/线程,复用资源,避免频繁创建销毁。

Python

from concurrent.futures import ProcessPoolExecutor

def task(url):
    print(f"下载: {url}")

if __name__ == '__main__':
    with ProcessPoolExecutor(max_workers=4) as pool:
        urls = ['url1', 'url2', 'url3']
        pool.map(task, urls)

📅 Day 09:Selenium 自动化

1. 核心概念 🤖

Selenium 是自动化测试工具,通过 WebDriver 驱动真实浏览器(Chrome/Edge),所见即所得。

  • 适用场景: JS 动态渲染页面、复杂的登录验证、滑动验证码。
  • 缺点: 速度慢,资源消耗大。

2. 环境配置

  1. pip install selenium
  2. 下载对应浏览器的 chromedriver 或使用 webdriver-manager 自动管理。

3. 常用操作代码

Python

from selenium import webdriver
from selenium.webdriver.common.by import By

# 1. 启动浏览器
driver = webdriver.Chrome()

# 2. 访问页面
driver.get('http://www.baidu.com')

# 3. 定位元素 (新版写法)
el = driver.find_element(By.ID, 'kw')

# 4. 交互操作
el.send_keys('Python') # 输入
driver.find_element(By.ID, 'su').click() # 点击

# 5. 无头模式 (不显示界面)
options = webdriver.ChromeOptions()
options.add_argument('--headless')

# 6. JS 执行 (滚动页面/懒加载)
driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')

driver.quit()

4. 显式等待 vs 隐式等待 ⏳

  • 隐式等待: driver.implicitly_wait(10) (全局设置,死等)。

  • 显式等待: 等待特定元素出现才继续,更智能。

Python

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, 'content'))
)

🛡️ 综合篇:反爬与反反爬策略

反爬手段 现象 解决方案
UA 认证 请求报错或无数据 构建 headers,使用 fake_useragent
IP 限制 访问频率过高被封禁 使用代理 IP 池,降低 time.sleep 频率
Cookie 需要登录才能看 模拟登录获取 Cookie,或手动复制 Cookie
Referer 盗链检查 在 headers 中带上来源页面的 URL
动态加载 源码中无数据 分析 Ajax 请求 (XHR) 或使用 Selenium
验证码 图形/滑块/点选 使用打码平台 API 或 OpenCV 识别
JS 逆向 参数被加密 (Sign/Token) 扣 JS 代码,使用 Python 模拟加密逻辑