🐍 爬虫工程师入门阶段一:基础知识点完全学习文档
欢迎来到爬虫世界!阶段一的目标是让你掌握爬虫最核心的基础知识,能够独立完成简单的静态网页数据抓取。本文档将详细拆解每一个知识点,并配有代码示例和实战练习,帮助你扎实入门。
目录
- [Python 基础回顾](#Python 基础回顾)
- [HTTP/HTTPS 协议核心](#HTTP/HTTPS 协议核心)
- [HTML/CSS 基础与选择器](#HTML/CSS 基础与选择器)
- [Requests 库完全指南](#Requests 库完全指南)
- [BeautifulSoup 解析 HTML](#BeautifulSoup 解析 HTML)
- [数据存储:TXT / CSV / JSON](#数据存储:TXT / CSV / JSON)
- 阶段一实战练习题
1. Python 基础回顾
在开始爬虫之前,你需要掌握 Python 最基本的语法和常用操作。以下是你必须熟悉的内容:
1.1 变量与数据类型
- 数字 :
int(整数)、float(浮点数) - 字符串 :
str,常用方法strip(),split(),replace(),join(),encode()/decode() - 列表 :
list,增删改查、切片、遍历 - 字典 :
dict,键值对操作、遍历 - 元组 :
tuple,不可变序列 - 集合 :
set,去重、交集并集
1.2 控制流
if/elif/else条件判断for循环和while循环break、continue、else子句
1.3 函数
- 定义函数
def - 参数(位置参数、默认参数、关键字参数)
- 返回值
return
1.4 文件操作
- 打开文件:
open(file, mode) - 读取:
read(),readline(),readlines() - 写入:
write(),writelines() - 使用
with语句自动关闭文件
1.5 异常处理
try/except/finally- 捕获特定异常类型
1.6 常用内置模块
os:文件和路径操作sys:系统相关参数time:时间处理、休眠random:随机数json:JSON 解析(后面会重点用到)
练习:写一个函数,读取一个文本文件,统计其中每个单词出现的次数,返回字典。
2. HTTP/HTTPS 协议核心
爬虫本质上是模拟浏览器向服务器发送请求并获取响应。理解 HTTP 协议是爬虫的基础。
2.1 什么是 HTTP?
HTTP(HyperText Transfer Protocol)是互联网上应用最广泛的一种网络协议,用于从 Web 服务器传输超文本到本地浏览器。
2.2 URL 结构
一个典型的 URL:https://www.example.com:443/path/to/page?key1=value1&key2=value2#section
- 协议 :
https:// - 域名 :
www.example.com - 端口 :
:443(HTTPS 默认 443,HTTP 默认 80) - 路径 :
/path/to/page - 查询参数 :
?key1=value1&key2=value2 - 片段 :
#section(通常前端使用,不会发送到服务器)
2.3 HTTP 请求方法
- GET:请求获取资源(最常见)
- POST:提交数据给服务器(如表单登录)
- PUT、DELETE、HEAD、OPTIONS 等(了解即可)
2.4 常见请求头(Headers)
请求头是客户端告诉服务器的一些额外信息,爬虫中经常需要伪装它们。
User-Agent:标识客户端类型(浏览器、操作系统等)Referer:表示请求是从哪个页面发出的Cookie:携带会话信息Authorization:身份认证Content-Type:POST 请求时,说明发送的数据格式(如application/json)
2.5 HTTP 响应状态码
服务器返回的状态码表示请求结果,常见的有:
- 2xx 成功
200 OK:请求成功
- 3xx 重定向
301 Moved Permanently:永久重定向302 Found:临时重定向
- 4xx 客户端错误
403 Forbidden:禁止访问404 Not Found:资源不存在
- 5xx 服务器错误
500 Internal Server Error:服务器内部错误
2.6 响应内容
服务器返回的响应体通常是 HTML、JSON、图片、文件等。爬虫主要解析 HTML 或 JSON。
2.7 HTTPS
HTTPS 是 HTTP 的安全版本,数据经过 SSL/TLS 加密。爬虫处理 HTTPS 与 HTTP 基本一致,requests 库会自动处理证书验证。
3. HTML/CSS 基础与选择器
爬虫抓取的数据通常隐藏在 HTML 结构中,因此你需要能看懂 HTML,并能用选择器定位到目标元素。
3.1 HTML 基础
HTML 由标签和属性组成,常见结构:
html
<!DOCTYPE html>
<html>
<head>
<title>页面标题</title>
</head>
<body>
<div id="content" class="wrapper">
<h1>文章标题</h1>
<p class="intro">这是一段介绍。</p>
<ul>
<li>列表项1</li>
<li>列表项2</li>
</ul>
</div>
</body>
</html>
3.2 常用标签
<div>:块级容器<p>:段落<a>:超链接<img>:图片<ul>/<li>:无序列表<table>/<tr>/<td>:表格<span>:内联容器<h1>~<h6>:标题
3.3 属性
id:唯一标识符class:类名(可重复,用于 CSS 样式)href:链接地址src:图片或脚本地址title:提示文本
3.4 CSS 选择器(重点)
CSS 选择器用于定位元素,在爬虫中常用 BeautifulSoup 的 select() 方法或 lxml 的 xpath。这里先介绍最常用的几种:
| 选择器 | 示例 | 说明 |
|---|---|---|
| 标签选择器 | div |
所有 <div> 元素 |
| 类选择器 | .intro |
class="intro" 的元素 |
| ID 选择器 | #content |
id="content" 的元素 |
| 属性选择器 | [href] |
带有 href 属性的元素 |
| 后代选择器 | div p |
<div> 内的所有 <p> |
| 子元素选择器 | div > p |
<div> 的直接子元素 <p> |
| 并列选择器 | div.wrapper |
<div class="wrapper"> |
练习:用上述选择器选出示例 HTML 中的:
- 所有
<li>元素 class="intro"的段落id="content"的div
4. Requests 库完全指南
requests 是 Python 中最优雅的 HTTP 库,几乎成为了爬虫的事实标准。
4.1 安装
bash
pip install requests
4.2 发送 GET 请求
最简单的用法:
python
import requests
url = 'https://api.github.com'
response = requests.get(url)
print(response.text) # 打印响应内容(字符串)
4.3 添加请求头
很多网站需要你伪装成浏览器,否则会拒绝访问。常见的请求头有 User-Agent。
python
headers = {
'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'
}
response = requests.get(url, headers=headers)
4.4 传递 URL 参数
GET 请求的参数可以通过 params 参数传递,它会自动编码并附加到 URL 后。
python
params = {'key1': 'value1', 'key2': 'value2'}
response = requests.get('https://httpbin.org/get', params=params)
print(response.url) # 输出:https://httpbin.org/get?key1=value1&key2=value2
4.5 发送 POST 请求
POST 通常用于提交表单或 JSON 数据。
python
# 表单形式(Content-Type: application/x-www-form-urlencoded)
data = {'username': 'user', 'password': 'pass'}
response = requests.post('https://httpbin.org/post', data=data)
# JSON 形式(Content-Type: application/json)
import json
json_data = {'key': 'value'}
response = requests.post('https://httpbin.org/post', json=json_data)
4.6 响应对象
response 对象包含服务器返回的所有信息:
response.status_code:状态码(如 200)response.headers:响应头(字典形式)response.text:响应内容(字符串,自动解码)response.content:响应内容(字节形式)response.json():如果响应是 JSON,可直接解析为字典response.encoding:查看或设置编码response.url:最终请求的 URL(可能经历重定向)
4.7 会话对象(Session)
如果你需要保持某些参数(如 Cookie)跨请求,可以使用 Session 对象。它会在多次请求中自动保存 Cookie。
python
s = requests.Session()
s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get('https://httpbin.org/cookies')
print(r.text) # 会看到设置的 Cookie
4.8 超时设置
为防止请求卡死,建议设置超时时间:
python
response = requests.get(url, timeout=3) # 3秒后超时
4.9 代理
如果你需要使用代理,可以通过 proxies 参数:
python
proxies = {
'http': 'http://127.0.0.1:8888',
'https': 'http://127.0.0.1:8888',
}
response = requests.get(url, proxies=proxies)
4.10 异常处理
网络请求可能出错,建议捕获异常:
python
from requests.exceptions import RequestException
try:
response = requests.get(url, timeout=3)
response.raise_for_status() # 如果状态码不是200,抛出HTTPError
except RequestException as e:
print(f'请求出错:{e}')
练习:使用 requests 获取百度首页的 HTML,打印状态码和前 500 个字符。
5. BeautifulSoup 解析 HTML
获取到 HTML 后,我们需要从中提取数据。BeautifulSoup 是一个强大易用的解析库。
5.1 安装
bash
pip install beautifulsoup4 lxml
lxml 是解析器,比 Python 内置的解析器更快。
5.2 基本用法
python
from bs4 import BeautifulSoup
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
soup = BeautifulSoup(html_doc, 'lxml')
5.3 查找元素的方法
5.3.1 find() 和 find_all()
find(name, attrs, recursive, string, **kwargs):返回第一个匹配的元素find_all(name, attrs, recursive, string, limit, **kwargs):返回所有匹配的元素列表
示例:
python
# 查找第一个 <p> 标签
p = soup.find('p')
# 查找所有 <a> 标签
all_links = soup.find_all('a')
# 查找 class="sister" 的标签
sisters = soup.find_all(class_='sister') # 注意 class 后面加下划线
# 查找 id="link1" 的标签
link1 = soup.find(id='link1')
5.3.2 select() 方法(使用 CSS 选择器)
python
# 选择所有 <a> 标签
links = soup.select('a')
# 选择 class="sister" 的标签
sisters = soup.select('.sister')
# 选择 id="link1" 的标签
link1 = soup.select('#link1')
# 选择 <p> 标签内的 <a> 标签
p_links = soup.select('p a')
5.4 获取标签内容
tag.name:标签名tag.text或tag.get_text():获取标签内的文本内容(包含子标签文本)tag.string:如果标签内只有文本,返回该文本;如果有子标签,返回 Nonetag.attrs:获取所有属性组成的字典tag.get('属性名'):获取指定属性的值
示例:
python
for a in soup.find_all('a'):
print(a.text) # 链接文字
print(a.get('href')) # 链接地址
print(a['href']) # 另一种方式(如果属性不存在会报错)
5.5 实战:提取豆瓣电影标题
python
import requests
from bs4 import BeautifulSoup
url = 'https://movie.douban.com/top250'
headers = {'User-Agent': 'Mozilla/5.0'}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'lxml')
# 每部电影信息在 <li> 标签中,class="item"
movies = soup.select('.item')
for movie in movies:
title = movie.find('span', class_='title').text # 电影名
rating = movie.find('span', class_='rating_num').text # 评分
print(title, rating)
练习:抓取一个简单的静态页面(比如 https://books.toscrape.com/),提取所有书籍的标题和价格。
6. 数据存储:TXT / CSV / JSON
爬到的数据需要保存下来,最常用的格式是 CSV 和 JSON。
6.1 保存为 TXT
直接用文件写入即可:
python
with open('data.txt', 'w', encoding='utf-8') as f:
f.write('要保存的文本')
6.2 保存为 CSV
CSV(逗号分隔值)可以用 Python 内置的 csv 模块,也可以用 pandas(但阶段一先不用)。
python
import csv
# 准备数据,列表的列表
data = [
['电影名', '评分'],
['肖申克的救赎', '9.7'],
['霸王别姬', '9.6']
]
with open('movies.csv', 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.writer(f)
writer.writerows(data)
encoding='utf-8-sig' 可以让 Excel 正确打开中文 CSV。
6.3 保存为 JSON
JSON 是轻量级数据交换格式,非常适合保存结构化数据。
python
import json
data = [
{'title': '肖申克的救赎', 'rating': 9.7},
{'title': '霸王别姬', 'rating': 9.6}
]
with open('movies.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
ensure_ascii=False允许中文正常显示indent=2美化输出
练习:将豆瓣 Top250 的前 10 部电影信息(排名、片名、评分)保存为 CSV 文件。
7. 阶段一实战练习题
为了检验你是否掌握了以上所有知识点,请独立完成以下两个题目。每个题目都附有解题思路,先自己尝试,实在困难再参考提示。
练习一:爬取豆瓣电影 Top250
- 目标:https://movie.douban.com/top250
- 数据字段:电影排名(1-250)、中文片名、导演、上映年份、评分、评价人数
- 要求:分页爬取(共 10 页),保存为 CSV 文件。
- 提示 :
- 第一页 URL:
https://movie.douban.com/top250?start=0,第二页start=25,以此类推。 - 需要设置
User-Agent请求头,否则会返回 418。 - 使用 BeautifulSoup 解析,每个电影信息在一个
<li>标签中,class="item"。 - 电影排名在
<em>标签中。 - 片名在
span标签class="title"中(注意可能有英文名干扰,取第一个)。 - 导演等其他信息在
<p class="">中,需要正则或 split 处理。 - 评分在
span标签class="rating_num"中。 - 评价人数在
<div class="star">内的最后一个<span>中,需提取数字。
- 第一页 URL:
解题思路框架:
python
import requests
from bs4 import BeautifulSoup
import csv
import time
def fetch_page(start):
url = f'https://movie.douban.com/top250?start={start}'
headers = {'User-Agent': 'Mozilla/5.0'}
resp = requests.get(url, headers=headers)
soup = BeautifulSoup(resp.text, 'lxml')
movies = soup.select('.item')
page_data = []
for movie in movies:
rank = movie.find('em').text
title = movie.find('span', class_='title').text
# 提取导演、年份等
info = movie.find('p', class_='').text.strip()
# 用正则或字符串分割提取导演和年份
# ...
rating = movie.find('span', class_='rating_num').text
# 提取评价人数
star = movie.find('div', class_='star')
num = star.find_all('span')[-1].text[:-3] # 去掉"人评价"
page_data.append([rank, title, director, year, rating, num])
return page_data
all_data = [['排名', '片名', '导演', '年份', '评分', '评价人数']]
for i in range(0, 250, 25):
all_data.extend(fetch_page(i))
time.sleep(2) # 礼貌延时
with open('douban_top250.csv', 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.writer(f)
writer.writerows(all_data)
练习二:爬取当当网图书列表
- 目标:http://category.dangdang.com/cp01.01.02.00.00.00.html(计算机/网络类)
- 数据:商品名称、价格、作者、出版社、评论数
- 要求:爬取至少 3 个分类(如计算机、小说、童书),每个分类前 5 页,保存为 JSON 文件。
- 提示 :
- 观察 URL 规律,不同分类对应不同 ID,页数参数
pg=2表示第 2 页。 - 当当网有简单的反爬,需要设置
User-Agent,并适当延时。 - 每个商品在
<li>标签中,class可能为line1或类似,可以用select('.line1')选择。 - 价格通常在一个带有
price类的标签中。 - 作者、出版社在
<p class="search_book_author">中,用<span>分割。 - 评论数在
<a>标签内,可能包含"条评论",需提取数字。
- 观察 URL 规律,不同分类对应不同 ID,页数参数
解题思路框架:
python
import requests
from bs4 import BeautifulSoup
import json
import time
def fetch_category(category_url, category_name, pages=5):
all_books = []
for page in range(1, pages+1):
url = f'{category_url}&page={page}' # 根据实际URL调整
headers = {'User-Agent': 'Mozilla/5.0'}
resp = requests.get(url, headers=headers)
soup = BeautifulSoup(resp.text, 'lxml')
items = soup.select('.line1') # 商品项选择器
for item in items:
name = item.find('a', class_='pic').get('title') # 商品名
price = item.find('span', class_='price_n').text # 价格
# 提取作者、出版社
author_info = item.find('p', class_='search_book_author').text.strip()
# 处理字符串...
comment = item.find('a', class_='red').text.strip('条评论')
all_books.append({
'name': name,
'price': price,
'author': author,
'publisher': publisher,
'comment': comment
})
time.sleep(2)
return {category_name: all_books}
# 定义要爬的分类URL和名称
categories = {
'计算机': 'http://category.dangdang.com/cp01.01.02.00.00.00.html',
'小说': 'http://category.dangdang.com/cp01.01.01.00.00.00.html',
'童书': 'http://category.dangdang.com/cp01.00.00.00.00.00.html?cpath=01.00.00.00.00.00'
}
result = {}
for name, url in categories.items():
result[name] = fetch_category(url, name)
with open('dangdang.json', 'w', encoding='utf-8') as f:
json.dump(result, f, ensure_ascii=False, indent=2)
恭喜你完成了阶段一的学习!现在你已经具备了编写基础爬虫的能力。接下来可以进入阶段二,学习如何处理登录、会话和更复杂的反爬措施。记住:多动手实践是进步最快的方法。如果在练习题中遇到问题,欢迎随时查阅文档或搜索引擎。加油!