🐍 Python 爬虫全栈开发:从入门到反爬攻防
这是一份涵盖 Python 爬虫各个阶段的详细学习笔记,从基础的 HTTP 请求到高级的 Selenium 自动化与反爬策略。
📅 Day 01:爬虫初探与基础流程
1. 课程体系概览 🗺️
- 基础阶段: 语法环境、数据类型、流程控制、函数模块。
- 进阶阶段: 面向对象、网络编程、Mysql 数据库、并发编程。
- 前端补充: HTML/CSS/JS、jQuery、Bootstrap、Ajax。
- 爬虫阶段核心:
- 数据容器: 字符串、列表、字典。
- 流程控制: 筛选与提取。
- 工具封装: 函数与类(面向对象)。
- 网络协议: HTTP/HTTPS (GET/POST)。
2. 什么是爬虫? 🕷️
爬虫是模拟用户向服务器发送请求,并在互联网上获取数据的一种方式。
- 核心动作: 模拟(非真人)、请求(下载、保存、注册、查询)。
- 数据分类:
- 娱乐/商业数据: 图片、小说、视频、商品信息。
- 搜索引擎: 百度、谷歌的抓取系统。
- 人机交互: 抢票、秒杀、自动投票。
3. 爬虫分类
- 通用爬虫: 搜索引擎的核心,抓取全网数据。
- 聚焦爬虫: 针对特定网站或内容进行筛选抓取。
- 增量爬虫: 监测更新,只抓取新产生的数据(如股票、天气)。
4. 爬虫流程操作 (Requests) 🛠️
Requests 是 Python 的第三方库,用于发送网络请求。
基本步骤:
- 准备工具:
import requests - 确定目标:
url = '网址' - 发送请求:
res = requests.get(url) - 处理数据:
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
📅 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
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. 环境配置
pip install selenium- 下载对应浏览器的
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 模拟加密逻辑 |